Documentation

Iframe animation controlled by Advanced Connector

It is possible to create an "avatar" – the animated character that can react to user's answers, give feedback or provide hints to an activity.

Preparing the avatar animation in Adobe Animate CC

Start a new HTML5 (Canvas) project in Adobe Animate. Our character should be placed on the main timeline in a Movie Clip named, e.g. "avatar". We have to enter some code in order to provide communication with the player and send the event notifying the player about animation loading. The following script should be placed on the first frame:

var message_ID = "avatar";
function getOpener () {
    var parent = null;
    if (window.parent != null && window.parent.postMessage != null) {
        parent = window.parent;
    }
    if (window.opener != null && window.opener.postMessage != null) {
        parent = window.opener;
    }
    return parent;
}
function sendMessage (actionID, params){
    var parent = getOpener();   //Get parent
    if (parent != null) {
        if(params == undefined) {
            params = {};
        }
        var newMessage = {id : message_ID, actionID : actionID, params:params};
        parent.postMessage(newMessage,'*'); //Send message to addon
    }
}
sendMessage("CUSTOM_EVENT", "AVATAR_READY");

See a screenshot example

An idle pose of the character is usually needed when a student is reading the instructions and thinking on the solution of the activity. Therefore, it should be looped on the timeline in the "avatar" Movie Clip object. Add a layer for labels and one for actions and use labels to indicate the point on the timeline when the correct/wrong reaction starts. At the end of the reaction, place the script to go back to frame 1:

this.gotoAndPlay("start");

See a screenshot example

It is best not to use any bitmaps and external resources as it makes the process of importing the animation to mAuthor significantly longer, more complex and harder to maintain. Also, we do not recommend using sounds in Animate, but in mAuthor. That gives you more control and compatibility over them.

If your animations are ready, go to Publish Settings and make sure the animation is looped. On the Advanced tab, click the button to attach Javascript code to the HTML file. Everything should be kept in one file to make it easier to upload. Deselect the "keep the libraries on the servers" option as it is unnecessary. Having published your project, you shoud get 2 files – avatar.html (or a name of your choosing) and a Createjs.min.js.

Now we need to combine them into one file:

– Open both of them in a text editor. Select and copy the whole text from the Createjs.min.js
– In the html file find the following line:

<script src="./createjs-2015.11.26.min.js"></script>
and remove it.

– Paste all the copied code just after the next

<script>
element.

Your file is ready to upload to mAuhtor.

Using the animation in mAuthor lesson

Create a new lesson and place the Iframe module on a page. Fill in the "Communication id" property with the id from the first frame on the main timeline (message_ID) in your animation code. In our case it was "avatar".

Upload the prepared html file with the animation in the "Index file" property. Your animation should load and be displayed in the editor properly.

Now prepare a simple activity by inserting Choice and Advanced Connector with the following code to make the avatar react to user's answers from any module that gives 'Score:1 Value:1' type events:

EVENTSTART
Score:1
Value:1
SCRIPTSTART
var iframe  = presenter.playerController.getModule('Iframe1');
var stage  = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage;
stage.children[0]['avatar'].gotoAndPlay('correct');
SCRIPTEND
EVENTEND

EVENTSTART Score:0 Value:1 SCRIPTSTART var iframe = presenter.playerController.getModule('Iframe1'); var stage = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage; stage.children[0]['avatar'].gotoAndPlay('wrong'); SCRIPTEND EVENTEND

Everything should already work properly and the avatar should react to answers.

Adding a failsafe for the long loading time

If your animation is large (which is not recommended), there can be a situation, when a student has already given the answer, but the file in the Iframe module is still loading. It is necessary to prevent the answers from being given before that.

This can be done by simply covering the whole page with, e.g. a semi-transparent shape module and hiding it only when the animation is loading. This is why our animation contains the code to send a custom event to the player.

We can react to this event in Advanced Connector as follows:

EVENTSTART
Value:AVATAR_READY
SCRIPTSTART
presenter.playerController.getModule('loading').hide();
SCRIPTEND
EVENTEND

Of course, you should place the shape module before that and name it "loading". You can use this CSS code to make it always cover the whole page and have the loading icon displayed:

.shape_loading{
  background-color: rgba(255,255,255,0.5);
  background-image: url(/file/serve/5010685316038656) !important;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 64px 64px;
  top: 0px !important;
  left: 0px !important;
  bottom: 0px !important;
  right: 0px !important;
  width: auto !important;
  height: auto !important;
}

When the animation loads and triggers the hide command on the loading shape, its hidden state is being saved, so whenever we change the page, we should actually make it visible again. Therefore, the following code should be added to the Advanced Connector:

EVENTSTART
Name:PageLoaded
Source:^((?!header|footer).)*$
SCRIPTSTART
presenter.playerController.getModule('loading').show();
SCRIPTEND
EVENTEND

Controlling a simple animation on the main timeline

If you have a simple animation that is composed on the main timeline, you can control it using Advanced Connector commands:

var iframe  = presenter.playerController.getModule('Iframe1');
var stage  = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage;
stage.children[0].gotoAndStop();

Below you can find the example code to be put in AC module if your single state buttons are called "play", "pause" and "stop":

EVENTSTART
Source:pause
SCRIPTSTART
var iframe  = presenter.playerController.getModule('Iframe1');
var stage  = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage;
stage.children[0].gotoAndStop();
SCRIPTEND
EVENTEND

EVENTSTART Source:play SCRIPTSTART var iframe = presenter.playerController.getModule('Iframe1'); var stage = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage; stage.children[0].gotoAndPlay(); SCRIPTEND EVENTEND

EVENTSTART Source:stop SCRIPTSTART var iframe = presenter.playerController.getModule('Iframe1'); var stage = $( iframe.getView() ).find('iframe').get(0).contentWindow.stage; stage.children[0].gotoAndStop(0); SCRIPTEND EVENTEND

Alternative way of sending messages to the iframe

If you e.g. plan on hosting your index.html on external server ("Iframe URL" property in Iframe module), and you don't have a https certificate installed, the presented way of communication from module to iframe may not work in some cases. To make sure that sending commands to animation is possible, change your code in Adobe animate to e.g. this:

if(stage.begin != 'init'){
var message_ID = "dummy";

//LISTENING window.addEventListener("message", function (event) { receiveMessage(event); }, false);

function validateMessage (message, ownID) { if (message != undefined) { if ((message.id == ownID) && message.actionID != undefined) { return true; } } return false; }

function receiveMessage (event) { var message = event.data; if (validateMessage(message,message_ID)) { switch (message.actionID) { case "RESET": //console.log("RESET!"); stage.children[0].gotoAndPlay(0); sendMessage("CUSTOM_EVENT","ANIMATION_READY"); break; case "CUSTOM_MESSAGE": switch(message.params.action){ case "play": stage.children[0].gotoAndPlay(); break; case "pause": stage.children[0].gotoAndStop(); break; case "stop": stage.children[0].gotoAndStop(0); break; } break; } } }

//SENDING function getOpener () { var parent = null; if (window.parent != null && window.parent.postMessage != null) { parent = window.parent; } if (window.opener != null && window.opener.postMessage != null) { parent = window.opener; } return parent; } function sendMessage (actionID, params){ var parent = getOpener(); //Get parent if (parent != null) { if(params == undefined) { params = {}; } var newMessage = {id : message_ID, actionID : actionID, params:params}; parent.postMessage(newMessage,'*'); //Send message to addon } } sendMessage("CUSTOM_EVENT","ANIMATION_READY");

this.gotoAndStop(); } stage.begin = 'init';

Now you can send "CUSTOM_EVENT" messages from Advanced Connector e.g. like this:

EVENTSTART
Source:pause
SCRIPTSTART
var iframe  = presenter.playerController.getModule('Iframe1');
iframe.sendMessage('CUSTOM_MESSAGE',{action:'pause'});
SCRIPTEND
EVENTEND

EVENTSTART Source:play SCRIPTSTART var iframe = presenter.playerController.getModule('Iframe1'); iframe.sendMessage('CUSTOM_MESSAGE',{action:'play'}); SCRIPTEND EVENTEND

EVENTSTART Source:stop SCRIPTSTART var iframe = presenter.playerController.getModule('Iframe1'); iframe.sendMessage('CUSTOM_MESSAGE',{action:'stop'}); SCRIPTEND EVENTEND

Demo presentations

  1. Avatar demo presentation contains a complete avatar animation and examples with the Choice module. Copy to My Lessons
  2. Animation demo presentation – a demo showing how to control a simple animation with single state buttons. Copy to My Lessons
  3. Animation + Audio demo presentation – a demo showing how to control an animation syncronised with sound in an Audio module. Copy to My Lessons

Downloads

  1. Animation example source file
  2. Adobe animate publish settings profile