Creating an Interactive Spinning Wheel Animation with GSAP inside Storyline

Spinning wheel animations are a fun and engaging way to add interactivity to websites or games. In this tutorial, we’ll walk through how to build a customizable spinning wheel using GSAP (GreenSock Animation Platform), a powerful JavaScript animation library. This tutorial builds upon the work of learnermancer, so I recommend checking out their tutorial as well, as I had to make quite a few changes to get it working the way I wanted.

First things first

  1. Import your wheel. Put the marker on the right side and center it vertically.
  2. Right click on your wheel and select the accessibility tab and give it an Alternate text of wheelOfFortune.
  3. Create a button to put your javascript on and add a trigger to Execute JavaScript when user clicks that button. We will put all our logic on this button trigger.

Understanding the Code Structure

Let’s break down the code step by step:

var animationTarget = document.querySelector("[data-acc-text='wheelOfFortune']");
var sections = 16;
var sectionSize = 360 / sections; // 22.5 degrees correct spot.

They work hand in hand to make it work seamlessly. If you change the duration you will notice it rotates one way and then the other. I didn’t need that so I just zeroed it out once it worked.

The first line selects the element we want to animate by using the data-acc-text attribute, which we’ll set to “wheelOfFortune”. This is a handy way to label objects in Storyline for coding purposes. Again, if you haven’t already. right-click on the circle you want to spin, select the “Accessibility” tab, and change the “Alternate text” to “wheelOfFortune”. Everything else will build upon this one item.

In my example, I have 16 sections, but you can adjust this value based on your needs (e.g., 8 for a pizza spinner, or 4 for a different design). The sectionSize variable calculates the angle of each section (e.g., 22.5 degrees for 16 sections).

function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

The getRandomInt function generates a random integer within a specified range. We’ll use this to determine where the wheel stops.

function spinWheel() {
  // First, spin the wheel for two full rotations
  gsap.to(animationTarget, {
    rotation: "+=1440", // Add 720 degrees (2 full rotations)
    duration: 0, 
    ease: "none", 
    onComplete: function() {
      // Now, determine the landing section
      var targetSection = getRandomInt(1, sections);
      var targetAngle = (targetSection - 1) * sectionSize; // Convert section to angle

      // Calculate the final rotation, considering the initial 720-degree spin
      var finalRotation = targetAngle; // This is the final angle

      // Apply the final rotation to land on the target section
      gsap.to(animationTarget, {
        rotation: finalRotation,
        duration: 5, // Adjust the duration as needed
        ease: "back.inOut(1.1)",
        onComplete: function() {
          // Update wheelTotalRotation with the finalRotation 
          player.SetVar("wheelTotalRotation", finalRotation);
          player.SetVar("wheelResult", targetSection);
          console.log("Landed on section:", targetSection);
        }
      });
    }
  });
}

// Initial Spin
spinWheel();

To make the wheel spin seamlessly, I had to create a two-part animation. The first part spins the wheel for two full rotations, while the second part lands it on the correct spot.

The first animation uses gsap.to to rotate the wheel by 720 degrees (two full rotations) with a duration of 0 (instant). Once completed, it determines the target section using getRandomInt and calculates the corresponding angle.

The second animation applies the final rotation to land on the target section, using the calculated finalRotation angle. The duration of this animation is set to 3 seconds, but you can adjust it as needed. The ease option controls the easing of the animation, providing a smooth deceleration.

Upon completion, the code updates some variables (wheelTotalRotation and wheelResult) and logs the landed section to the console.

You can now take the number it spits out in wheelResult and use that to show a layer, or some other trigger. You can build off of this from this point and do something extraordinary.

See Video below: