Intermediate Tutorial


Iframe Communication


30 minutes

Posted on: October 22, 2017

Learn Sumerian
Iframe Communication

Tags

iframe
postmessage

In this tutorial you will learn about:

Scripting

In this tutorial, we’ll embed an Amazon Sumerian scene in an iframe, but make the scene react to mouse movements outside the iframe. To make this work, you have two hosting options. You can host the scene on your own server (same domain) or in the cloud (cross-domain).

Using iframes makes it easy to embed a scene into a webpage. Due to the security policies around iframes, you have to develop special solutions to communicate with the rest of the webpage, especially in the cross-domain case.

You’ll learn about:

  • Scripting
  • Iframes
  • postMessage
  • Changing mesh color

Prerequisites

Before you begin, you should have completed the following tasks and tutorials:

Create a New Scene

From the Dashboard, create a scene from the Default Lighting template.

Solution 1: Scripting Mouse Movement on the Window Object

To track the mouse movement on a page, we traditionally use an Event Listener on the Window object.

  1. Add a Box entity to the scene.

  2. Add a Script component to the Box entity.

  3. Create a Custom Script in the Script component.

  4. Open the script in the Script Editor.

  5. Enter the following code.

     // This will not work outside the iframe!
     var setup = function(args, ctx) {
       ctx.listener = function(evt) {
         console.log(evt.clientX, evt.clientY);
       };
       window.addEventListener('mousemove', ctx.listener);
     }
    
     var cleanup = function(args, ctx) {
       window.removeEventListener('mousemove', ctx.listener);
     }
    
  6. Make sure to save your script.

  7. Publish your scene!

Embed the Scene in an HTML Page

Use the following code to embed the scene in an HTML page.

<iframe id="sumerian-scene" src="https://YOUR_PUBLISH_URL.scen/yoursceneID.scene"></iframe>

If you open the HTML page in a browser, and open the JavaScript console, you’ll notice that the mouse position logs only when the mouse is inside of the iframe. This is because we are listening to the iframe window and not the parent window.

Solution 2: Listening for Mouse Movement on window.parent

Now let’s attach the listener on the correct Window object by using window.parent. Update the code so it looks like this.

// This will throw a cross-origin error!
var setup = function(args, ctx) {
  ctx.listener = function(evt) {
    console.log(evt.clientX, evt.clientY);
  };
  window.parent.addEventListener('mousemove', ctx.listener);
}

var cleanup = function(args, ctx) {
  window.parent.removeEventListener('mousemove', ctx.listener);
}
  1. Make sure to save your script.

  2. Re-publish your scene!

Unfortunately, we now get the following error message.

Uncaught DOMException: Blocked a frame with origin "https://YOUR_PUBLISH_URL.scen" from accessing a cross-origin frame.

The browser automatically blocks the iframe from reaching out of its frame because of security concerns. How can we get around this? One option is to download the scene as a webpage, and put it on the same domain as the main webpage. If you do it this way, the browser will allow the iframe to reach out and not throw an error.

Solution 3: Using postMessage

Let’s say we want to include a published scene in an iframe, without having to put it on our own server. A solution we can use here is named postMessage.

Change the HTML embed code so it looks like this:

<iframe id="sumerian-scene" src="https://YOUR_PUBLISH_URL.scen/yoursceneID.scene"></iframe>
<script>
var iframe = document.getElementById('sumerian-scene');
iframe.onload = function() {
  window.addEventListener('mousemove', function(event) {
    var data = {
      clientX: event.clientX,
      clientY: event.clientY
    };
    iframe.contentWindow.postMessage(data, '*');
  });
};
</script>
  1. Make sure to save your script.

  2. Re-publish your scene!

    Now, in our script, we can listen to the message event on the iframe window. Update the script to the following:

     var setup = function(args, ctx) {
       ctx.listener = function(evt) {
         console.log(evt.data.clientX, evt.data.clientY);
       };
       window.addEventListener('message', ctx.listener);
     }
    
     var cleanup = function(args, ctx) {
       window.removeEventListener('message', ctx.listener);
     }
    
  3. Make sure to save your script.

  4. Re-publish your scene!

We can now get log messages both on the iframe and from outside the iframe.

Change the Color of a Mesh Depending on Mouse Position

To change the color of a mesh based on mouse positioning, update your HTML embed code to the following:

<!-- Embed the sumerian scene -->
<iframe id="sumerian-scene" src="..."></iframe>

<!-- When the iframe loads, send in the mouse position -->
<script>
var iframe = document.getElementById('sumerian-scene');
iframe.onload = function() {
  window.addEventListener('mousemove', function(event) {
    // Send the mouse position (relative to the upper-left iframe corner) to the iframe.
    var rect = iframe.getBoundingClientRect();
    var data = {
      myEvent: true,
      x: event.clientX - rect.left,
      y: event.clientY - rect.top
    };
    iframe.contentWindow.postMessage(data, '*');
  });
};
</script>

In the Sumerian script, we want to set the diffuse color of the cube, depending on the mouse position. Copy and paste this code into the Custom Script.

var setup = function(args, ctx) {
  // Listen for messages from the parent window
  window.addEventListener('message', ctx.messageListener = function(evt) {
    if(evt.data.myEvent){
      // Set the color of the mesh on the entity
      var color = [
        0.5 * Math.sin(evt.data.x / ctx.domElement.width) + 0.5,
        0.5 * Math.sin(evt.data.y / ctx.domElement.height) + 0.5,
        0,
        1
      ];
      ctx.entity.meshRendererComponent.materials[0].uniforms.materialDiffuse = color;
    }
  });
  // Listen for mouse movement on the iframe window.
  // This is needed because mouse events on the iframe
  // can't be caught by the parent window.
  window.addEventListener('mousemove', ctx.mousemoveListener = function(evt){
    ctx.messageListener({
      data: {
        myEvent: true,
        x: evt.clientX,
        y: evt.clientY
      }
    });
  });
}

var cleanup = function(args, ctx) {
  window.removeEventListener('message', ctx.messageListener);
  window.removeEventListener('mousemove', ctx.mousemoveListener);
}

Now re-publish and share your scene!

You’ve learned how to embed a Sumerian scene in an iframe. To learn more, check out the following tutorial:

Back to Tutorials

© 2019 Amazon Web Services, Inc or its affiliates. All rights reserved.