How I Built a SCORM eLearning Course with Just JavaScript and GSAP
By Nathan Stoker · November 8, 2026 · 9 min read

What if you could build a fully interactive SCORM course without Storyline, Captivate, or any rapid development tool at all? Just raw JavaScript, GSAP animations, and a zip file.
That is exactly what I did. I built a 10-minute Mental Math Shortcuts course from scratch using nothing but HTML, CSS, JavaScript, and GSAP. It packages as a SCORM 1.2 zip, plays on any LMS, tracks completion and scores, and includes 18 interactive slides with animated walkthroughs, drag-to-sort activities, timed challenges, and a memory card game.
Then I built a companion practice calculator so learners can keep sharpening those skills after the course ends.
In this post, I will walk you through how I built a SCORM eLearning course with just JavaScript and GSAP, why practice tools matter as much as the training itself, and how you can try both for free.
Why Skip the Rapid Development Tools?
I want to be clear: I love Articulate Storyline. I use it daily. But this project started as an experiment. Could I build something with the polish and interactivity of a Storyline course using only web technologies?
The answer is yes, with tradeoffs. Here is what a pure JavaScript approach gives you:
Total control over every pixel, animation, and interaction. No platform limitations on what you can build. A tiny file size (the entire course is under 100KB). The ability to version control everything in Git. And the flexibility to create interaction types that don't exist in any authoring tool's template library.
The tradeoff is that you are responsible for everything. Accessibility, responsive layout, SCORM communication, slide management, state tracking. Storyline handles all of that for you. This approach is for developers who want maximum creative control.
The Course Architecture
The course is structured as four files plus a SCORM manifest:
mental-math-course/
├── imsmanifest.xml ← SCORM 1.2 package manifest
├── index.html ← Course shell (header, slide area, nav)
├── css/styles.css ← All visual styling
├── js/scorm.js ← SCORM 1.2 API wrapper
├── js/slides.js ← All 18 slide templates + interaction logic
└── js/app.js ← Navigation, scoring, progress, lifecycle
Each file has a single responsibility. The HTML is a thin shell with a header, a slide area, and a nav bar. The app controller handles navigation, scoring, and the slide lifecycle. Each slide is a self-contained object with its own HTML template and init function.
The Slide Definition Pattern
Every slide follows the same structure. This makes it easy to add, remove, or reorder content:
const slide03_round_teach = {
id: 'round-teach',
html: `
<div class="slide-inner">
<span class="strategy-badge round">🎯 Strategy 1 — Round & Adjust</span>
<p class="slide-subtitle">When a number is close to a friendly number,
round it, multiply, then adjust.</p>
<div class="math-display" id="s3-math">29 × 6 = ?</div>
<div id="s3-steps">
<div class="math-step" id="s3-a" style="opacity:0;">
<span class="label">Think</span><span>29 is close to 30…</span>
</div>
<!-- more steps -->
</div>
</div>`,
init(slide, ctx) {
const tl = ctx.gsap.timeline({ defaults: { ease: 'power3.out' }, delay: 0.3 });
tl.to('#s3-a', { opacity: 1, duration: 0.4 })
.to('#s3-b', { opacity: 1, duration: 0.4 }, '+=0.4')
.to('#s3-c', { opacity: 1, duration: 0.4 }, '+=0.4');
}
};
The init function receives a context object with GSAP, navigation helpers, and scoring methods. This keeps each slide isolated while still communicating with the course controller.
The SCORM 1.2 Wrapper
The SCORM integration is lightweight. The wrapper finds the LMS API by walking up the window chain (standard SCORM 1.2 pattern), then exposes simple methods:
const ScormAPI = (() => {
let api = null;
let initialized = false;
function findAPI(win) {
let attempts = 0;
while (win && !win.API && attempts < 10) {
if (win.parent && win.parent !== win) {
win = win.parent;
} else if (win.opener) {
win = win.opener;
} else {
break;
}
attempts++;
}
return win?.API || null;
}
return {
init() {
const scormApi = findAPI(window);
if (scormApi) {
scormApi.LMSInitialize('');
scormApi.LMSSetValue('cmi.core.lesson_status', 'incomplete');
scormApi.LMSCommit('');
}
},
setScore(score) { /* ... */ },
setComplete() { /* ... */ },
setLocation(loc) { /* ... */ },
finish() { /* ... */ }
};
})();
The course uses cmi.core.lesson_location for bookmarking, cmi.core.score.raw for scoring, cmi.suspend_data for state persistence, and cmi.core.lesson_status for completion. When the learner finishes, LMSFinish fires on beforeunload.
If no LMS is detected, the course runs standalone with a console message. No errors, no broken experience.
What the Course Teaches
The course covers five mental math strategies across 18 slides:
Multiplication strategies: 🎯 Round & Adjust (round to a friendly number, multiply, correct the difference), ✂️ Break Apart (split one factor by place value, multiply each piece, add), and ⚖️ Double & Halve (halve the even factor, double the other).
Division strategies: 🧩 Factor Out (break the divisor into smaller factors, divide step by step) and 🔄 Think Backwards (use multiplication facts in reverse).
Each strategy follows a teach, try, practice progression. Animated walkthroughs show the thinking step by step with GSAP timelines. Interactive exercises let learners build solutions themselves. Knowledge checks reinforce strategy selection.
The Interactions
This is where skipping the authoring tool actually shines. Without template constraints, I could build exactly the interaction each concept needed.
Click-to-Place (Slide 4)
Learners select answer chips and click drop zones to build a step-by-step solution. The zones validate against expected answers and show targeted feedback:
if (cId === correct) {
contentEl.textContent = selectedBtn.textContent;
z.classList.add('correct');
selectedBtn.classList.add('placed');
checkComplete();
} else {
z.classList.add('incorrect', 'animate-shake');
ctx.showFeedback('s4-feedback',
'Not quite — think about what 48 rounds to.', 'incorrect');
}
Double & Halve Manipulative (Slide 9)
Learners click buttons to double or halve each factor, watching the numbers transform in real time until the problem becomes trivially easy:
document.getElementById('s9-dblA').onclick = () => {
if (!solved) { a *= 2; b /= 2; update(); }
};
When either factor becomes a round number or single digit, a "I see it!" button appears. This mirrors the mental experience of recognizing when a problem has become simple enough to solve in your head.
Memory Match Game (Slide 14)
A flip-card matching game pairs division problems with their multiplication twins (96 ÷ 8 matches 8 × 12 = 96). A timer tracks speed. This reinforces the Think Backwards strategy by making learners connect division and multiplication facts physically.
Strategy Sorting (Slide 15)
Learners click problems to select them, then click the correct strategy bin. Wrong answers trigger a shake animation and a hint. This tests strategy identification, not just calculation.
Timed Final Challenge (Slide 17)
Four problems, 60 seconds, type your answers. The timer changes color as time runs low. After submission, each problem shows the recommended strategy. This is the capstone that ties everything together.
GSAP Animations: The Secret Sauce
GSAP makes this course feel like a real authoring tool built it. Every teach slide uses a GSAP timeline to reveal steps sequentially:
const tl = ctx.gsap.timeline({
defaults: { ease: 'power3.out' },
delay: 0.3
});
tl.to('#s6-a', { opacity: 1, duration: 0.4 })
.to('#s6-b', { opacity: 1, duration: 0.4 }, '+=0.3')
.to('#s6-c', { opacity: 1, duration: 0.4 }, '+=0.3')
.to('#s6-d', { opacity: 1, duration: 0.4 }, '+=0.3');
Strategy cards on the overview slide stagger in. The trophy on the completion slide rotates continuously. Feedback messages animate into view. These small touches add up to a polished learning experience.
Why Practice After the Course Matters
Here is the part most course developers skip.
A 10-minute course can introduce five strategies. It can walk learners through examples, let them try a few problems, and quiz them on strategy selection. But it cannot build fluency. Fluency comes from repeated practice over time.
Research on skill acquisition is clear: spaced practice beats massed practice. A learner who completes the course and then practices three problems a day for two weeks will retain far more than someone who completes the course and never thinks about it again.
This is the gap between "I understand the concept" and "I can actually do this." Understanding that 29 × 6 can be solved as (30 × 6) − 6 is one thing. Recognizing, mid-conversation, that the tip on a $48 dinner is a Round & Adjust problem, that takes practice.
The Companion Practice Calculator
To bridge that gap, I built a companion tool: the Mental Math Breakdown Calculator. You type any arithmetic problem and it shows you the best strategy from the course, with step-by-step thinking you can follow in your head.
The calculator uses the same five strategies the course teaches: 🎯 Round & Adjust, ✂️ Break Apart, ⚖️ Double & Halve, 🧩 Factor Out, and 🔄 Think Backwards. For addition and subtraction, it adds Round & Compensate and Place Value strategies.
Smart Strategy Selection
The calculator does not just pick one approach. It analyzes the problem and identifies every applicable strategy, then flags the best one. For 25 × 12, it shows Double & Halve as the best strategy (halve 12, double 25, solve 50 × 6 = 300) while also offering Break Apart and Round & Adjust as alternatives.
Learners can click between strategy tabs to see the same problem solved multiple ways. This reinforces the course lesson that multiple strategies often work, and teaches learners to recognize which one is most efficient.
The Thought-Bubble Step Format
Instead of numbered instructions, the calculator models the inner monologue of solving in your head. Italic "think" steps show the reasoning ("29 is close to 30..."). Bold "calc" steps show the math. A final "result" step confirms the answer. Each step animates in sequentially.
Every strategy also includes a "Why does this work?" explanation that matches the course teaching.
Built for Mobile
The calculator uses an on-screen keypad rather than relying on the device keyboard. Number keys, four operators, clear, backspace, and a "Break it down" button are all right there. Desktop users can also just type normally. Quick-try example chips from the course (29 × 6, 48 × 5, 25 × 12, 144 ÷ 12) let learners jump straight to practice.
How I Built a SCORM eLearning Course: Key Takeaways
Building a SCORM course with just JavaScript and GSAP is absolutely possible. It gives you total creative control, tiny file sizes, and interaction types no template library can match. The tradeoffs are real: you own every line of accessibility, responsiveness, and LMS communication code.
If you want to try this approach, here is what I would recommend. Start with the architecture: a thin HTML shell, a SCORM wrapper, a slide definition pattern, and an app controller. Use GSAP for all animations. Keep each slide self-contained with its own HTML and init function. Test on your LMS early.
And build a practice tool. The course teaches the strategies. The tool helps learners actually use them. Together, they close the gap between knowledge and skill.