How can a non-programmer create captivating effects in Storyline using JavaScript?

How can a non-programmer create captivating effects in Storyline using JavaScript?

Good morning, class! This is a continuation of my series where I explore JavaScript and share my findings with you in the form of practical notes. Together, we’re figuring out:

  • how to create visual effects using GSAP animation,
  • and how to build interactive mechanics that truly capture learners’ attention.

Since more of you are joining in, let me repeat what I usually say. If this is your first time here and all you know about programming is that it’s for programmers, remember:

?? Instructional designers don’t have to know how to code! Learning JavaScript is totally optional for you. But if you’re combining instructional design with course development and want to go beyond Storyline’s built-in features to create something unique and truly yours, trust me—coding is absolutely within your reach.

You can do it!

That’s enough motivation—let’s get to work. To make sense of this article, you should first read the three previous ones. And not just read—practice as you go!


?? Previous articles:

  1. Where to start if you’re a complete beginner. This one’s optional. You don’t need it to start coding right away, but I highly recommend it. It definitely won’t hurt.
  2. Basic animation with JavaScript. The first lesson—big and detailed. It covers the fundamentals and proves that JavaScript isn’t as scary as it seems.
  3. How to animate object properties (color animation example). A fascinating deep dive into SVGs. Sounds unusual for an image format, but trust me, it’s worth it.
  4. Animating multiple objects at once and controlling the chaos.


?? Today, we’ll be revisiting what we’ve learned so far and learn a couple more things:

? I’ll show you how to control the starting point of an animation.

? We’ll talk about data arrays—a must-know for creating effects beyond simple button animations.

? We’ll get familiar with the super useful .forEach(); method.

? And with one small trick, we’ll solve one minor issue with code size and one huge issue with object positioning when resizing the browser window.

By the end of this lesson, you’ll walk away with this animated interactive template:

Intrigued? Let’s go!


Sketching the Mechanism

Take a look at the example above. At first glance, is it immediately clear what it consists of? How each element works?

I’m guessing the answer might be something like: “Uhh… a few circles… they appear and disappear?”

Not the best starting point for writing code. Programming is all about precision and clarity—no adjectives needed.

??That’s why I strongly recommend (and will keep recommending in the future): save yourself time and frustration—sketch out your idea first.

Your sketch should include:

  • A block with all the elements,
  • A schematic representation of the animations you want,
  • A final section outlining what actions will trigger your animations.

Think of it as “drawing” a blueprint for your code. Keep it in front of you—it’s your visual guide for coding.

Here’s what my version looks like today:

If you’ve read the previous article—and I really hope you have—then right now you should be thinking: “Aha! I know how to write the code for this thing!”

For those of you who do—feel free to scroll ahead to the bug-fixing section. Because—spoiler alert—if you follow the steps you already know, you’ll end up with a mechanism that almost works as intended.

For everyone who needs a step-by-step breakdown—I totally get it.

But! You have to make an effort to write the code yourself. Or with the help of AI. But the key point here is: do it yourself! Understanding the code and knowing how to tweak it is half the battle. If you’re not actually writing or at least attempting it, studying won’t get you very far.

Alright, where does a sketch start? With the elements, of course. So, let’s begin.


1?? Defining Variables

Why variables first? Because JavaScript works with variables.

And what are variables? They’re boxes that store data about objects on the slide.

To assign objects to variables, you need to either find their ID attributes or set an Alternative Text.

?? Just a reminder: experienced JavaScript users in Storyline strongly recommend using ID attributes. But if you’re lazy—or just want a more visual way to explain your code (like me here)—you can use Alternative Text instead.

The choice is yours. Just remember the primary role of Alternative Text and don’t put random stuff in there.

Now, let’s open Storyline and create the objects. For clarity, I’ve made a screenshot with all the objects lined up.

?? Key things to note: First—always… no, scratch that—ALWAYS name your objects on the timeline with clear, meaningful names that relate to the objects on the slide.

In my case:

  • I have five circles, each with its own name.
  • And a group of four text blocks, which will appear in the overlapping areas of the circles.

?? Just to be clear—this screenshot is for visual reference only. Of course, in the final version, all objects should be perfectly centered on the slide, stacked one on top of the other.

Next, we assign an Alternative Text to each object. Let me show you an example using the black circle:

The other objects will have the following Alternative Text values:

  • Green circle: "Top Oval"
  • Purple circle: "Right Oval"
  • Pink circle: "Bottom Oval"
  • Yellow circle: "Left Oval"

?? Here's something new. In this example, I have a group of four text fragments. But how do we assign them to a variable? How do we introduce this group to JavaScript?

The same way as individual circles—by using an Alternative Text! Yes, groups can have Alternative Text too! To do this:

  1. Select the group.
  2. Click on Accessibility.
  3. Assign an Alternative Text for the group.

Prep work is done—time to write some code! You'll be working in JavaScript window, here:

And I'll be in Notion—it's just more convenient for writing the article.

You should end up with five variables for the circles and one for the text group:

A couple of important details to keep in mind in this code snippet:

  • You don’t need to write "let" for each variable separately. Just declare it once and list all the objects, separating them with commas. End the statement with a semicolon.
  • Remember, you choose the variable names. Just make sure they make sense to you later when you're working with the code.
  • Don't forget to leave comments in your code for future reference:

Done!


2?? Moving on to Animation

We're using animations from the GSAP library. In its simplest form, it looks something like this (example):

And yeah, you can do it this way for today's example (why this method works but isn’t optimal—we covered last time).

Since we’re animating five circles and one text group, we’ll, of course, animate them as part of an animation sequence. To do that, we first need to create the animation sequence (which we store in a variable).

?? Don’t forget to pause it right away!

If you’re wondering, “But why?”—shame on you! Go read the previous article.

Then, inside the sequence, we add animations for all the slide objects in order and set their delays. Here’s my version:

I’ve added a comment in the code explaining what’s happening in this animation. But I hope you already understand what parameters like scale, opacity, ease, and so on are used for.

There are two new things here: comment formatting and the .fromTo(); method.

The new comment format /* comment */ is used when you have a really long comment that doesn’t fit in a single visible line.

If the comment is short, just one line, then it stays the same as before: //comment.

And for the text group, there’s a new method—not just .to, but .fromTo.

?? Pay close attention! This method has a different syntax, something we haven’t used before:

The difference is that we’re not just defining how the object should change—we’re also specifying the starting state, which is different from what we see on the Storyline's slide.

Sounds a bit tricky? Let’s break it down:

  • Our variable is text.
  • { start } – Here, you define the object’s initial state before the animation begins. In today’s case, the text group needs to appear smoothly. To achieve that, it has to be transparent at the start. Physically, that’s not how it looks on the slide. But we need it to be invisible at first. So, in the first brackets, we set opacity to zero.
  • { end } – This defines how the object should appear. In my case, it needs to fade in smoothly, so opacity is set to one.

That’s the whole trick!


3?? Setting Up Events

Now, let’s talk about the triggers that will start and rewind the whole thing. To do that, we need to remember how the .addEventListener method works, along with the special methods for handling animation sequences: .play(); and .reverse();. (We discussed in detail what it is and how these guys work in previous articles.)

Last time, I used a not-so-elegant solution, and I was really frustrated with its imperfections, but I couldn't come up with a better one. It drove me crazy!

For today's article, it's important to recall this solution and stick with it for now:

What this code does:

  • When you hover over the main black circle, the animation sequence starts playing.
  • To prevent the animation from reversing when the mouse moves over one of the colored circles, the sequence must remain active while hovering over any of them.
  • Finally, when the mouse leaves the entire group of objects, the animation plays in reverse.

At this point, your code should look something like this:

  • Lines 1-8: Declared variables.
  • Lines 10-15: Defined the animation and delays.
  • Lines 18-27: Set up event listeners to trigger the animation.

Essentially, we've just transformed our sketch into a set of code lines. Everything is clear and structured, even though we're now speaking JavaScript instead of using visual or human language.

Take a moment to celebrate—and hit play on the slide.

Drum roll!

WTF! Sorry… ??

Why, JavaScript?! Why?!! ??

Don't get too discouraged. It's annoying, but the reality is that problems like this are part of the process.

It’s time for the fourth stage, which wasn’t in the sketch: debugging!

Let’s figure out why the code isn’t working as expected and fix it.



?? Debugging and Fixing the Code

Let’s take a quick detour. Just like we started with a sketch in the beginning, debugging also requires us to clearly understand the problem first before taking action.

Remember, programming isn’t about adjectives—it’s about data. Everything is precise and structured. So, pause for a moment and try to analyze the issue just by looking at the previous example. Can you describe what went wrong?

.

.

.

The issue lies in how JavaScript interprets the coordinates for object movement. Looking at top and bottom elements:

  • They stay in the correct position on the horizontal axis—which is good.
  • But they move vertically from y=0, instead of from their original positions—which is not good.

For right/left elements, the same issue happens, but with the x coordinate instead.

So, JavaScript doesn’t consider the actual placement of objects on the slide as their default (x, y) coordinates. Instead, it assumes they start at (0,0).

To move objects from the exact position where they were originally placed, we need to:

  • First, tell JavaScript that the starting coordinate is the center of the slide.
  • Remember that the object’s reference point isn’t its actual center (!), but its top-center or left-center, and we need to adjust for that.
  • Consider that objects scale up during the animation, which means their position shifts even more due to the changing diameter of the circles. We need to factor this in.
  • Keep in mind that the screen size may change, affecting positioning and object’s sizes.

At this point, giving up on JavaScript seems like the most reasonable decision in life. But hold on! There’s a solution: xPercent / yPercent.

?? xPercent and yPercent are relative positioning units that move an element by a percentage of its own width or height. The transformations are relative to the center of the element, which is exactly what we need!

Formula:

  • xPercent: 100 → moves the element right by 100% of its own width.
  • xPercent: -100 → moves the element left by 100% of its own width.
  • yPercent: 100 → moves the element down by 100% of its own height.
  • yPercent: -100 → moves the element up by 100% of its own height.

After experimenting, I found that shifting by 45% of the circles’ size works perfectly.

So, let’s replace x/y with xPercent/yPercent:

Time to test it out! Fingers crossed—let’s see if it works.

Yeehaw!

Celebrate for a moment… and then move on to the next issue—object overlap. It’s not very informative, and honestly, it just doesn’t look great.

How do we fix it?

The solution depends on your creativity, but I see two main options.


1?? Keep the Code, Change Objects

To do this, we need to remove the colored fill.

?? If you make the objects fully transparent (100% opacity), JavaScript will stop recognizing them (!). It will treat the circles as if they don’t exist wherever there’s no fill. Basically, it will "see through" them. And if JavaScript can see through an object, it means it detects the slide itself instead. If that happens, the "mouseleave" event gets triggered. Ups!

I learned this the hard way—painful, frustrating experience. Imagine: the code was working perfectly, and then suddenly… boom, it stopped.

Funny thing is, when working with object colors, you have to define a whole separate variable for the color. But if an object has a fill and you set its opacity to 100%, JavaScript just goes: nope, nothing here!—and poof! The inside of the object ceases to exist.

So, I went with a white fill, played around with the opacity, and settled on 99%. The result? A sleek, minimalist black-and-white version. Looks pretty cool!

I did a little research and turns out… I'm the only one who likes the black-and-white minimalist version. Conclusion? The solution works technically, but not aesthetically.

Which means—time to move on to the second approach.


2?? Tweaking the Code

Actually, tweaking isn't the right word here. Everything works, so we’re not fixing anything—we’re just adding a new piece.

Just like when we worked with the sketch or analyzed the coordinate issue, this is the moment to pause and think. How can you even approach a solution if your JavaScript knowledge is only surface-level?

Let me walk you through my thought process. You don’t need to be a JavaScript expert to think logically—shoutout to brain for that!

So, thanks to working with graphic design tools like Adobe Illustrator and Procreate, I know about blending modes like multiply, overlay, darken, etc. These are ways objects mix colors when layered on top of each other—super useful in certain cases.

Knowing that, I asked AI if there was a way to use blending modes in JavaScript. I got a ton of results, tested different options, and went from 10 lines of code… down to just one.

Here’s what it looks like:

Add this line to your code right after defining the variables, and go test it out!

Meanwhile, let me break down what this line actually does and how it works. Let's take a look at what the example consists of:

The task is to make the color properties of each circle such that when they overlap, their colors mix in a specific way. This means we need to change a certain property (mixBlendMode) for each object. To access this property, we need to first tell JavaScript where to look for it (style).

You can write a line of code for each object to update the blend mode, like this:

You can indeed optimize and combine the variables into an array, then use the .forEach() method to change the property for all the elements at once.

Here’s how this can work:

  • [top, right, bottom, left] — this array holds the data.

?? In JavaScript, an array is like a box where you can store several values and refer to them by their order.

  • forEach(); — this is an array method that iterates over each element in the array and performs a specific action on it, which you define inside the parentheses.
  • oval — this is the argument inside the arrow function (oval => { ... }) — the current element in the array (for example, first "top", then "right", and so on). You can name it anything you like (”oval”, “circle”, “element”, etc.).
  • The .style property in JavaScript is used to modify the inline CSS styles of HTML elements. When you access style for an element, you get the CSSStyleDeclaration object, which contains all the CSS properties applied to the element through styles. Looks like it's similar to working with SVG, but there we used a method that gathered computed style data (getComputedStyle(element)). I'm not very sure, I didn't dive too deep this time.
  • The mixBlendMode property in JavaScript lets you control how the element blends with the background. It determines how the element's pixels mix with the pixels beneath it. By default, the element just overlays the background without changing it, but with mixBlendMode, the colors can mix in various ways, creating different visual effects.

I believe this blending technique holds a huge creative potential. You can experiment with different options. Here's a list of blend modes and their effects:

  • normal — Normal blending without mixing (default).
  • multiply — Multiplies pixels, darkening the image (like transparent glass).
  • screen — Lightens, as if light is passing through slides.
  • overlay — A combination of multiply and screen, creating a contrast effect.
  • darken — Shows the darker colors from both the background and the element.
  • lighten — Shows the lighter colors from both the background and the element.
  • color-dodge — Lightens pixels of the element based on the background.
  • color-burn — Darkens pixels of the element based on the background.
  • difference — Subtracts the element's pixels from the background, creating a negative effect.
  • exclusion — Similar to difference, but with less contrast.
  • hue — Uses the color of the element, but brightness and saturation are taken from the background.
  • saturation — Uses the element's saturation, but the color and brightness are taken from the background.
  • color — Uses the element's color, but brightness is taken from the background.
  • luminosity — Uses the element's brightness, but the color comes from the background.

This approach can allow you to experiment and add a creative touch to your design. Have fun playing with it!


Test the mechanics again—does everything work correctly?

How about this?

When testing the code without resizing the browser window, everything works perfectly. But as soon as you resize the browser during testing, everything falls apart.

The code works correctly, but the coordinates of the moving objects don't update when the slide is resized.

I spent a long time searching for a solution on my own and with advice from experienced colleagues. I found several solutions, but they were either unfeasible or only worked correctly in certain cases.

The final solution came by accident, as a result of solving another problem. Specifically, because, as I mentioned a couple of times already, I didn't like the solution involving the duplication of .addEventListener();.

So, follow me:

  • Combine all objects into a group on the Storyline slide and give it Alternative text:

  • Create a variable for the group in the code.
  • Trigger the animation sequence when the cursor hovers over the entire group.
  • Reverse the animation when the cursor leaves the group.

And in this case, two goals are achieved at once:

  • The code is now shorter and no longer contains duplicates.
  • When the slide scale changes, the objects also scale and move proportionally to the changes in the screen size.

?? The solution to the scaling issue is temporary. We're waiting for the promised update from Articulate, where this problem will be fixed.

Oookay, we’re done for today! Phew!


Summary

Today, we reviewed the key points of creating animations with GSAP and sequences, and discussed several new concepts:

  1. The fromTo(); method for controlling animations from an initial state.
  2. Using xPercent and yPercent instead of x and y for correct object positioning.
  3. An introduction to data arrays and their usage.
  4. Getting familiar with the forEach(); method.
  5. Applying the mixBlendMode blending mode for mixing colors.
  6. An improved approach to event handling for better animation control.

Good luck with your projects, and see you next time, N.


Lisa Humble

Training Manager

5 天前

Can I ask what is the typical time to create a 2 hour delivery elearn ?

回复
Shawn Porter

Freelance eLearning Developer and Instructional Designer ?? Specializing in Articulate Storyline 360, Camtasia, game-based learning, and 3D modeling

2 周

I couldn't agree more. Earlier today I was working on a personal project where I wanted to shuffle a series of variables. In the past I would have done this with a series of triggers and slides. Now I use a few lines of code. It makes some things in Storyline so much easier.

Amira Judeh

Instructional Designer ? eLearning Developer ? Learning Experience Designer and Facilitator ? Transforming training into impactful and engaging experiences

2 周

Javascript is still a bit intimidating for me but I can see it has such great potential to boost the Storyline projects. Thank you for sharing your experience!

Steve S.

Learning and Development Consultant

3 周

Love this

Brittany Murray

Learning and Design Expert // eLearning

3 周

Please continue this series Natalia Vostretsova ?? ! And thank you for what you bring to the ID community. I feel seen being able to blend my love for tech with ID. You are my one of my virtual ID mentors whether you realize it or not!

要查看或添加评论,请登录

Natalia Vostretsova ??的更多文章

社区洞察

其他会员也浏览了