community
654 TopicsCC Text Adjustment in Modern Player
Hi Team, A code snippet to adjust closed caption text in Storyline: var player = GetPlayer(); var style = document.createElement('style'); style.innerHTML = ` .caption-text { max-width: 90vw !important; padding: 10px 20px !important; box-sizing: border-box; white-space: normal !important; overflow-wrap: break-word !important; } `; document.head.appendChild(style); This works in the Classic Player. In the Modern Player, if we modify and use, it only works when the screen is adjusted to 100% zoom. Could you please advise if there’s a supported way to adjust CC text styling in the Modern Player that works across all screen sizes, or an updated approach/code for this? Thank you!9Views0likes0CommentsBalancing Interactivity and Simplicity in E-Learning Design
Hi everyone, As I continue to work on different e-learning projects, one recurring challenge I’ve faced is striking the right balance between interactivity and simplicity. On one hand, learners often stay more engaged when the course includes branching scenarios, interactive quizzes, and simulations. On the other hand, too many features can sometimes overwhelm the learner, slow down performance, or distract from the actual learning objectives. This raises a few questions I’d love to hear your thoughts on: When do you decide that interactivity is essential, and when is it better to keep things simple? How do you test whether learners are truly benefiting from interactive elements, or just enjoying the novelty? Are there any frameworks or best practices you follow to evaluate the right “depth” of interactivity in a course? Do you use data (completion rates, time spent, quiz scores, feedback, etc.) to adjust interactivity levels, and if so, how? Personally, I’ve found that aligning every design choice directly with the learning objectives helps avoid overcomplication. But I’m curious to learn how others here in the Articulate community approach this balance. Looking forward to your insights!24Views2likes0CommentsStoryline 360 Pros — What’s Your Favorite “Hidden Gem”? 💎
As someone who’s spent a lot of time working with (and on!) Storyline 360, I’ve come to appreciate the power in the little things — those lesser-known features that quietly make our lives easier. Here's one of my personal favorites: 🎧📽️ Cue Points with the “C” Key: I recently spoke with a customer who struggled to time trigger actions to audio and video media on their slides. They would preview the slide, make note of when a trigger should be fired, then return to slide authoring view to add a cue point to the timeline to tie into the trigger event. This would require a lot of manual back-and-forth between authoring and previewing. I often have to do the same thing, and there is an easier way. If you use stage preview (accessible via the "Play" icon" in the lower-left corner of the Timeline panel), Storyline will stay in the slide authoring view and play the timeline of the slide, including any audio or video media that's present. As it plays, you can press the "C" key on your keyboard to have cue points added to the current playback position. It’s a simple way to place cue points in real time, right where they’re needed — perfect for syncing trigger actions to specific moments in your media. cting Storyline 360's UI and using the "C" key to drop cue points on the timeline. Now I’m curious: What’s your favorite under-the-radar Storyline feature? Something small, subtle, maybe even a little obscure — but that you personally couldn’t live without. Drop it in the comments — I’d love to learn what little gems you rely on. 👇1.1KViews9likes28CommentsAuto-Generate PDF Certificates in Storyline (No HTML Edits Needed)
UPDATE August 20, 2025: I uploaded the new version of the file I've been using. It adds a layer for the learner to double-check their name, then blocks them from editing the name again if they download the certificate, in order to prevent multiple people from generating the certificate. I recently developed a way to generate a certificate PDF in Storyline without having to edit the published files. That means it works even in Storyline Preview and Review 360, and it's simple enough to use as a team-wide template. I drew inspiration from Devlin Peck’s tutorial, but updated the code to follow current JavaScript standards and removed the need to modify output files manually. You’ll find the full code and a sample .story file at the bottom of this post. If you like it or have any suggestions for improvement, let me know! You can also see an example version of it in action here, using a simple certificate template from Canva: https://philwingfield.com/wp-content/certificate-generator/story.html Table of Contents: What You’ll Need Define Your Storyline Variables Certificate Background Image Changing Orientation to Portrait Placing Text on the Certificate Naming the PDF File Triggering the Script in Storyline Troubleshooting TL;DR Full Code .story File (attached to post) What You’ll Need Storyline (obviously!) A background image for your certificate (.jpg or .png, set to A4 size) Recommended: Some sort of code reader such as Visual Studio Code Somewhere to upload the certificate file for testing, such as AWS (though there are instructions for local storage below under the Certificate Background Image header) Define Your Storyline Variables You’ll need to set up the Storyline variables that will be pulled into the certificate. Here are the variables I used: Storyline Variable Purpose UserName Learner’s name (typed in by the user) CHANGECourseName Course name (manually set per course) CHANGECreditHours Number of credit hours (manually set) ⚠️ Variable names are case-sensitive. userName ≠ UserName. I made this as a template for our team, so the variables beginning with CHANGE are the ones they will change manually when using the template in a course by changing the values of these variables: The current date is handled inside the JavaScript, so you don’t need to create a date variable in Storyline. Here’s how the script pulls in those values: This line gets us ready to pull the variables from storyline, and the next few lines redefine the Storyline variables as JavaScript variables: const player = GetPlayer(); And then this line pulls the value of the UserName variable from Storyline and stores it in a new JavaScript constant called name (a constant is a type of variable that does not change later) const name = player.GetVar(“UserName”); So then we do that with all the variables: const player = GetPlayer(); const name = player.GetVar("UserName"); const course = player.GetVar("CHANGECourseName"); const hours = String(player.GetVar("CHANGECreditHours")); If you need to pull in other variables, follow the same pattern. There is another variable, date, which is defined in the code itself in lines 20-24 and returns the current date. It does not need to be input to Storyline. You could also pull in quiz data if you like. In Storyline, make a number variable on the last slide (I'll call it score) and make a trigger to set score equal to the internal variable Quiz1.ScorePercent when the timeline starts. Then you could use something like this code after line 10: const score = player.GetVar("score")+"%"; The +"%" part will append a % sign to the end, so a learner answering 4/5 correctly will display as 80% instead of just 80. Don't forget to tell jsPDF where to draw it during the Placing Text on the Certificate section below! Certificate Background Image You’ll need a background image for your certificate — It should be sized as A4 landscape (297mm x 210mm)***. Make sure to leave space for where the name, course name, date, and number of credit hours can go. Note that jsPDF will compress the background image, so I would recommend doubling the photo size to 594x420mm if you want the higher resolution, or even tripling it. It will look less blurry when it is scaled down. Here’s an example background you can view (hosted via S3): 📎 certificate_example.png (Note: I may not maintain this file indefinitely.) To load the image in the code, host it somewhere with public access (like AWS with a direct link), and reference the URL like this on line 2: const CERT_BG_IMG_URL = "https://yourhost.com/your_image.png"; Alternatively, you can reference an image placed locally in the story_content folder after publishing and reference it as “/story_content/your_image_name.jpg”, but that will not work in Preview or Review 360. ***The defaults for a standard 8.5x11" are 216mmx280mm. jsPDF will convert your image to the correct size as defined in line 70, so the certificate may be slightly distorted if you don't use A4 sizing. Changing Orientation to Portrait There are 2 steps if you want to change your image to portrait instead of landscape. In line 62: remove orientation: 'landscape' so it is just curly brackets: {} The default for jsPDF is portrait A4, so we only need to define it as landscape if we want it that way. In line 70: change the size of the imported image. Swap the 297 and 210 in that line (the x and y lengths) so it reads (img, 0, 0, 210, 297) This will force whatever image you import to be 210mm wide and 297mm high, so make sure you change line 2 from the URL for my certificate to whatever certificate you have, or else it will be distorted. Make sure that your portrait image is portrait A4 as well. 🚧 CORS Warning If you’re hosting the image online, make sure CORS is enabled in the hosting service so it can load locally and in preview mode. For AWS: 🔗 Enable CORS in Amazon S3 If your PDF shows text but no background image, this may be why. The script is written to fall back and still display text if the image fails to load. Placing Text on the Certificate You’ll manually position the text using jsPDF’s .text() function. Here's an example: doc.setFont("times", "bold"); doc.setFontSize(30); doc.text(name, doc.internal.pageSize.width / 2, 130, { align: 'center' }); .setFont() – sets the font and weight. There are 14 accepted fonts from jsPDF, and you can see the parameters in the image below, taken from the jsPDF documentation: If you want to import custom fonts, Devlin Peck once again has a good tutorial: https://www.devlinpeck.com/content/jspdf-custom-font .setFontSize() – sets the font size .text() – 4 fields separated by commas which let you define the text (in this case it is the variable “name,” which was defined earlier in line 14), the x coordinate from the left, the y coordinate from the top, and then the alignment in reference to that coordinate. Note that the x coordinate in the example above uses a formula to place it in the exact center of the document from left to right. The y coordinate, 130, means it is 130mm from the top. To determine where your text should go: Open your certificate background in Canva, GIMP, or another editor Use guides or measurement tools to identify the X/Y positions. For example, in this screenshot, I had a line drawn in canva, opened the position editor, and could see the y coordinate at 129.97mm for the end where the name would go. So, it is entered as 130 in the text() function Use those values in the .text() calls in your script You can also preview your placement by: Pressing F12 to open the console in preview, review 360, or a published course. Copying and pasting your entire code into the console. Then you can paste again and quickly adjust the x/y coordinates until you get it fine-tuned. This is also a good way to check for console errors if the download is not happening (copying and pasting the console error message into google is how I discovered the CORS issue from above). Naming the PDF File Line 54 defines the filename for the downloaded certificate: doc.save(`${name}_${course}_certificate.pdf`); The ${} symbols simply allow you to call a variable, in this case name and course. If you wanted to make it a static name, you could replace that with something like: doc.save("Course Certificate.pdf"); Triggering the Script in Storyline Use a Storyline trigger like this: Make sure this happens after the learner has entered their name, or the UserName variable won’t have any value. In my example file, the js script is triggered when the certificate generation layer is opened and the learner clicks the "Continue to Download" button. I also have another js script set to execute when the timeline begins on the base layer (it makes the variable update as the user types their name, rather than after they click off of the field). Make sure you are editing the one tied to the download button. If the download button won't appear for some reason, then just set the button's initial state to normal instead of hidden. A.I. Troubleshooting As of 2025, generative AI like chatGPT and deepseek excels at catching things like syntax errors (e.g., missing a bracket), cleaning up code, or giving solutions to a very targeted question asking how to arrive at a very particular result. It can be an exercise in frustration if you don't have a clear idea of what you want the result to be, and you often have to help it troubleshoot yourself if something doesn't work. However, it is an excellent tool, especially for people like me who have a hobbyist-level understanding of JavaScript. Here are some suggested question types for how to use generative AI to troubleshoot - I find it works best when you ask the entire question at once, otherwise it won't wait and will just start generating: - "Why isn't [wanted action] happening when I run this code: [paste entire script]?" - "This script below gives me the date format as MM/DD/YYYY. How can I change it to the full written month name, like July 4, 2025? [paste the part of the script that generates the date variable]" - "The script isn't running at all. What's the issue with this code? [paste entire script]" - "How can I make a record of each time someone generates a certificate?" - "I want to change the color of the course title. How can I do that? [paste section that draws the text]" - "Explain line by line in detail what this section of code you gave me does [paste the code that it gave you]" Just keep in mind that generative AI will confirm what you ask and will often have on blinders about your issue. When you go to someone experienced and explain what you're doing to solve a problem, that person will often be able to give you a completely different way to approach it that's simpler and more elegant. Generative AI will almost never do that. Instead, it will dig into the method that you were trying and attempt to make THAT work, even if it is overly complicated or will never actually function. TL;DR Set up your Storyline variables Add a background image to your certificate Use jsPDF to place Storyline variables over it Trigger the script No need to modify published files Works in Preview and Review 360 as well as published outputs Generative AI is a great troubleshooter (to an extent) Full Code // --- CONFIGURABLE SETTINGS --- // const CERT_BG_IMG_URL = "https://philwingfield.com/wp-content/open-content/certificate_example.png"; // Background image URL (A4 landscape: 297mm x 210mm) // --- LOAD jsPDF LIBRARY DYNAMICALLY --- // const script = document.createElement('script'); script.src = "https://cdnjs.cloudflare.com/ajax/libs/jspdf/3.0.1/jspdf.umd.min.js"; /** * Main logic to generate the certificate PDF after jsPDF loads. */ script.onload = () => { // --- GET VARIABLES FROM STORYLINE --- // const player = GetPlayer(); const name = player.GetVar("UserName"); const course = player.GetVar("CHANGECourseName"); const hours = String(player.GetVar("CHANGECreditHours")); // --- FORMAT CURRENT DATE --- // const now = new Date(); const dd = String(now.getDate()); const mm = String(now.getMonth() + 1); const yyyy = now.getFullYear(); const formattedDate = `${mm}/${dd}/${yyyy}`; /** * Draws the certificate text on the PDF. * @param {jsPDF} doc - The jsPDF document instance. */ function drawText(doc) { // User Name doc.setFont("times", "bold"); doc.setFontSize(30); doc.text(name, doc.internal.pageSize.width / 2, 130, { align: 'center' }); // Credit Hours doc.setFont("times", "normal"); doc.setFontSize(20); doc.text(hours, 233, 150, { align: 'left' }); // Course Name doc.setFontSize(30); doc.setTextColor(0, 0, 0); doc.setFont("times", "bold"); doc.text(course, doc.internal.pageSize.width / 2, 88, { align: 'center' }); // Date doc.setFont("times", "normal"); doc.setFontSize(24); doc.text(formattedDate, 210.64, 176.89, { align: 'left' }); // Save PDF doc.save(`${name}_${course}_certificate.pdf`); // format of the saved document name } /** * Generates the PDF, adds background image, and overlays text. */ async function generatePDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'landscape'}); // Load background image const img = new Image(); img.src = CERT_BG_IMG_URL; img.crossOrigin = "anonymous"; img.onload = function () { doc.addImage(img, 0, 0, 297, 210); // Defines position and size in mm or image drawText(doc); }; // Skips background image loading if not available; check for CORS permissions img.onerror = function () { console.warn("Failed to load certificate background image. Continuing without it."); drawText(doc); // Proceed without background }; } generatePDF(); }; // --- APPEND SCRIPT TO LOAD jsPDF --- // document.head.appendChild(script);475Views4likes13CommentsHow to Add Audio or Video to Rise 360 Introduction?
I would like to add audio or video to a Rise 360 Introduction that narrates the text. I know I can add audio or video to Lessons within the course, but I can't find a function to add audio or video to the Introduction. Does anyone know how add audio or video to the Introduction, or is it even possible in Rise 360? Screenshots provided of Dev and Preview. Thank you.Combine Quiz Banks
This should be easy, but I can't figure out a quick way to do it. My stakeholders want a 25-question quiz at the end. Using AI to generate the quiz I can only get 14 questions. Is there a way to get more? I have made a question bank for each scene to get more questions. How can I join/merge them together to generate 1 question bank with 25 + questions?SolvedRise feature request: multiple block selection
Hi all, I'd love to see a new feature in Rise: the ability to select multiple blocks at once and then move or copy them as a group. Right now, adjusting the layout of a longer lesson can be quite time-consuming, since you have to move each block one at a time. The idea is simple: You select several blocks (for example: a text block, an image block, and a video block) Then you can move them up or down together, or copy and paste them as a group This would make editing and reorganizing lessons much faster and easier Let me know if others are also missing this feature or if maybe there’s already a smart workaround I’ve missed! Please upvote if you need this feature as well! Thanks, Thom118Views2likes6Comments