This is the starting screen for the interactive game taxonomy example I shared at the ATD international conference in 2021.

Many designers asked how to do something like that in Storyline. This short blog is about WHY, WHEN, and HOW.

Why?

Always start with the why! What’s the business problem are we solving for? Well, for the taxonomy we’ll need the title of the game the user will deconstruct. Hence the text entry.

However, this is about games! What would make a simple entry serve two purposes:

  1. Set the tone! It is fun. It is playful. (No, it’s easy. Learning how to deconstruct games is a skills. But it’s all about play.)
  2. Pique curiosity! If people are hesitant at this point, let’s give them some teaser. (I be many users typed in something, realized what’s going on, delete the text and type it again… Hooked.)
  3. Share it! If you like something you share it. That’s life today. Sharing the word is important.

When?

It is only used to focus attention to the entry box. And after that some version of this eye movement does the same consistently: focusing on the entry box. It is also set as a decorative image for accessibility.

How?

There are two parts here to build something like that:

  1. You need eyes. I mean not real eyes but eyes for the graphics. I got the graphics from Adobe Stock, and then in Illustrator created different versions of it.
  2. You need to track the number of characters the user is typing. If you can catch that, Storyline has triggers and conditions to change the image accordingly.

Let’s deal with part 1 first, the eyes. Once you have the different eyes stages, you can create a state for each. You may even have a better system to name them 🙂

Storyline screen capture with a single image of a pair of eyes and multiple states of the same image with the eyes staring at different directions.

Next, you’ll need a variable. This variable will be the one holding the number of characters the user has typed in. Based on the number of characters, you will set up triggers to change the state of the image.

  1. Create a variable called GameTitleType_Num (number with default 0).
  2. Create triggers to set the right state of the image (Eyes).

You can decide how many states you want. Two important things: a) check for 0 characters. Set it to normal. In case the user deletes all the characters it should always go back to normal state. b) set the last condition to > X. So anything above that character length is covered by the last state.

Now, with all that there’s one thing left. How in the world we can tell GameTitleType_Num how many characters has the user typed in. Storyline will not do that for you out of the box.

WHY can’t we track the variable that is associated with the text entry? Because Storyline’s variable that is associated with a text entry gets updated ONLY after the text entry loses its focus. In other words, when the user clicks out of the text box, hits enter, submit, or whatever. We need to know character by character as being typed how many we have.

JavaScript

Which leads us to part 1 of the problem: capturing the number of characters real time. You’ll use JavaScript for that.

This task can be done in many ways. This is only one way to approach it, and so, it may or may not work for your purposes.

In the old times, Storyline included a JavaScript library called jQuery. What that meant that you can use this library without any extra hoops and loops. The library could manipulate things on the screen. However, with 2020 Storyline no longer includes jQuery.

That said, you can add it manually on your own. Therefore, the first thing you’ll need to do is make sure jQuery is loaded when you launch your course.

Add this code to the Master layout as a JS running when the page loads (if you’re using multiple master pages, do it on all):

let p = GetPlayer();
//let webLoc = p.GetVar("WebObjectFolder");
//let oLocation="story_content/WebObjects/"+webLoc+"/";


function add_script(scriptURL,oID,type) {

let scriptEl = document.createElement("script");

let head=document.getElementsByTagName('head')[0];

let fn = "loadedCallback_"+oID
scriptEl.type = type;

scriptEl.src = scriptURL;

scriptEl.id=oID;


scriptEl.onload = eval(fn);


head.appendChild(scriptEl);

}

if(document.getElementById('zsoltsupport')==null){

add_script("https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js","zsoltsupport","text/javascript");


}


function loadedCallback_zsoltsupport()
{
// jQuery is loaded
}

There are commented lines “//” you don’t need now but they don’t hurt. I left them in because if you download the source for the project there are other neat things in it (like a PDF library) that requires those lines.

Now that you have this code on the master pages, you can return to the page with the eyes.

You’ll need to add a couple of more variables:

  1. GameTitleType set it to text with default as blank. This will hold the typed in letters real time.
  2. gTitle set it to text and associated with the text entry box. You can name this anything you want, btw. This is the normal variable that will hold he entry at the end of the typing.

Next, this is where some creative hacking is happening. Bare with me.

  1. When you add a new text entry field there is a placeholder text: type your text here. Add the following “GameTitleType|” before this text as you can see in the screenshot. So the complete placeholder will be: GameTitleType|type your text here

Why? Our JavaScript code that you will add next will look for any text input on the screen that has this structure: something|something else. If the text entry has this structure, the code will remove the first part and leaves the type your text here just like users would see normally. So they will not notice anything. However, the code “tags” this text entry. Whenever the user types a letter in it, the code will add that real time to the Storyline variable you identified. In this case GameTitleType. So basically, all this is to tell the code what variable to update.

Why not just hardcode this variable name in the code? Because the code should be independent, standalone. So you can reuse it on any page you want.

Final things: you will add two JS triggers to this page with the eyes on:

  1. The first will run this code that replaces the “coded” placeholder and sets up the magic.
  2. The second JS trigger will set the focus to the text entry.
defer();

function defer() {
    if (window.jQuery) {
        setEyes();
    } else {
        setTimeout(function() { defer() }, 50);
    }
}

function setEyes()
{
   
var player = GetPlayer(); // Get the player
var placeHolderText;  
// To hold the placeholder original text and the SL variable later.  

// This is jQuery. It loops through all input fields...

$(":input").each(function() {
var place = $(this).attr('placeholder'); 
// Getting the current text fields placeholder attribute. 
// This is where the text is stored from Storyline.

if (place !== undefined) // if it does have text
{
 placeHolderText = place.split("|"); 
 // we split it by the "|" character. 
// You can replace this with any divider you want.

 if (placeHolderText.length==2) 
// That means we have a divider in the placeholder text. 
{
   $(this).data('zs_place',placeHolderText[0]);
 
// placeHolderText[0] holds the SL variable name. 
// We're adding a new data attribute to the input field. Name it zs_place. 
// You can use any other name. We store the SL name here. 
// This is not visible for the user but accessible for the code later.
   
  $(this).attr('placeholder',placeHolderText[1]);
//  We replace the original placeholder with only the user should see
// The normal placeholder text is in placeHolderText[1]   

// Finally, the power of JQuery: we bind this function to the current input field
// What it means EVERY TIME the input field changes (like when you type)
// this function runs.
$(this).bind('input propertychange', function() {

// We replace the the SL variable (remember we stored its name in a 
// data attribute named zs_place before)
// with the input variable's current value
// Real time. 
// $(this) just means the current jQuery object, the inputfield. 

      player.SetVar($(this).data("zs_place"),$(this).val());
player.SetVar($(this).data("zs_place")+"_Num",$(this).val().replace(/r?n|r| /g,'').length)

});
}
}
  });
}

Add the code above in a JS trigger that runs when the timeline loads. It’s a deeper dive if you want to understand what’s going on here. In brief, this code is watching your text entry and updates your variable real time.

If you have only one text entry on the page and you want to focus on it (check your accessibility requirements if there’s anything else the user should read before) then add the second JS trigger after 1 second of timeline start. This is optional.

$('form:first *:input[type!=hidden]:first').focus();

All done. You have all the pieces together for a test drive. Here’s the source code if want to use it for education purposes (otherwise, you must replace the icons and images with your own licensed version).