javascript
89 TopicsChallenge #544: Brand Storytelling Accordion (Powered by AI & JS!) 🚀
Hi everyone! 👋 Here is my entry for this week's Accordion Interactions challenge. For the content, I decided to focus on Brand Storytelling and how brands communicate through stories rather than just hard data. I thought it would be a valuable mini-lesson for anyone interested in marketing or instructional design. But the most exciting part for me was the behind-the-scenes creation process! Yesterday (March 24th), I had the opportunity to attend the "10 AI Assistant Capabilities You’re Missing & 10 Tips to Master them" event by David Anderson, which discussed the implementation of the AI Assistant in Articulate. Around the same time, I watched an excellent video tutorial by Learning Dojo titled "Building a Sliding Accordion with New Learning Prompts Tool". I felt so inspired that I decided to test out the prompts from prompts.learningdojo.app mentioned in the video, implementing them directly into the Articulate Storyline AI Assistant. To my surprise, it worked wonderfully! 🤯 The AI generated the structure for a fully functional HTML/CSS/JS accordion. I simply placed it inside an "Execute JavaScript" trigger when the timeline starts on a blank slide. Then, from my side as an instructional designer, I only had to tweak the CSS styles (giving it a clean design with a deep blue/purple gradient) and make a few minor adjustments to the code to structure the content into two levels and ensure the text fit perfectly. I think this is a fantastic tool and workflow for adding interactive and custom UI elements to our courses. AI keeps surprising me every day! You can check out my interaction here: Brand Storytelling Accordion Hope you like it! I'd love to read your feedback.Race Back To Base
Hello! Can you make it back to base before the sandstorm hits? Play now. The thing I really love about working with vectors is how scalable they are. Even the tiniest details remain crystal clear when you scale them up. I built this demo using elements from a single vector pack created by Macrovector on Freepik. To create the illusion of movement, I used PowerPoint to recolour the wheels on the Mars Rover vehicle, and isolated parts of the tyre track. I then made a GIF using these shapes. And then placed the GIF over the modified SVG image in Storyline. This allowed me to turn the motion on/off using state changes. Pretty much everything that moves in this demo is a GIF, tucked away in a state change until it's needed. Having access to high-quality, easy-to-use graphics allowed me to focus on the instructional elements and the scoring mechanic. The 'wronger' your answer, the quicker your oxygen will deplete. Even if you reach the third question, if your oxygen hits zero, you will have to start again. This is controlled by JavaScript, which adjusts the value of the variable by a set amount when triggered. var player = GetPlayer(); var penalty = 35; // Change to 45 or 55 depending on the button var battery = player.GetVar("Battery"); var elapsed = 0; var interval = 100; var steps = 10000 / interval; var amountPerStep = penalty / steps; var timer = setInterval(function() { elapsed++; battery = Math.max(0, battery - amountPerStep); if (battery === 0) { player.SetVar("Battery", 0); clearInterval(timer); } else if (elapsed >= steps) { player.SetVar("Battery", Math.round(battery)); clearInterval(timer); } else { player.SetVar("Battery", Math.round(battery)); } }, interval); The eagle-eyed among you will have also noticed that when this demo runs on a desktop, the closed captions that accompany the narration have been repositioned and have a slight 'glitch' effect as they appear. This is also achieved with JavaScript. Despite the recent improvements to the closed caption feature in Storyline, sometimes I prefer to manually override the position of the captions to better suit my layout. This code only reliably works in desktop view, though. const mobileView = window.innerWidth < 768 || window.innerHeight < 500; var storyW = 1280; var storyH = 720; var boxLeft = 850; var boxTop = 430; var boxWidth = 350; var boxHeight = 200; var captionFontSize = 20; function positionCaptions() { if (mobileView === true) { console.log("Mobile view detected - caption positioning skipped."); return; } var leftPct = (boxLeft / storyW * 100).toFixed(2) + "%"; var topPct = (boxTop / storyH * 100).toFixed(2) + "%"; var widthPct = (boxWidth / storyW * 100).toFixed(2) + "%"; const css = ` .caption-container { position: absolute !important; transform: none !important; } .caption { position: absolute !important; left: ${leftPct} !important; top: ${topPct} !important; width: ${widthPct} !important; font-size: ${captionFontSize}pt !important; transform: none !important; z-index: 1000 !important; } @keyframes glitchstutter { 0% { opacity: 0; transform: translate(-10px, 4px) skewX(-8deg); filter: blur(6px); } 8% { opacity: 0.8; transform: translate( 10px, -4px) skewX( 9deg); filter: blur(3px); } 12% { opacity: 0; transform: translate(-8px, 2px) skewX(-6deg); filter: blur(7px); } 18% { opacity: 0.9; transform: translate( 8px, 3px) skewX( 6deg); filter: blur(1px); } 22% { opacity: 0.1; transform: translate(-12px, -2px) skewX(-10deg); filter: blur(5px); } 28% { opacity: 1; transform: translate( 6px, 0px) skewX( 4deg); filter: blur(1px); } 35% { opacity: 0.3; transform: translate(-6px, 4px) skewX(-6deg); filter: blur(3px); } 42% { opacity: 1; transform: translate( 4px, -2px) skewX( 3deg); filter: blur(1px); } 50% { opacity: 0.6; transform: translate(-3px, 1px) skewX(-2deg); filter: blur(1px); } 60% { opacity: 1; transform: translate( 2px, 0px) skewX( 1deg); filter: blur(0px); } 75% { opacity: 0.95; transform: translate(-1px, 0px) skewX( 0deg); filter: blur(0px); } 100% { opacity: 1; transform: translate( 0px, 0px) skewX( 0deg); filter: blur(0px); } } .caption-glitch { animation: glitchstutter 0.6s ease-out forwards !important; } `; let style = document.getElementById('custom-caption-style'); if (!style) { style = document.createElement('style'); style.id = 'custom-caption-style'; document.head.appendChild(style); } style.textContent = css; var capEl = document.querySelector('.caption'); if (capEl) { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { capEl.classList.remove('caption-glitch'); void capEl.offsetWidth; capEl.classList.add('caption-glitch'); }); }); observer.observe(capEl, { childList: true, subtree: true, characterData: true }); capEl.classList.add('caption-glitch'); } console.log(`Captions positioned at left:${leftPct} top:${topPct} font:${captionFontSize}pt`); } document.addEventListener('DOMContentLoaded', positionCaptions); positionCaptions(); I had a lot of fun making this. It still surprises how much mileage you can get from a small number of visual assets. If you have any more questions about this demo, please ask.
The South Africa Big 5
Hello! I'm currently sitting in Joburg Airport, waiting for my flight back to the UK after a terrific week in South Africa with New Leaf Technologies. After the Learning Indaba, I was very fortunate to spend some time with the team at Kwalata Game Lodge in Dinokeng Game Reserve. Inspired by that experience, here's my demo for this week's Accordion Challenge. This demo uses JavaScript to 'shuffle' the five parts of the accordion, reordering their z-index positions, so that the selected part always appears beneath the other four. var player = GetPlayer(); var animalValue = player.GetVar("ANIMAL"); var ids = { GrassFgd: "6HxcFGzoBsU", ELEPHANT: "6YFFSsUIcdG", RHINO: "6f62e0IMC4F", LION: "5ohBXuBxrO4", BUFFALO: "6moj2Qru7Il", LEOPARD: "6DwuJlPK3xT", GrassBgd: "64KgCoIDN33" }; // Priority order: index 0 = highest z-index (frontmost) var animalOrder = ["ELEPHANT", "RHINO", "LION", "BUFFALO", "LEOPARD"]; function getEl(id) { return document.querySelector('[data-model-id="' + id + '"]'); } function getZ(id) { var el = getEl(id); if (!el) return 0; return parseInt(window.getComputedStyle(el).zIndex) || 0; } function setZ(id, z) { var el = getEl(id); if (el) el.style.zIndex = z; } var zBgd = getZ(ids.GrassBgd); var zFgd = getZ(ids.GrassFgd); var zBase = zBgd + 1; // zBase+0 = selected (back), zBase+1..4 = others low to high // So Elephant (highest priority) gets zBase+4 when not selected, etc. if (!animalValue || animalValue.trim() === "") { // Reset: Elephant highest, Leopard lowest in the group for (var i = 0; i < animalOrder.length; i++) { // i=0 (Elephant) gets highest: zBase+4, i=4 (Leopard) gets zBase+0 setZ(ids[animalOrder[i]], zBase + (animalOrder.length - 1 - i)); } } else { var selected = animalValue.trim().toUpperCase(); // Selected goes to the very back of the group setZ(ids[selected], zBase); // Remaining animals keep their relative order, stacked above var zCounter = zBase + 1; // Walk from lowest priority to highest (Leopard up to Elephant) // so that Elephant ends up with the highest z-index for (var i = animalOrder.length - 1; i >= 0; i--) { if (animalOrder[i] !== selected) { setZ(ids[animalOrder[i]], zCounter); zCounter++; } } } // Re-pin grass layers setZ(ids.GrassBgd, zBgd); setZ(ids.GrassFgd, zFgd); Each section of the accordion is also made using an SVG image, as the transparent areas of a PNG image would have blocked users from clicking any sections beneath it. Right! I have a flight to catch! Visit the Game Reserve here: https://bit.ly/elhc544
Rise notes utility
I added a global utility bar to my Rise course to add a simple 'notes' piece, data is kept in the browser's local storage and it will not write to SCORM. Because of the global nature of this addon, it can be a handy way to make the functionality, and even some branding, always available to users across your entire course.
678Views11likes13CommentsCase: Operation Dopamine - A Noir Comic Mystery
Hi E-Learning Heroes! 👋 For this week's Comic Book-Inspired Challenge, I decided to go full "Noir Detective" graphic novel style. 🕵️♂️✨ In my project, "Case: Operation Dopamine", the learner steps into the shoes of a private investigator exploring a ransacked laboratory. The mission? To find the 6 stolen components of Gamification (such as Engagement, Customer Lifetime Value, and Emotional Connection) and restore color to a black-and-white corporate world. 🔍 Play the interactive demo here: > Play Operation Dopamine I had so much fun blending storytelling, visual design, and instructional concepts into this one. I would love to hear your thoughts and feedback!194Views2likes4CommentsMission: Survive the Stakeholder 😅 | Things to Say & Not Say to IDs
Hi everyone! 👋 For this week's challenge, I decided to gamify the classic "Instructional Designer eye twitch" moments we've all experienced during project kick-offs. Welcome to Mission: Survive the Stakeholder! In this short interaction, you play as a project manager meeting with Alex, your ID. Your goal is to choose the right things to say to get the project moving without causing his stress meter to max out. Behind the scenes: Visuals: I generated the 3D Pixar-style character states using AI to capture those perfect, relatable expressions of creeping panic. The Tech: To make the stress meter feel fluid, I built a custom HTML/CSS/JS interaction and embedded it as a Web Object in Storyline. The custom slider is dynamically synced with the background video, so Alex's reactions update smoothly in real-time as your score changes. You can play the demo here: Mission: Survive the Stakeholder I had so much fun putting this together. I’d love to hear your thoughts! Did you manage to keep Alex calm, or is he currently updating his resume? 😂246Views5likes2CommentsBurning Questions
Hello! Another tongue-in-cheek demo, with a serious message. But I don't recommend that you take this passive-aggressive route to explain gamification to your boss... This demo is built around an oversized slider, which is animated using rapid state changes controlled by Javascript. Video sections created in Powtoon. Any questions, please ask. I promise I won't turn you into a computer game character in a burning building. Try it for yourself here: https://bit.ly/elhc542
Perfect Match?
Hello! Typography is a big part of elearning design. And being a total font nerd, I love it when I find the 'Perfect Match'. This interaction is built around two dials and has been optimised for mobile phones. Javascript randomises the starting position of the dials at the start of each game. It also controls how far the dial turns with each tap. When the value of Dial1 and Dial2 match, a feedback layer is shown, and the score increases. When you hit 4/4, the game resets. The AI voiceover is 'Liam' with the style exaggerated to ~70, and I used Suno to create the game show-style theme tune. This plays on repeat until the score hits 4/4, when it is stopped and replaced by applause. But you can also mute the music during the game if it's not your jam. The content is based on this article. I had a lot of fun making this one! Let me know what you think. If you have any questions, please ask. PLAY HERE: https://bit.ly/elhc54093Views2likes0CommentsTurn That Light Off
Hello! Non-human characters can be a strong choice for your e-learning courses. They're often more popular with users than AI avatars. My characters always come across as a bit grumpy, for some reason... Believe it or not, this is a regular 'pick one' freeform question slide. The character was created using Nano Banana, and I manipulated it in Pixlr to create the different mouth shapes. The animation is achieved through rapid state changes, synchronised to the waveform of each bit of narration. This is controlled by Javascript that I wrote with the help of Claude.ai. The voice is Dave, one of my favourite Storyline AI voices, with the style exaggerated to 75 😀 Switch my demo on here: https://bit.ly/elhc539