Documentation

Iframe animation controlled by Advanced Connector

It is possible to create an "avatar" – an animated character that can react to the user's answers, give feedback, or provide hints for 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 must enter some code 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 the student is reading the instructions and thinking about the solution to 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 increased compatibility and control 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 should get 2 files – avatar.html (or a name of your choosing) and 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 the mAuthor lesson

Create a new lesson and place the Iframe module on the 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 the Choice and Advanced Connector modules with the following code to make the avatar react to the 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 the student has already answered, 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 saved, so whenever we change the page, we should 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 the 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 the Advanced Connector 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 to host your index.html on an external server ("Iframe URL" property in Iframe module) and you don't have an 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 synchronized with sound in an Audio module. Copy to My Lessons

Downloads

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