# Scormbusters — full facts > Scormbusters is a hosted eLearning authoring tool. Its paid service migrates legacy eLearning courses — Adobe Captivate Classic, Articulate Storyline and Rise 360, Lectora, iSpring, Moodle backups, and any course where only the published SCORM output survives — into editable courses built from blocks designed for WCAG 2.1 AA (your content and a human review decide conformance), exported back to SCORM 1.2, SCORM 2004, cmi5 or xAPI. - No lock-in: export to SCORM 1.2, SCORM 2004, cmi5 or xAPI, or as a project file that imports back, and packages keep working in your LMS if you leave. (https://scormbusters.com/#no-lock-in) - A full editor: 37 block types, a Scenes slide editor with triggers, branching, question pools, review links, version history and co-editing. (https://scormbusters.com/#full-editor) - Bring your own AI: connect Claude, ChatGPT, Cursor, VS Code, Codex or Gemini over MCP; we never call a model and sell no AI credits. (https://scormbusters.com/#bring-your-own-ai) ## What it does - Imports a legacy course, from its source file or from the published package alone, into an editable course: lessons of text, images, audio/video, and quiz questions with their correct answers where the package records them. - Rebuilds the course as content from blocks designed for WCAG 2.1 AA (your content and a human review decide conformance; see /accessibility-conformance) — reflowing lessons for most formats (Captivate, Rise, Lectora, iSpring, Moodle, generic SCORM), an editable slide canvas for slide-based Storyline and for Captivate courses whose actions keep state — and checks contrast, alt text and structure while you author. - Exports SCORM 1.2, SCORM 2004, cmi5 and xAPI packages for any LMS. LTI 1.3 is in beta: launch, learner provisioning and AGS grade passback to the LMS gradebook on completion. Every course also exports to a portable source file. - Identifies the authoring tool from a package's contents, not its file name. - Reads packages as data; no script from an uploaded package is ever run. - Includes a full authoring environment: block-based lesson editor, slide canvas, visual branching. - Free accessibility scan: upload a published course zip or paste its URL; get findings by severity and a transcript of what a screen reader announces. No account; the file is uploaded for scanning only and deleted immediately, never kept. ## Import formats - Adobe Captivate Classic: .cptx project files (Captivate 9, 2017 and 2019; slides, text, images, narration audio, question pools and quiz questions with answer keys read from the binary project), and HTML5 publishes from Captivate 9 to 2019 (read from the published output alone) - Adobe Captivate 12/13 (all-new Captivate) publishes - Articulate Storyline HTML5 publishes, including graded quiz questions with answer keys - Articulate Rise 360 exported packages (SCORM, xAPI, cmi5 or web), block for block - Lectora (published HTML, and .awt project files from Lectora Inspire 12 onward) - iSpring Suite and QuizMaker publishes, versions 8.7 to 11.15 - Generic SCORM 1.2 and SCORM 2004 packages, AICC, cmi5 and xAPI (Tin Can) - Adapt / Evolve, H5P - IMS Common Cartridge (.imscc) and QTI 1.2/2.x - Moodle course backups (.mbz, Moodle 1.9 to 4.x); user data is never imported - PowerPoint (.pptx) - Articulate Studio (Presenter '09) packages are recognized — slide titles, text and notes are read; content inside Flash is reported, not converted ## What does not survive import - Storyline triggers, variables and object states are rebuilt from the HTML5 publish as working Scenes triggers where the slide canvas runs them the same way (jumps, layers, show/hide, variables with their conditions, named states, media): 49% of trigger actions across the test corpus. Execute JavaScript, motion paths, conditions mixing AND with OR, and conditions on built-in states or object properties are not, and are counted in the import report. - Captivate Classic actions are rebuilt as working triggers on the slide canvas, where it runs them the same way, when a course keeps state with them (a variable, a conditional or advanced action, a state change): jumps, show and hide, variables, if/else with AND or OR, shared actions and state changes; 40% of Classic publish actions and 9.7% of all-new 12/13 actions across the test corpus. Execute JavaScript, effects, timeline pauses, a jump to the last visited slide and conditions on Captivate's own variables do not, and the import report counts them. A software simulation is editable content, not a working simulation: its click boxes keep their jumps and reveals, not their scoring or timing. - Flash-era (pre-HTML5) packages recover structure only: the outline, titles and media stored outside the SWF. Text drawn inside a SWF cannot be read back. Flash-only Captivate publishes are not converted. - Articulate Studio packages are recognized: Presenter '09 slide titles, text and notes are read; anything compiled into Flash (Quizmaker questions, Engage interactions, Presenter visuals and narration) is reported, not converted. - Imported courses are not pixel-identical to the original: most formats become lessons that reflow; slide-based Storyline keeps its layout on an editable slide canvas. - Every import produces a report of anything that could not be carried across. - Across 98 real published courses re-imported on every release: words 100%, images 99%, media 98%, quiz questions 83%; interactions rebuilt as working triggers: Storyline 49%, Captivate Classic 40%, all-new Captivate 9.7%. The import report lists everything else. - No automated check proves WCAG conformance; the scan and the editor's checker find problems, and a human review with assistive technology is still needed. ## Dates and context (checked 2026-09-26) - Adobe Captivate Classic support has not ended: Adobe lifted its announced end date on 2025-03-17 and says support continues until customers have transitioned. - Captivate 13.1 (2026-04-16) includes a beta Classic importer: .cptx files from 11.8.3 onward only, non-responsive output, and it does not accept published-only courses. - The all-new Captivate (12/13) cannot open Classic .cptx files directly. - Articulate Studio 360 (Presenter, Quizmaker, Engage), Replay 360 and Peek 360 reach end of support on 2026-12-31. - ADA Title II web rule (US state and local government): WCAG 2.1 AA by 2027-04-26 for entities serving 50,000 people or more, 2028-04-26 for smaller ones and special districts. - HHS Section 504 rule (extended by HHS's May 2026 interim final rule): WCAG 2.1 AA by 2027-05-11 for recipients of HHS funding with 15 or more employees, 2028-05-10 for those with fewer. - Adobe ended Flash Player on 2020-12-31; SWF-based courses no longer play in current browsers. - Scormbusters is proprietary hosted software (on-premises deployment is available under an Enterprise agreement); the player inside every exported package is MIT-licensed, so customers can deliver and redistribute their courses freely. ## Pricing model - Authoring: hosted plans are flat — Designer $20/month for one author, Studio $149/month per organization for up to 10 authors, never per seat or per learner; annual billing takes 20% off. Each starts with a 14-day trial (card required). Enterprise is by agreement; on-premises deployment is available under an Enterprise agreement. - Migrations: importing and previewing are free; an imported course counts once, when it is first exported or published. Designer includes 5 a month, Studio 25, Enterprise unlimited, the trial 3. Annual Studio migrates Rise courses without counting for its first 60 days. - Migration credits: $99 a course; 10 for $790; 50 for $2,950. They don't expire while the account is open. - Library Pass: $4,900 one-time — up to 150 course migrations, 12 months of Studio and a dated accessibility evidence report. Library Pass Plus: $9,500 one-time — up to 500 course migrations and 12 months of Enterprise LTI 1.3 hosted delivery. - Done-for-you migration: $600–$1,200 a course, quoted. - The accessibility scan is free. ## Facts by topic ### Migrate your courses https://scormbusters.com/migrate (last reviewed 2026-11-14) - Scormbusters imports published courses from Storyline, Rise 360, Captivate, Lectora, iSpring, Adapt, H5P and Moodle, and any SCORM, AICC, cmi5 or xAPI package; from Articulate Studio it reads Presenter '09 text and notes only, and Flash content is not converted. - Source files are optional: the published package is enough. - Across 98 real published courses re-imported on every release: words 100%, images 99%, media 98%, quiz questions 83%; interactions rebuilt as working triggers: Storyline 49%, Captivate Classic 40%, all-new Captivate 9.7%. The import report lists everything else. - Every import produces a report listing what did not come across. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### LTI 1.3 setup https://scormbusters.com/docs/lti (last reviewed 2026-10-05) - Scormbusters is an LTI 1.3 tool (beta): OIDC login, signed JWT verification with per-org RS256 keys served over JWKS, nonce replay protection, and automatic learner provisioning. - AGS grade passback is implemented: when the platform includes the lti-ags claim in the launch, the final score and completion are posted to the LMS gradebook when the learner finishes the course. - Launched learners are provisioned viewer-role accounts keyed to the LTI identity (issuer + subject), never linked through the platform's unverified email claim. - Launch and AGS grade passback are verified end to end against Canvas (open-source canvas-lms; assignment and module-item placements) and Moodle 5.2.3 (2026-10-05, automated): passing and failing scores arrive in each gradebook. Not yet verified on Blackboard; Deep Linking and NRPS are not implemented. - LTI delivery is an Enterprise feature, on the hosted service or on-premises. ### Webhooks https://scormbusters.com/docs/webhooks (last reviewed 2026-10-03) - Ten webhook events: course.published, course.unpublished, enrollment.created, enrollment.completed, lesson.completed, quiz.submitted, certificate.issued, user.joined, user.removed and invite.accepted. - Every delivery is signed (HMAC-SHA256 over the raw body, X-OpenCourse-Signature header) with a per-webhook secret shown once at creation. - Delivery is fire-and-forget with a 10-second timeout and no automatic retry; every attempt is visible in the delivery log with status, response body excerpt and duration. - certificate.issued fires only when a learner first earns a certificate; a later failed attempt never revokes it, because completions keep the best result. ### xAPI / LRS integration https://scormbusters.com/docs/xapi (last reviewed 2026-10-03) - Scormbusters forwards xAPI statements to any LRS endpoint configured per organization; once configured, lesson and course completions forward automatically with nothing to enable per course. - Exports are also available as native cmi5 and Tin Can (xAPI) packages, where the package itself talks to the LRS and resume state lives in the LRS State API. - An on-premises install may point at an LRS on a private network address; the hosted service refuses private addresses (SSRF guard). ### LMS compatibility https://scormbusters.com/docs/lms-compatibility (last reviewed 2026-10-03) - SCORM 1.2 and SCORM 2004 3rd Edition exports are verified on SCORM Cloud (Rustici's reference engine) by automated full-course runs; re-verified 2026-10-03 with both registrations recording COMPLETED / PASSED / 100. - A from-scratch Moodle 4.5 in Docker is driven headlessly on every probe run: 22 checks pass under SCORM 1.2 and 46 under 2004 (the 2004 Moodle run is a data-model smoke test; Moodle documents its own 2004 support as incomplete). - Two platform quirks are handled and documented: SCORM Cloud and Moodle both leave cmi.core.entry empty on resume under 1.2, and suspend_data truncation is silent, so the exports budget for the 4,096-character SCORM 1.2 floor. - Anyone can reproduce the results: the conformance probe is a SCORM package, shared on request, that imports into any LMS. ### Accessibility https://scormbusters.com/docs/accessibility (last reviewed 2026-10-03) - Accessibility covers two different things and Scormbusters documents both: the published course a learner experiences, and the authoring tool an author operates — most vendors' VPATs explicitly exclude the authoring application. - Matching, sorting and drag interactions ship a single-pointer select-then-place alternative (WCAG 2.2 SC 2.5.7) and full keyboard paths (SC 2.1.1), guarded by automated tests that fail on regression. - Contrast, dialog semantics, focus management and per-control names are enforced by tests (contrast ratios computed from the design tokens; shared primitives take a required label, so an unnamed control does not compile). - No self-graded conformance report is published: a third-party WCAG-EM assessment is the bar before any ACR/VPAT goes in front of procurement. ### Custom interactions https://scormbusters.com/docs/custom-interactions (last reviewed 2026-10-08) - The Custom Interaction block (custom_html) runs author code in an iframe sandboxed to allow-scripts only, from srcdoc, with its own Content Security Policy: no network requests, no external scripts, no same-origin access, no session. - A custom interaction reports to the course over postMessage (protocol opencourse-interaction): a score out of a maximum with optional pass/fail, completion, up to 1,000 characters of JSON state, and its height. - Scores count toward the lesson score and pass mark in the Scormbusters player and in SCORM 1.2, SCORM 2004, cmi5 and xAPI exports; saved state persists with the learner's attempt in the app and in suspend_data within the SCORM 1.2 4,096-character limit. - A custom interaction's score is self-reported by its code in the learner's browser and recorded as such; it is not tamper-proof, like any client-side SCORM content. ### Captivate Classic migration https://scormbusters.com/captivate-classic-migration (last reviewed 2026-11-14) - Adobe has not ended Captivate Classic support: on 2025-03-17 it lifted its announced end date and said support continues until customers have transitioned. - Captivate 13.1 (2026-04-16) has a beta Classic importer: .cptx from 11.8.3 onward only, non-responsive output, no published-only courses. - Captivate cannot open its own published output; only the .cptx is editable in Captivate. Scormbusters works from either, so a lost .cptx is not a blocker. - Scormbusters reads Classic .cptx project files (validated against real files from Captivate 9, 2017 and 2019/11.0), Classic HTML5 publishes from Captivate 9 to 2019 (through 11.8), and all-new Captivate 12/13 publishes. - From a .cptx: slides, text, images, narration audio, question pools, and quiz questions with answer keys — multiple choice, true/false, multiple answer, short answer, fill-in, matching, sequence and hotspot. From a publish additionally: video, closed captions and the pass mark. - When a course keeps state with its actions, they are rebuilt as working triggers on the slide canvas where it runs them the same way: button, click-box and slide enter/exit actions (jumps, show and hide, variables, conditional and shared actions, state changes from a publish). In our test corpus that was 40% of Classic publish actions and 67% from a .cptx. - Does not come across: Execute JavaScript, effects, timeline pause and continue, a jump to the last visited slide, text-entry logic and conditions on Captivate's own variables; each is counted in the import report. Flash-only (SWF) publishes are not converted. A .cptx from a 2019 point release later than 11.0 that refuses to read is imported via its published HTML5 output instead. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### Open a .cptx in the new Captivate https://scormbusters.com/open-captivate-classic-project-in-new-captivate (last reviewed 2026-09-26) - The all-new Adobe Captivate (12 and 13) cannot open Captivate Classic .cptx files directly; Adobe describes the two as not compatible. - Captivate 13.1 (2026-04-16) added a beta importer (Import > Captivate Classic) for .cptx files saved in 11.8.3 or later; output is non-responsive. - Captivate Classic (11.8.x) is still available with the same license and still supported; Adobe lifted its end date on 2025-03-17. - Scormbusters imports Classic .cptx files and Classic HTML5 publishes from Captivate 9 to 2019 as editable courses. - Every import produces a report listing what did not come across. ### Captivate to Storyline or Rise https://scormbusters.com/convert-captivate-to-storyline-or-rise (last reviewed 2026-11-14) - Storyline 360 and Rise 360 cannot import Captivate .cptx files or Captivate published output as editable content. - The usual workarounds are rebuilding by hand, re-importing the original PowerPoint if one exists, or embedding the published Captivate course as a web object. - Scormbusters imports Captivate .cptx files and HTML5 publishes into editable, responsive lessons, then exports SCORM, cmi5 or xAPI that any LMS accepts. - Into Storyline or Rise, advanced actions, variables and simulation logic are rebuilt by hand; into Scormbusters, Captivate Classic actions are rebuilt as working triggers where the slide canvas runs them the same way (40% of publish actions in our test corpus), and the rest is listed in the import report. ### Edit SCORM without the source file https://scormbusters.com/edit-scorm-without-source-file (last reviewed 2026-11-14) - Captivate, Storyline and iSpring cannot re-open their own published SCORM output; editing needs the source file or a tool that reads the package. - Scormbusters identifies the authoring tool from a package's contents and reads Captivate, Storyline, Rise 360, Lectora, iSpring, Adapt, H5P, generic SCORM 1.2/2004, AICC, cmi5 and xAPI packages. - Storyline triggers and Captivate Classic actions are rebuilt as working triggers where the slide canvas runs them the same way: 49% and 40% respectively in our test corpus. Custom JavaScript never is. Flash-era packages recover structure only. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### Lost .story file? Storyline output to editable https://scormbusters.com/storyline-published-output-to-editable (last reviewed 2026-11-14) - Storyline cannot open published output; without the .story file the published package is the only copy of the course. - Scormbusters reads Storyline HTML5 publishes (SCORM, xAPI or web) and rebuilds each slide on an editable slide canvas with its real text, images, audio and video. - Graded questions arrive with their answer keys: multiple choice, multiple response, true/false, word bank, fill-in-the-blank, numeric, matching, sequence and hotspot. - Triggers are rebuilt as working triggers where the slide canvas runs them the same way (jumps, layers, show/hide, variables and their conditions, named states, media): 49% of trigger actions across our test corpus. Execute JavaScript, motion paths and the rest are counted in the import report. - Flash-era Storyline publishes (no html5 folder) recover structure only. ### Rise 360 alternative https://scormbusters.com/rise-360-alternative (last reviewed 2026-11-14) - Articulate's pricing page (checked 3 November 2026) lists Articulate 360 AI at $1,749 per seat per year for L&D teams and $1,449 per seat per year for instructional designers. - Rise 360 has no downloadable source file; Articulate's own community answers (checked 2026-11-03) say that once a subscription lapses you can no longer edit or export Rise courses, and that Articulate keeps them for a period after a paid subscription expires. - Exported Rise packages (SCORM, xAPI, cmi5 or web) keep playing without a subscription but cannot be edited in Rise. - A Rise export (Publish → LMS, standard package, or Publish → Web) is the portable copy of a Rise course; Scormbusters imports it block for block as an editable course. - Rise scenarios keep their branching: each choice keeps its feedback and leads to the slide the author chose, in the Scormbusters player and in the exported SCORM package. - Embedded Storyline blocks arrive as their text, pictures and questions, not as a working interaction; everything not recreated is listed in the import report. - Scormbusters Studio is $149 a month per organization for up to 10 authors, or 20% less billed annually. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### Articulate Studio end of support https://scormbusters.com/articulate-studio-end-of-support (last reviewed 2026-11-14) - Articulate Studio 360 (Presenter, Quizmaker, Engage), Replay 360 and Peek 360 reach end of support on 2026-12-31 (Articulate's Studio 360, Replay 360, and Peek 360 End-of-Support Guide, accessed 2026-11-14). - After that date Articulate stops updates and technical support; the apps remain available and functional, and published content keeps working without republishing. - Storyline 360 imports Quizmaker projects (64-bit Storyline: Quizmaker 360 only) and Engage interactions only while the matching Engage is installed and activated. - Scormbusters does not convert Studio courses: it reads Presenter '09 slide titles, text and notes, and reports content inside Flash without converting it. - A Presenter course's original .pptx imports into Scormbusters as an editable course. ### Flash (SWF) eLearning to HTML5 https://scormbusters.com/convert-flash-elearning-to-html5 (last reviewed 2026-09-26) - Browsers removed Flash Player support after Adobe ended it on 2020-12-31; SWF-based courses no longer play in a current browser. - No tool reliably converts SWF course content into editable HTML5; the content is compiled into the SWF. - Scormbusters recovers structure only from Flash-era packages: the course outline, slide or page titles, and media files stored outside the SWF. Text drawn inside the SWF cannot be read back. - Articulate Presenter '09 packages are the exception with more to read: slide titles, text and notes come from presentation.xml. - Flash-only Captivate publishes are not converted. ### Lectora course to editable https://scormbusters.com/convert-lectora-course (last reviewed 2026-11-14) - No other mainstream authoring tool imports Lectora courses; moving tools usually means a manual rebuild. - Scormbusters reads Lectora published HTML and Lectora .awt project files (the XML format of Lectora Inspire 12 onward). - A .awt project keeps question answer keys in plain text; its images and video come across when the whole project folder is zipped. - Measured on 9 real Lectora packages (Lectora Inspire 11.3 to Lectora 22): every word and picture came across, and 63% of quiz questions; the import report lists the questions it could not rebuild. - Lectora actions and variables are not converted; the import report lists each one for rebuilding. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### iSpring course to editable https://scormbusters.com/convert-ispring-course (last reviewed 2026-11-14) - iSpring Suite edits the source PowerPoint and project folder; a published iSpring package cannot be re-opened in it. - Scormbusters reads published iSpring Suite and QuizMaker output, versions 8.7 to 11.15. - Slides become lessons of real text in reading order, with slide notes, audio, video and embedded quiz questions with their answers. - Measured on 7 real iSpring packages (8.7 to 11.15): every word came across, and 72% of quiz questions; questions with pictures in their feedback, drag-and-drop and hotspot questions are listed in the import report instead. - iSpring interactions and dialogue simulations are not converted; the import report lists each one for rebuilding. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### Moodle backup (.mbz) to SCORM https://scormbusters.com/moodle-backup-to-scorm (last reviewed 2026-11-14) - Moodle has no built-in export of a course as a SCORM package; a .mbz backup restores only into Moodle. - Scormbusters reads Moodle backups from 1.9 to 4.x (.mbz, zip or tar.gz). - Sections become modules; pages, labels and books become content; resources and folders become downloads; quiz questions become question blocks with answers where Scormbusters has an equivalent question type. - Measured on 5 real Moodle backups (Moodle 1.9, 2.4 and 2.9): every word came across, and 48% of quiz questions; calculated, essay, drag-and-drop-onto-image and random short-answer matching questions and surveys are listed in the import report instead. - Forums, assignments and other activities bring their instructions only; the report lists what was left behind. - User data in a backup (accounts, posts, submissions, attempts) is never imported, only counted in the report. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### ADA Title II and eLearning https://scormbusters.com/ada-title-ii-elearning-accessibility (last reviewed 2026-11-14) - ADA Title II web rule: WCAG 2.1 AA by 2027-04-26 for state and local governments serving 50,000 people or more. - ADA Title II web rule: WCAG 2.1 AA by 2028-04-26 for smaller governments and special districts. - HHS Section 504 rule, as extended by HHS's May 2026 interim final rule: WCAG 2.1 AA by 2027-05-11 for recipients of HHS funding with 15 or more employees, and by 2028-05-10 for those with fewer than 15. - Online courses delivered through an LMS are web content under these rules. ### Make old eLearning WCAG 2.1 AA https://scormbusters.com/make-elearning-accessible-wcag (last reviewed 2026-09-26) - Many WCAG failures in legacy courses come from the authoring tool's player — fixed slide sizes (1.4.10 Reflow), mouse-only interactions (2.1.1 Keyboard) — and cannot be fixed by editing the published package. - Fixing a course in its original tool requires the source file and a license for that tool. - The free Scormbusters scan checks a published course zip or URL, lists findings by severity and shows what a screen reader announces; it needs no account. - No automated tool proves WCAG conformance; a human review with assistive technology is still needed. ### Bring your own AI https://scormbusters.com/bring-your-own-ai (last reviewed 2026-11-14) - Scormbusters makes no AI calls and stores no AI keys. Authors connect their own assistant (Claude, ChatGPT, Claude Code or any MCP client, including local models) to the Scormbusters MCP server; the assistant edits courses with the author's approval, billed on the author's existing subscription. - There are no AI credits, allowances or AI fees in Scormbusters on any plan, and AI is entirely optional: the editor, player and every export work without ever connecting one. - Articulate 360 AI is priced at $1,449 (for Instructional Designers) to $1,749 (for L&D Teams) per seat per year, as listed on articulate.com, checked 2026-11-14. - Articulate's advanced AI features (AI avatars, translation, training kits) additionally consume credits sold from $250 per 50,000, in 25,000-credit packs; per Articulate's pricing page, credits expire at the end of the subscription term and do not roll over. - A Claude Pro or ChatGPT Plus subscription is about $20 per month, works across every tool that speaks MCP — not just one vendor's editor — and is the same subscription many authors already pay for. - The Model Context Protocol (MCP) is an open standard; the Scormbusters MCP server exposes 32 documented authoring tools, authorized per user over OAuth and revocable at any time. ### SCORM conformance https://scormbusters.com/scorm-conformance (last reviewed 2026-10-03) - A full multi-lesson course export with a graded quiz was verified on SCORM Cloud on 2026-09-24 under both SCORM 1.2 and SCORM 2004 3rd Edition: registration recorded completed, passed, score 100; deliberate wrong answers recorded failed with the remediation path shown. Re-verified 2026-10-03 with the current exporter: both standards again recorded completed, passed, 100. - The conformance probe passed 22 checks under SCORM 1.2 on SCORM Cloud (2026-09-17) and 22 under 1.2 plus 46 under 2004 on a from-scratch Moodle 4.5 (2026-09-17), zero failures, including suspend_data at each spec's full floor (4,096 and 64,000 characters) and resume across a relaunch. - Both SCORM Cloud and Moodle open the SCORM session before the content does, so the content's own Initialize call returns false on a healthy session; content that treats that as fatal breaks on the reference implementation. - Both SCORM Cloud and Moodle leave cmi.core.entry empty on resume rather than 'resume'; a player that trusts entry restarts every returning learner. Scormbusters reads lesson_location and suspend_data directly. - Moodle's own documentation says its SCORM 2004 support is incomplete (no sequencing), so a passing Moodle 2004 run is a data-model smoke test, not a conformance claim; the 2004 claim rests on SCORM Cloud. - The probe is a SCORM package that interrogates any LMS it runs in — it talks to window.API directly, not through Scormbusters' driver — and anyone can build it from source and run it against their own LMS. ### Accessibility conformance https://scormbusters.com/accessibility-conformance (last reviewed 2026-10-01) - Published courses target WCAG 2.1 AA plus WCAG 2.2's dragging-movements criterion (SC 2.5.7), which most authoring vendors formally concede ('Does Not Support') in their own reports. - Every drag interaction in published courses has a single-pointer alternative (select, then place) and a keyboard path; SC 2.5.7 requires the single-pointer one, which a keyboard path alone does not satisfy. - The authoring tool itself was audited against WCAG 2.2 AA and ATAG 2.0 Part A on 2026-09-17; the failures found (canvas not keyboard-operable, ~45 unnamed controls, systemic contrast, no announcements) are fixed and each fix is held by a test. - No mainstream authoring vendor publishes an accessibility conformance report for its authoring application — only, sometimes, for published output. - A third-party WCAG-EM audit has not yet been performed; that is stated on the page rather than papered over. No automated check proves WCAG conformance. - Every published course embeds captions where stored, visible focus, non-color-only feedback, declared language and prefers-reduced-motion support; each is enforced by an automated test. ### Audit a course library for accessibility https://scormbusters.com/elearning-library-accessibility-audit (last reviewed 2026-11-14) - A library scan takes many published packages, or one zip of packages exported from an LMS, and runs the accessibility scan and the LMS package check on each; nothing is imported and the uploads are deleted as soon as they are read. - The library report shows which WCAG criteria fail in which courses and recommends fix now, fix later, keep or retire for each one, weighted by how many learners take it a year; it downloads as CSV. - Designer scans up to 25 packages at a time, Studio up to 100 and Enterprise without a limit; one package at a time is always free at /scan, with no account. - Any scanned course's text downloads as a Word document and its questions as CSV, on every plan, without importing it. - A fixed course can be exported with 'Replace the original in your LMS', which keeps the original package's identifiers so completions and grades stay attached (verified in Moodle); in-course bookmarks start over. - No automated scan proves WCAG conformance; the library report says what to fix first, and a human review with assistive technology is still needed. ### Articulate 360 alternative https://scormbusters.com/articulate-360-alternative (last reviewed 2026-11-14) - Articulate 360 AI is $1,449 per seat per year for Instructional Designers and $1,749 per seat per year for L&D Teams, as listed on articulate.com/360/pricing, checked 2026-11-14, with AI features drawing on credits. - Scormbusters costs $20 a month for one author, or $149 a month per organization for up to 10 authors; learners and reviewers are never counted. - Scormbusters never makes an AI call and sells no credits: an author connects their own Claude, ChatGPT or local model over MCP, and AI is optional. - Published Storyline (HTML5) courses and exported Rise 360 packages import as editable courses; Storyline triggers are rebuilt as working triggers where they would run the same (49% of trigger actions in our test corpus), and everything left out is listed in the import report. - Scormbusters runs in a browser on Windows, macOS and Linux; Storyline 360 is a Windows desktop application. - Exports: SCORM 1.2, SCORM 2004, cmi5 and xAPI. ### Captivate alternative https://scormbusters.com/captivate-alternative (last reviewed 2026-11-14) - Adobe has not set an end date for Captivate Classic; on 2025-03-17 it lifted the one it had announced. - The all-new Captivate (12/13) cannot open a Classic .cptx directly; the beta importer in Captivate 13.1 takes .cptx files from 11.8.3 onward and produces non-responsive output. - Scormbusters imports Classic .cptx files, Classic HTML5 publishes from Captivate 9 to 2019, and all-new Captivate 12/13 publishes, so a course whose source is lost still comes across. - Captivate actions are rebuilt as working triggers on a slide canvas where it runs them the same way: 40% of Classic publish actions and 9.7% of all-new 12/13 actions in our test corpus. Execute JavaScript and effects never are, and each is counted in the import report. - Scormbusters runs in a browser on Windows, macOS and Linux, and exports SCORM 1.2, SCORM 2004, cmi5 and xAPI with no Scormbusters branding. ### Free accessibility scan https://scormbusters.com/scan (last reviewed 2026-10-12) - The accessibility scan reads a published SCORM, cmi5, xAPI or AICC package itself — every screen, including those behind branching — rather than crawling the course in a browser. - It reports against six WCAG 2.1 success criteria a machine can be certain about: 1.1.1 Non-text Content (missing or filename alt text), 1.2.2 Captions, 1.3.1 Info and Relationships (heading order), 2.1.1 Keyboard, 2.4.6 Headings and Labels (unnamed controls and hotspots) and 3.1.1 Language of Page. - Each finding quotes what a screen reader actually announces, and the report includes a transcript of the worst screen read aloud. - No automated scan proves WCAG conformance; the report finds problems, and a human review with assistive technology is still needed. ### Import scorecard https://scormbusters.com/scorecard (last reviewed 2026-11-14) - Across 98 real published courses re-imported on every release: words 100%, images 99%, media 98%, quiz questions 83%; interactions rebuilt as working triggers: Storyline 49%, Captivate Classic 40%, all-new Captivate 9.7%. The import report lists everything else. ### Free SCORM package checker https://scormbusters.com/check (last reviewed 2026-10-06) - The package checker reads the manifest and every file it names without running the course's code, so runtime findings are flagged as risks, not proofs. - It catches a manifest one folder down — the result of zipping the folder instead of its contents — which most LMSs reject. - It flags launch and listed files whose names differ only in upper/lower case: they work on Windows and macOS and fail on Linux LMS servers. - SCORM 1.2 guarantees 4,096 characters of resume data (cmi.suspend_data); the checker warns when a Storyline course published as SCORM 1.2 is large enough to risk it, and SCORM 2004 3rd Edition raises the limit to 64,000. - cmi5 and xAPI packages are checked for IRI activity ids and launch files that exist; AICC packages for all four course structure files. ## For AI agents - MCP server: https://scormbusters.com/api/mcp (Streamable HTTP; sign in with your Scormbusters account over OAuth, or send a personal access token (oc_pat_…) from Settings → API). A connected assistant can build courses, import and fix legacy Storyline and Captivate courses (including writing alt text for their pictures with view_scene_images), audit accessibility, and export SCORM, cmi5 or xAPI packages. - [MCP reference for LLMs](https://scormbusters.com/docs/mcp/llms.txt): setup for each client and every tool with its schema, examples and errors (same text at https://scormbusters.com/docs/mcp.md). - MCP setup for people: https://scormbusters.com/docs/mcp - REST API reference: https://scormbusters.com/docs/api (OpenAPI spec at https://scormbusters.com/api/openapi) ### MCP tools Every tool's schema, examples and errors: https://scormbusters.com/docs/mcp.md. - `list_courses` (read-only): List courses. - `get_course` (read-only): Get course structure. - `create_course`: Create course. - `update_course`: Update course. - `add_module`: Add module. - `add_lesson`: Add lesson. - `get_lesson` (read-only): Get lesson content. - `add_block`: Add block. - `update_block`: Update block. - `delete_block`: Delete block. - `list_block_types` (read-only): List block types. - `update_module`: Update module. - `update_lesson`: Update lesson. - `set_flow`: Set branching flow. - `audit_course` (read-only): Audit course. - `export_course` (read-only): Export course package. - `get_scene_slide` (read-only): Get Scenes slide. - `view_scene_images` (read-only): View a slide's pictures. - `update_scene_object`: Update Scenes object. - `update_scene_slide`: Update Scenes slide. - `upload_asset`: Upload asset. - `import_course`: Import legacy course. - `create_review_link`: Create review link. - `get_review_feedback` (read-only): Get review feedback. - `apply_review_suggestion`: Apply review suggestion. - `resolve_review_comment`: Resolve review comment. - `reply_review_comment`: Reply to review comment. - `search_library` (read-only): Search the library. - `replace_in_library`: Replace across the library. - `undo_library_replace`: Undo a library replace. - `search` (read-only): Search course content. - `fetch` (read-only): Fetch course content. ### REST API operations Authenticate with an organization API key (oc_live_…, created under Settings → API by an owner or admin) in the X-API-Key header. - `POST /api/courses`: Create a course - `PATCH /api/courses/{courseId}`: Update a course - `DELETE /api/courses/{courseId}`: Delete a course - `GET /api/courses/{courseId}/certificate`: Get course completion certificate - `GET /api/courses/{courseId}/enrollments`: List enrollments for a course - `POST /api/courses/{courseId}/enrollments`: Enroll learners or groups - `DELETE /api/courses/{courseId}/enrollments/{enrollmentId}`: Remove enrollment - `GET /api/analytics/events`: Query analytics - `POST /api/analytics/events`: Track analytics event - `GET /api/webhooks`: List webhooks - `POST /api/webhooks`: Register a webhook ## All pages - [Migrate your courses](https://scormbusters.com/migrate): Move courses from Storyline, Rise 360, Captivate, Lectora, iSpring, Articulate Studio, Flash-era packages, Moodle or any SCORM/AICC/cmi5/xAPI package into editable courses, from the published output, no source files needed. - [LTI 1.3 setup](https://scormbusters.com/docs/lti): Connect Scormbusters to Canvas, Moodle or Blackboard as an LTI 1.3 tool: registration, keys, launch flow, learner provisioning, and AGS grade passback to the LMS gradebook. - [Webhooks](https://scormbusters.com/docs/webhooks): HMAC-signed webhooks for ten course, learner and organization events, with per-event payloads, signature verification, delivery behavior and delivery logs. - [xAPI / LRS integration](https://scormbusters.com/docs/xapi): Forward learning activity statements to any xAPI Learning Record Store, configured per organization, with the exact statement schemas sent. - [LMS compatibility](https://scormbusters.com/docs/lms-compatibility): What is verified where: dated SCORM Cloud and Moodle runs for SCORM 1.2 and 2004, the per-LMS matrix, the two platform quirks every vendor hits, and how to reproduce every claim. - [Accessibility](https://scormbusters.com/docs/accessibility): What is accessible today, how it is enforced in code, and what remains: the published course output, the authoring tool itself (ATAG), and the automated checks that gate regressions. - [Custom interactions](https://scormbusters.com/docs/custom-interactions): Run your own HTML, CSS and JavaScript in a lesson, sandboxed, and track it: the Scormbusters API and postMessage protocol for score, completion, saved state and height, the sandbox, and the limits. - [Captivate Classic migration](https://scormbusters.com/captivate-classic-migration): Move Adobe Captivate Classic courses (9 to 2019, plus all-new 12/13) into editable, responsive courses, from the .cptx or from the published output alone. - [Open a .cptx in the new Captivate](https://scormbusters.com/open-captivate-classic-project-in-new-captivate): Why the all-new Captivate (12/13) will not open a Captivate Classic .cptx, what Adobe's beta importer in 13.1 accepts, and the options when it does not fit. - [Captivate to Storyline or Rise](https://scormbusters.com/convert-captivate-to-storyline-or-rise): There is no Captivate importer in Storyline or Rise 360. The realistic options for moving Captivate courses to another tool, and what can be automated. - [Edit SCORM without the source file](https://scormbusters.com/edit-scorm-without-source-file): Turn a published SCORM package into an editable course — text, media and, where the package carries them, quiz questions with answer keys — and re-export it. - [Lost .story file? Storyline output to editable](https://scormbusters.com/storyline-published-output-to-editable): Recover the text, images and quizzes from a published Storyline HTML5 package when the .story file is gone. - [Rise 360 alternative](https://scormbusters.com/rise-360-alternative): Keep every Rise 360 course editable without a per-seat subscription: what Articulate 360 costs, how to export each Rise course before renewal, and what a Scormbusters import keeps. - [Articulate Studio end of support](https://scormbusters.com/articulate-studio-end-of-support): What Articulate Studio 360's end of support on 2026-12-31 means, Articulate's own routes into Storyline 360 and Rise 360, and exactly what Scormbusters can and cannot do with Studio packages today. - [Flash (SWF) eLearning to HTML5](https://scormbusters.com/convert-flash-elearning-to-html5): The options for Flash-era courses when there is no source file — emulation, re-recording, rebuilding — and the structure-only recovery Scormbusters can do. - [Lectora course to editable](https://scormbusters.com/convert-lectora-course): Convert a Lectora course — the published HTML or the .awt project — into an editable, responsive course and new SCORM, cmi5 or xAPI. - [iSpring course to editable](https://scormbusters.com/convert-ispring-course): Edit a published iSpring Suite or QuizMaker course without the original PowerPoint or project folder, and export it again. - [Moodle backup (.mbz) to SCORM](https://scormbusters.com/moodle-backup-to-scorm): Turn a Moodle course backup into an editable course and a SCORM, cmi5 or xAPI package for another LMS. User data is never imported. - [ADA Title II and eLearning](https://scormbusters.com/ada-title-ii-elearning-accessibility): The ADA Title II and HHS Section 504 WCAG 2.1 AA deadlines for online courses, and how to remediate a legacy course library before them. - [Make old eLearning WCAG 2.1 AA](https://scormbusters.com/make-elearning-accessible-wcag): How to make an existing Captivate, Storyline or SCORM course WCAG 2.1 AA accessible: what can be patched, what cannot, and when to migrate instead. - [Bring your own AI](https://scormbusters.com/bring-your-own-ai): Scormbusters charges nothing for AI: connect the Claude or ChatGPT subscription you already pay for over MCP. Compare that with authoring tools that price AI per seat with expiring credits. - [SCORM conformance](https://scormbusters.com/scorm-conformance): How Scormbusters SCORM 1.2 and 2004 exports are verified: automated runs against SCORM Cloud and a from-scratch Moodle 4.5, every claim dated, every check reproducible. - [Accessibility conformance](https://scormbusters.com/accessibility-conformance): The live WCAG 2.1 AA status of Scormbusters' published courses and of the authoring tool itself — per-claim evidence, enforced by tests, gaps stated plainly. - [Audit a course library for accessibility](https://scormbusters.com/elearning-library-accessibility-audit): Scan a whole library of published SCORM, cmi5, xAPI and AICC courses at once: which WCAG criteria fail where, which courses to fix first or retire, and the text of each course without importing it. - [Articulate 360 alternative](https://scormbusters.com/articulate-360-alternative): A flat-priced, browser-based alternative to Articulate 360 that imports published Storyline and exported Rise 360 courses as editable ones, and uses your own AI assistant instead of credits. - [Captivate alternative](https://scormbusters.com/captivate-alternative): Choosing a tool after Adobe Captivate: a browser-based editor that imports Captivate Classic projects and publishes, and all-new 12/13 publishes, as editable courses. - [Scormbusters vs ScormEdit](https://scormbusters.com/compare/scormedit): ScormEdit patches text and images in a package; Scormbusters rebuilds the course as editable content, quizzes included. - [Free accessibility scan](https://scormbusters.com/scan): Upload a published course zip or paste its URL and get a WCAG accessibility report plus a screen-reader transcript. No account; the file is uploaded for scanning only and deleted immediately, never kept. - [Free rebuild preview](https://scormbusters.com/preview): Upload a published course and play it rebuilt as an editable Scormbusters course, with the list of anything to rebuild by hand. Free, no account, no card; the private link lasts seven days. - [Import scorecard](https://scormbusters.com/scorecard): What share of words, images, media, quiz questions and interactions Scormbusters recreates, measured on every release across real published courses from 13 authoring tools and standards. - [Free SCORM package checker](https://scormbusters.com/check): Check a published SCORM 1.2, SCORM 2004, cmi5, xAPI or AICC zip before uploading it to an LMS: what will break, what it means for learners and how to fix it. No account; the file is uploaded for checking only and deleted immediately, never kept. - [Pricing](https://scormbusters.com/pricing): Hosted authoring plans with a 14-day trial; importing is free and migrations are counted when an imported course is first exported, with credits, a Library Pass or done-for-you migration for larger libraries. - [Help center](https://scormbusters.com/help): How-to guides for importing, editing, checking and exporting courses. - [Documentation](https://scormbusters.com/docs): Every Scormbusters guide and reference in one place: getting started, the block and Scenes editors, migration, delivery to an LMS, accessibility, plans, AI assistants over MCP and the developer APIs. - [REST API reference](https://scormbusters.com/docs/api): REST API reference (OpenAPI 3): courses, enrollments, analytics and webhooks, with request and response shapes. - [MCP server](https://scormbusters.com/docs/mcp): Connect your AI assistant to Scormbusters over the Model Context Protocol. - [Import a Captivate course](https://scormbusters.com/help/import-captivate): Import a Captivate .cptx or published HTML5 course, step by step. - [Import a Storyline course](https://scormbusters.com/help/import-storyline): Import a published Storyline HTML5 package and what to expect on the slide canvas. - [Import a published SCORM package](https://scormbusters.com/help/import-published-scorm): Import any SCORM, AICC, cmi5 or xAPI package when the source file is gone. - [Read the import report](https://scormbusters.com/help/reading-the-import-report): What each line of the import report means and how to act on it. - [Export to your LMS](https://scormbusters.com/help/export-to-lms): Export SCORM 1.2, SCORM 2004, cmi5 or xAPI and replace the old package in your LMS. - [Use the accessibility checker](https://scormbusters.com/help/accessibility-checker): Find and fix contrast, alt text, structure and keyboard problems while you author. # Help guides (full text) ## Open or edit a Captivate 2017/2019 course without Captivate URL: https://scormbusters.com/help/open-captivate-project-without-captivate Last updated: 2026-09-26 No Captivate license, an old .cptx that newer versions reject, or only the published SCORM zip left? Here is what each option can and cannot recover, and how to get an editable course from the published output alone. The problem: You inherited Captivate 2017 or 2019 courses. Nobody has Captivate any more, the .cptx files may be missing, and you need to change a few screens — or the whole course. ### Why it is hard A .cptx is a binary project file that only Captivate Classic reads, and projects move forward only: a project saved in a newer build cannot be opened by an older one. Very old projects (`.cp`, from Captivate 4 and earlier) need an intermediate Captivate version that Adobe no longer offers to convert them. And the published output — the SCORM zip in your LMS — is a player plus compiled data, which no version of Captivate can open. ### Your options - **Get Captivate Classic.** If you have the .cptx and the change is small, a Captivate subscription (which Adobe says includes Classic) is the most faithful route: the course stays exactly as it was. - **Edit the published files by hand.** In a Captivate HTML5 publish most on-screen words are drawn into images and the rest live in a compiled JavaScript file (`assets/js/CPM.js`), so changing text by hand is fragile and changing structure is not realistic. - **Rebuild** in another tool from screenshots of the running course. Reliable, but slow for anything long. - **Convert the .cptx or the published output** into an editable course (below). A Captivate 9, 2017 or 2019 .cptx imports directly into Scormbusters — slides, text, images, narration and quiz answer keys — with no Captivate license. ### What Scormbusters recovers from the published zip Upload the SCORM, xAPI or HTML5 zip you already have. Scormbusters reads `CPM.js` as data — the slides, the caption text, each item's accessibility text, images, audio, video, closed captions and the quiz definitions with their correct answers — and rebuilds each slide as a lesson of ordinary blocks. It has been tested on real publishes from Captivate 9 to 2019 and from the all-new Captivate 12 and 13. A course whose actions keep state — variables, conditional (advanced or shared) actions, object states — comes across on the slide canvas instead, with its button, click-box and slide actions as working triggers. Execute JavaScript, effects, widgets and the timing of a slide do not come across, and software simulations keep their jumps and reveals but not their scoring. The import report counts each of these. See [Import an Adobe Captivate course](https://scormbusters.com/help/import-captivate) for the full list. Warning: A Flash (SWF) publish is different: its content cannot be read back at all. See [Convert Flash (SWF) eLearning to HTML5](https://scormbusters.com/convert-flash-elearning-to-html5). ## SCORM course doesn't resume or loses progress URL: https://scormbusters.com/help/scorm-course-not-resuming Last updated: 2026-09-26 Why learners restart a SCORM course from the beginning: SCORM 1.2's 4,096-character suspend_data limit, LMS quirks on relaunch, and new package versions — and how to diagnose each. The problem: Learners close the course halfway, come back, and start from slide one — or finish and the LMS still says incomplete. ### The most common cause: suspend_data overflow SCORM keeps a course's resume state in one text field, `cmi.suspend_data`. SCORM 1.2 guarantees only 4,096 characters; SCORM 2004 guarantees 64,000 ([Rustici: suspend data limits](https://support.scorm.com/hc/en-us/articles/206167396-Bookmarking-and-Suspend-Data-Limitations)). Long courses with many slides, variables or questions can write more than 4,096 characters. Many LMSs truncate the overflow silently, the saved state no longer makes sense to the course, and the learner starts over. To check: in the LMS's attempt details, look at the stored suspend_data. If it is exactly 4,096 characters long, or ends mid-word, it was cut off. Fixes, in order: publish as SCORM 2004 if your LMS supports it; ask the LMS vendor whether the limit can be raised; reduce what the course saves. ### Other causes worth ruling out - **The LMS opens a fresh attempt.** Some LMS settings start a new attempt on every launch; check the course's attempt settings. - **The course reads the wrong signal.** On relaunch, SCORM Cloud and Moodle both report the entry mode as empty rather than "resume", so a course that only resumes on "resume" sends everyone back to the start. - **The course closes before it saves.** Closing the browser tab rather than the course's own exit can lose the last commit. - **A new package replaced the old one.** Some LMSs reset progress when a course's package is updated. ### How Scormbusters packages avoid it Exported packages keep resume data under 3,800 characters in both SCORM versions, dropping the least important state first when a slide course saves a lot, and never dropping completed lessons, the score or question draws. They restore progress from their own saved data rather than trusting the entry mode, and check that the LMS session actually works instead of reading the return value of Initialize. Verified with a relaunch on SCORM Cloud and Moodle 4.5. See [Export a course to your LMS](https://scormbusters.com/help/export-to-lms#resume-data-and-the-suspenddata-limit). ## Import an Adobe Captivate course (.cptx or published output) URL: https://scormbusters.com/help/import-captivate Last updated: 2026-10-07 What Scormbusters reads from a Captivate Classic .cptx, a Classic HTML5/SCORM publish (CPM.js) and an all-new Captivate 12/13 publish (project.js); what comes across, what does not, and how it differs from Adobe's own Classic importer. The problem: You have Captivate Classic courses — sometimes only the published SCORM zip — and need them editable, responsive and accessible without rebuilding every slide by hand. ### Steps 1. **Find the best file you have.** Either works: a published HTML5 output (a SCORM, xAPI or web publish with an `assets/js/CPM.js` or `assets/js/project.js` inside) or the `.cptx` project file itself. Both carry the quiz answer keys; their differences are described below. 2. **Zip it as it is.** Upload the zip Captivate produced, or zip the published folder yourself. A wrapping folder, `__MACOSX` entries and a zip inside a zip are all handled. 3. **Open the importer.** From the dashboard choose **Import**, or go to `/courses/import`, and drop the file on the upload area. 4. **Import.** Choose **Import as a new course**. Files up to 100 MB are accepted. A `.cptx`, a Classic publish whose actions keep state, and an all-new (12/13) publish whose actions keep state and whose slides are all free-positioned open on the Scenes slide canvas; other Captivate courses reflow into lessons. 5. **Read the report.** The finished screen lists what could not be recreated and what is worth knowing. See [Reading the import report](https://scormbusters.com/help/reading-the-import-report). ### Which Captivate files can be imported Three different Captivate formats are recognized, and the importer decides which one it has by looking inside the file, not at its name: - **A Classic HTML5 publish** (Captivate 9 to 2019, i.e. 11.x). Captivate compiles the whole project into `assets/js/CPM.js`. It is the same whether you published to SCORM 1.2, SCORM 2004, xAPI or plain HTML5. Tested against real publishes from Captivate 9.0.2, 2019 11.0.1, 11.5.5 and 11.8.3. - **An all-new Captivate publish** (12.4 onward, including 13.x). There is no CPM.js; the model lives in `assets/js/project.js`. Tested against publishes from 12.6, 13.0 and 13.2. - **A Classic project file (.cptx).** Read directly from the binary project format, answer keys included. Tested against real project files from Captivate 9.0, 2017 (10.0) and 2019 (11.0). Nothing in a published package is ever run: the JavaScript files are parsed as data, and only literal values are read. Tip: If you have both the .cptx and a published HTML5 output of the same course, either works: both carry the quiz answer keys. The publish also carries closed captions and the pass mark; the .cptx keeps each slide's layout on an editable canvas. ### The published output alone is enough You do not need the .cptx. A Captivate HTML5 publish carries the slides, the text (as caption HTML where the version keeps it, and always as each item's accessibility text), the images, audio, video, closed captions and the quiz definitions, including which answers are correct. That is what the importer reads. This matters because the published zip is very often the only thing that survived: the project was on a departed colleague's laptop, or the vendor delivered only SCORM. ### What comes across from a published course Unless its actions keep state (see the next section), each Captivate slide becomes a lesson of ordinary, editable blocks in reading order — headings, paragraphs, images, audio and video — rather than a fixed-size slide. The point of leaving Captivate is a course that reflows on a phone, reads correctly with a screen reader and can be edited by anyone, so pixel positions and slide timing are deliberately not kept. - **Questions with their answer keys:** multiple choice (true/false publishes as a two-option choice), multiple answer, fill-in-the-blank, matching and sequence. - **Short answer:** one-to-three-word answers become a fill-in-the-blank with the same accepted answers; longer answers become a reflection that shows the author's model answer, because Captivate only ever accepted an exact sentence. - **Hotspot questions** become questions where the learner chooses the right area by name, so they work by keyboard and screen reader. - **Drag-and-drop** questions and interactions become matching or categorize questions when every item and target has words to choose by. - **Question pools:** a pool that random question slides drew from becomes a lesson holding its questions that draws as many per attempt as Captivate did. - **Click-to-reveal buttons** become accordion sections; buttons that opened a web page stay as links. - **Closed captions** are kept as transcripts; narration clips are kept and start when the learner presses play. - **The pass mark** from the quiz settings becomes the course passing score. - Text and logos repeated on most slides (master-slide furniture) are kept once, and Captivate's own results slides are left out. ### Courses whose actions keep state: the slide canvas, with working triggers A course whose actions only move between slides or reveal text loses nothing by reflowing. One whose actions keep state cannot: a variable set on one slide and tested on another, an advanced action that shows the Next button once every topic has been visited, a portrait that switches to its COMPLETED state. When a Classic publish has any of those — a variable assigned, a condition tested, an object's state changed — the whole course lands on the slide canvas instead: each slide at its size, each object where Captivate placed it and under the name Captivate gave it, and its actions rebuilt as triggers that run in the exported package. What comes across as working triggers: - **Events:** the success action of a button, a click box or a smart shape used as a button (a click); a slide's **On Enter** action (when the slide starts); its **On Exit** action (when the slide's timeline ends), on a slide that never pauses for a click. - **Jumps:** go to the next or previous slide, jump to a slide. Captivate jumps once the whole action has run, so the jump runs last here too. - **Show and hide** of objects on the same slide. - **Variables:** the project's own, with their starting values; assign, increment and decrement. Captivate's system variables (cpInfo…, cpCmnd…, cpQuiz…) are left behind. - **Conditional (advanced and shared) actions:** each if becomes a trigger per branch; AND becomes *all conditions*, OR becomes *any*, else the opposite. A toggle — an action that changes the variable its own condition tests — gets a small variable of its own (`branch_1` and on) so it reads its condition once, as Captivate does. - **Change state**, to a state the object has, with the state's picture or words. A state Captivate resets on every visit (Retain state off, its default) is reset the same way. - **Open URL** (web and mailto links) in this window or a new one. The rest of the slide comes with it: captions and shapes as text with their words, images, shapes drawn as rectangles, ellipses and lines, video, narration, and the questions as question objects that grade the same way. A question with no slide equivalent (fill-in-the-blank with several blanks, for example) is kept as text on the slide and counted in the report as **Questions kept as text on the slide**. Closed captions on this route are kept as slide notes. Tip: Each object keeps the name it had in Captivate (`Button_Transactional`, `PersonLZ`), so the triggers in the slide editor read like the advanced actions you wrote. ### All-new Captivate (12/13) actions An all-new publish keeps its actions in `assets/js/project.js` as small scripts, which are read as data and never run. They come across as working triggers when two things are true: an action a learner sets off keeps state (a variable assigned, a condition tested, an object's state changed), and **every slide is free-positioned** — each object placed where you drew it, as on a PowerPoint deck imported into Captivate. Responsive slides (paragraph and image cards, tabs, flip cards, timelines, carousels, drag-and-drop widgets, question and results slides) are laid out by Captivate's player per screen size and rebuild well only as lesson blocks, so a publish with any of them reflows into lessons; its actions that keep state are then counted in the report under **Buttons and click interactions**, with the kinds listed. On the slide canvas each object sits where Captivate's own player puts it (checked against that player rendering a real 13.2 publish), under the id Captivate gave it. What comes across as working triggers: - **Events:** an object's click actions, including **when this object is clicked, once** (it gets a variable of its own, `once_1` and on, that slide entry clears, as Captivate clears what was clicked); a slide's On Enter; hover. - **Jumps:** next, previous, go to slide. Captivate's new player jumps where the jump is and runs the rest of the action after the next slide has entered; here the jump runs last. Where that order would show — the rest of the action writes a variable that a slide's On Enter reads, or reads one it writes — the whole action is left out and counted. - **Show and hide** of objects on the same slide. - **Variables:** your own, with their starting values (a Boolean comes across as a number, 0 or 1, as Captivate stores it, and a number starts where Captivate's player reads it: as a whole number); assigning a value; **Adjust variable** adding or subtracting a whole number; **Toggle variable** on a number or Boolean (it reads the variable once, as Captivate does, through a `branch_` variable). Captivate's own variables (Quiz., Project., Date., LMS. and the rest) are left behind. - **Decisions:** each one becomes a trigger per branch, several in order, each reading what the ones before it left, as Captivate does; AND is *all conditions*, OR is *any*, else the opposite. Comparisons are equal, not equal, greater and less, as the player reads them. - **Change state** to one of your own states, with the state's words, picture, fill and text color. A state change set to reset on revisit puts the object back on every visit. Left out and counted in the report, by reason: Execute JavaScript; animations; enable and disable; a delayed or repeated action; a while loop; slide exit actions; conditions on Captivate's own variables, comparing two variables, or about objects (visited, hidden, clicked, selected); assigning from another variable or an expression; multiplying or dividing a variable, or adding a fraction; toggling a text variable, or toggling on hover; a change to a random state or to Captivate's own hover, down, visited or selected looks; return to the last visited slide; "when objects are clicked" naming other objects; and anything reading a variable a text entry field or a left-out action writes. Text entry fields themselves, shapes Scenes cannot draw (arrows, stars, irregular outlines) and the variable shown in a text are counted too. Closed captions are kept as slide notes. Tip: Of the roughly 80 public all-new publishes we have found, only the corpus's 13.2 PowerPoint-import deck is free-positioned with actions that keep state; its decisions test equality. The other comparisons, toggles, increments and hover follow Captivate's own player code and are covered by tests built from real publishes' action strings, not yet by a real publish that lands on the canvas. ### What does not come across Every one of these is counted in the import report, by reason, never dropped silently: - **Execute JavaScript** and **Apply Effect** actions, and widgets. - Actions that depend on the timeline stopping: **Continue**, **Pause**, and an On Exit action on a slide that waits for a click. Slides on the canvas do not stop, so learners move on with Next. - **Return to the last visited slide**, and an action that jumps more than once (only the last would happen in Captivate). - Conditions on Captivate's own variables, comparing two variables, or mixing AND with OR; assigning one variable from another or from an expression; and any action reading a variable that something left out (JavaScript, a text entry box) writes. - Showing or hiding an object on another slide, the click-outside (failure) and last-attempt actions of a click box, and Captivate's own rollover, down and visited looks. - Enable and disable, go to the next or previous state, play or stop audio, send e-mail, exit, and player commands (mute, volume, playbar, table of contents); links to files rather than web addresses; a jump to a point partway into a slide; setting a variable the project does not declare. - In an **all-new Captivate (12/13)** publish with responsive slides, actions are not converted: the course reflows into lessons (see the section above for free-positioned ones). - In a reflowing course (one whose actions keep no state), button actions themselves: jumps are the lesson order, revealed text is ordinary content. Text that displayed a variable, such as the learner's name, has the variable removed. - Text entry boxes outside questions, widgets, web objects and animations. - Scored clicks on slide objects (Captivate's click-box scoring), Likert surveys (kept as text) and drag-and-drop driven by the author's own JavaScript. - Pretest branching (the questions are imported as ordinary questions). - Software simulations keep their screenshots, captions and the jumps their click boxes make; the scoring, the failure captions and the timing of the click-by-click simulation do not. An imported course is editable content running in Scormbusters' player, not a copy of the Captivate player. ### Importing a .cptx project file A .cptx is read directly from its binary object store, validated against real project files saved by Captivate 9, 2017 and 2019 — in each case against the HTML5 publish of the same project, so what this route reads was checked object by object against what Captivate itself publishes. A .cptx always lands on the Scenes slide canvas. From a .cptx you get: the slides in order with their labels, every caption's text at its real position, images (including the raw-bitmap form Captivate stores for pasted or PSD-sourced pictures), slide narration audio, and the questions with their full definition — question text, options, **the answer keys**, points, and correct/incorrect feedback — for multiple choice, true/false, multiple answer, short answer, fill-in-the-blank (the list-of-answers style), matching, sequence and hotspot. Question pools come across drawing the same number of questions per attempt as Captivate did. Likert surveys are kept as text, as in the published route. Actions come across from a .cptx too, read from the project's own action records and checked one by one against the publish of the same project: the success actions of buttons, click boxes and smart shapes used as buttons, slide On Enter and On Exit, advanced and shared actions (with their parameters), go to the next slide, jump to slide, show, hide, assign, open URL, and conditions comparing one variable with == or !=. Objects keep their names and start hidden when *Visible in output* was off. A decision with several conditions, Change state and the rarer actions are counted in the report instead — the publish carries those in a form that has been checked, so import it when they matter. What the .cptx route does not read, each counted in the import report: video files stored inside the project, closed captions, the quiz pass mark, and the fill-in-the-blank style whose blank is a marked word in the sentence rather than a listed answer (the sentence itself still comes across). The published route reads closed captions and the pass mark, so if those matter, import the publish — or both, and compare. Point releases of Captivate 2019 later than 11.0 (11.5, 11.8) write the same format family but no real project file from them has been through the validation corpus; the record layout is checked as it is read, so a file this route cannot read is refused with a clear message — it never imports junk. In that case publish to HTML5 and upload the output, which is validated through 11.8.3. Very old projects (the pre-.cptx `.cp` format from Captivate 4 and earlier) are not supported. Warning: Flash-only (SWF) publishes cannot be converted. Their content is compiled into Flash movies that cannot be read as data; see [Convert Flash (SWF) eLearning to HTML5](https://scormbusters.com/convert-flash-elearning-to-html5). ### How this differs from Adobe's Classic importer Adobe added a beta importer for Classic projects to Captivate 13.1, announced on 16 April 2026 ([Adobe's announcement](https://elearning.adobe.com/2026/04/announcing-adobe-captivate-13-1-bring-your-classic-projects-forward/)). If you want to keep authoring in Captivate, it is the natural thing to try first — it is part of the subscription you already pay for. The differences that decide between them: - **Status.** Adobe's importer is labeled beta; Adobe says imported projects may need manual fixes. - **Input.** Adobe's importer needs the .cptx. It cannot start from a published-only course. Scormbusters can. - **Versions.** Adobe's release notes say projects from versions earlier than 11.8.3 are not officially supported. Scormbusters reads Classic publishes from Captivate 9 onward. - **Layout.** Adobe's importer produces non-responsive projects. Scormbusters produces lessons that reflow. - **Where you end up.** Adobe's importer leaves you in the all-new Captivate; Scormbusters leaves you in an editor with SCORM 1.2, SCORM 2004, cmi5 and xAPI export and a portable source file. Captivate Classic has not reached end of support. Adobe lifted its earlier end date in March 2025 and says Classic will be supported until customers have transitioned ([Adobe blog, 17 March 2025](https://elearning.adobe.com/2025/03/coming-soon-solution-to-migrate-your-captivate-classic-courses-to-the-new-adobe-captivate/)). Migrate when responsive output, accessibility or editing without a Captivate license matter to you, not because of a deadline. ## Import a published Storyline course (no .story file needed) URL: https://scormbusters.com/help/import-storyline Last updated: 2026-10-07 How Scormbusters recovers the real text, pictures, layers, quizzes and triggers from a Storyline HTML5 publish — including text hidden behind Storyline's font subsetting — and exactly what does not survive: JavaScript, motion paths and the few trigger forms Scenes cannot run the same way. The problem: The .story file is gone, and all you have is the published output — a SCORM zip or a folder with `story.html` and `html5/` in it. Storyline cannot open that. ### Steps 1. **Check it is an HTML5 publish.** Look for a folder called `html5/data/js` inside the zip. If it is there, the full import applies. If there is only `story_content/` with `.swf` files, it is a Flash-era publish (see below). 2. **Upload the zip.** From the dashboard choose **Import** and drop the zip. You can zip the published folder yourself; a wrapping folder or a zip inside a zip is fine. 3. **Import and open in the slide editor.** Storyline courses import onto the slide canvas (the Scenes editor), one lesson per scene. **Open in editor** takes you there. 4. **Read the report, then rebuild what is listed.** The report notes how many triggers, variables and states came across, and counts the trigger actions that did not, with why. Rebuild the ones the course actually needs. ### Why Storyline cannot open its own output Storyline publishes a player plus data, not a project. There is no menu in Storyline that turns a published folder back into a .story, and Articulate's own recovery options (temporary files on the author's machine, cloud backups) only help if they still exist on the machine that built the course. So the usual answers are: find the .story, rebuild from screenshots, or embed the old output as a web object and live with it. The published data is much richer than it looks, though. That is what the importer reads. ### Where the content actually is A modern Storyline publish keeps everything in `html5/data/js/`: `data.js` lists scenes, slides and media, and each slide has its own file describing its layers and objects. There are no per-slide HTML pages to scrape — `story_content/blank.html` is an empty stub — which is why generic tools that read HTML find almost nothing. The words on screen live in `paths.js`. Despite the name it is not glyph outlines: every line of text is kept as real characters in SVG text runs, linked from each object. Following that link recovers the typography a learner actually saw — headings, paragraph breaks, bullet text — rather than the shorter accessibility description. ### Recovering text Storyline scrambled Storyline embeds only the letters each font needs ("subsetting"), and in doing so it moves some characters to private codes in Unicode's Private Use Area. The code for "f" in one course might be the code for the "ffi" ligature or an emoji in another font in the same course. Read naively, words arrive with holes: "Studienfach" becomes "Studienach", "Unofficial" loses its middle. The importer works out the mapping for each publish, font by font, by lining up each scrambled run against the same object's accessible text, and only trusts the mapping once it can rebuild the text exactly. If a few characters still have nothing to decode them against, they are counted in the report as **Characters in a subsetted font** so you can check those headings. ### What comes across - Every scene as a lesson, every slide with its size and every object in place: text, shapes, pictures, audio and video. - Layers, with whether each starts visible. - Alt text the author wrote, on the object it belongs to. - Graded questions with their answer keys: multiple choice, multiple response, true/false, word bank, text entry, numeric (exact value), matching (drag-and-drop or drop-down), sequence and hotspot. Hotspot and drag questions are rebuilt so they need no dragging and work by keyboard. Where the author wrote feedback on layers, that text is used. - **Slide draws (question banks).** When a scene drew some of a bank's slides at random, those slides come across as a bank that shows as many per attempt, keeps the same draw when a learner resumes, and redraws on a new attempt. - The pass mark from the results slide, when there is one agreed mark. - Closed captions as WebVTT tracks on their videos, with the words also kept as a transcript. ### Triggers, variables and states Storyline publishes every trigger in the slide data, next to the objects, and the importer rebuilds them as Scenes triggers that run in the preview and in the exported SCORM package: - **Jumps** to another slide, the next or previous slide, or into a lightbox. - **Layers** shown and hidden, including Storyline's default of hiding the other layers. - **Objects** shown and hidden; an object that only a trigger shows starts hidden. - **Variables** set, added to and toggled, with the course's own variables and their starting values. Storyline's built-in ones (review mode, last slide viewed and the rest) are left behind. - **Conditions:** AND becomes "all of", OR becomes "any of", and an Else becomes a second trigger with the opposite condition. - **Object states** that triggers switch to or test, by name and with their text. - **Media** played and paused, and links opened. A clickable shape with no words or picture of its own comes across as a hotspot, so its trigger has somewhere to live. ### What does not come across A trigger that would run differently here is left out and counted in the report, never approximated: - **Execute JavaScript**, **motion paths** and animation triggers. - Conditions on object properties (on stage, a quiz score), on Storyline's built-in Selected, Visited or Disabled states, or that mix AND with OR. - Hover triggers that restore on mouse leave, cues on a layer's own timeline, drag-and-drop, key-press and collision events. - Anything reading a variable that something left out — JavaScript, a text field, a slider — would have set; conditions comparing one variable with another; variables set from another value. - Custom behavior on the player's Next and Previous buttons (**Custom Next and Previous button behavior**), and result-slide actions such as submitting, resetting or printing results (**Result-slide actions**). - What states look like: their names and text come across, their colors and pictures do not. - Question types with no equivalent: Likert and essay surveys (their text comes across), numeric ranges, questions whose choices are only pictures, and drag-and-drop questions whose items have no words to choose by. Warning: A course built mostly from JavaScript, motion paths or drag-and-drop — a software simulation, a game — keeps its slides and its simpler triggers. Check the report's trigger lines before you publish it. ### Flash-era Storyline publishes Storyline 1 and 2 publishes made before HTML5 output keep each slide as a Flash movie with no `html5/` folder. Structure and media come across, but the text on the slides exists only as vector artwork inside the Flash files and cannot be read back. The report says **Flash-era package**. If you still have the .story, republishing it as HTML5 and importing that gives a full import. ### If you do have the .story file You can upload a `.story` file too; it is read directly and lands on the slide canvas, but without its triggers — only the HTML5 publish carries those in a form the importer reads. The published-output route is the one tested against real courses (eleven real Storyline publishes, from Storyline 2 in 2015 to Storyline 360 in 2026), so if you can publish the .story to HTML5 first, do. ## Import a published SCORM, AICC, cmi5 or xAPI package URL: https://scormbusters.com/help/import-published-scorm Last updated: 2026-10-07 Which published packages Scormbusters can turn into editable courses — SCORM 1.2/2004, AICC, cmi5, xAPI, Rise 360, Lectora, iSpring, Articulate Studio, Adapt, H5P, Common Cartridge, QTI and Moodle backups — how the zip is handled, the 100 MB limit, and what to try when an import fails. The problem: You have a course as an LMS package — a zip — and no way to edit it. ### Steps 1. **Get the package.** Download the zip you would upload to an LMS. Any of the formats below; the file name and extension do not matter for a `.zip`. 2. **Open the importer.** From the dashboard choose **Import** (or go to `/courses/import`). Accepted: `.zip`, `.imscc`, `.mbz`, `.h5p`, `.pptx`, `.story`, `.cptx`, `.awt` and Scormbusters' own `.opencourse.json`. 3. **Optionally tick Review the content after import.** **Review the content after import** flags dated references and images without alt text on the import report, so the editor's **Import report** panel lists them. Nothing is rewritten. 4. **Import as a new course.** The file is uploaded, read and turned into a new draft course. Nothing is published until you publish it. 5. **Check the report.** Read what could not be recreated, then open the course. See [Reading the import report](https://scormbusters.com/help/reading-the-import-report). ### What the importer does with a package It reads the package as data and rebuilds the course as ordinary lessons of editable blocks — text, headings, images, audio, video, tables and questions — not an embedded copy of the old HTML. Nothing in the package is run. Media files are copied into your library and every block is pointed at the new copy. A `.zip` is identified by what is inside it, not by its name, because almost every tool publishes an ordinary SCORM package. The importer checks for each tool's signature in turn and uses the generic SCORM reader only when nothing more specific matches — otherwise a Rise or Storyline course would import as the player's scaffolding instead of the author's content. ### Standards packages: SCORM, AICC, cmi5 and xAPI - **SCORM 1.2 and SCORM 2004** (any edition). The manifest's organization becomes modules and lessons; each lesson's launch page is followed through framesets and redirects to the page that shows the content, and that page becomes blocks. Questions written in the page's HTML — or scored by its own script — become gradable questions where the right answer can be read. A mastery score becomes the passing score. - **AICC** (course structure files), **cmi5** (`cmi5.xml`) and **xAPI / Tin Can** (`tincan.xml`): read the same way from their own course structure. - A package published to several standards at once is read as SCORM, whose manifest carries the most structure. SCORM 2004 sequencing and navigation rules, prerequisites between lessons and time limits are not recreated: the imported lessons are open, and the report lists the rules that were there. ### Packages from specific authoring tools These are recognized by their content and read with a dedicated reader: - **Adobe Captivate** — see [Import a Captivate course](https://scormbusters.com/help/import-captivate). - **Articulate Storyline** — see [Import a published Storyline course](https://scormbusters.com/help/import-storyline). - **Articulate Rise 360** — web and SCORM exports, including the 2025 format that loads the course from `locales/`. Blocks map to their nearest equivalent; knowledge checks keep their answers. - **Lectora** — published HTML (SCORM, AICC, xAPI or plain), and `.awt` project files or a zipped project folder. Chapter and page structure is kept; tests keep their questions. - **iSpring Suite and iSpring QuizMaker** — the content inside the player's data files, including quiz questions. - **Articulate Studio** (Presenter, Quizmaker, Engage). Presenter '09 packages give up each slide's title, text and notes. Everything Studio compiled into Flash — Quizmaker questions, Engage interactions, Presenter slide visuals and narration — is counted in the report, not converted. See [Articulate Studio end of support](https://scormbusters.com/articulate-studio-end-of-support). - **Adapt and Evolve** — the course JSON, in built or source layout. - **H5P** — `.h5p` files and exported H5P folders, including Course Presentation and Interactive Book. - **IMS Common Cartridge** (`.imscc`, e.g. a Canvas course export) and **QTI 1.2 / 2.x** question packages. - **Moodle course backups** (`.mbz`, Moodle 1.9 to 4.x). A backup can contain learners' accounts, grades and submissions. **User data is never imported** — the report only counts what was there. ### How your zip is normalised People zip a published folder in many ways, and the importer accepts all the common ones: - A **wrapping folder** ("Compress" in Finder or Explorer puts everything inside `MyCourse/`) is removed, however many levels deep, so the package root is where the tool put it. - **`__MACOSX/`**, `.DS_Store`, `Thumbs.db` and `desktop.ini` are ignored. - **Backslash paths** written by some Windows tools are fixed. - **A zip inside a zip** — for example an LMS download that wraps the package — is opened one level down. - A `.mbz` that is really a `.tar.gz` (every Moodle backup since 2.6) is read as one. The same rules apply to all of them: the upload must be 100 MB or smaller, and its contents at most 5,000 files and 500 MB uncompressed, with no single file compressed more than 100 to 1. Each person can run 10 imports in 24 hours. ### What to try when an import fails - **"File too large (max 100MB)".** Remove video from the package and add it after import, or split the course and import the parts. - **"ZIP archive rejected: …".** The archive is over one of the limits above. If it holds more than one course, import them one at a time. - **"Nothing in … could be converted into editable content, so no course was created."** The package was recognized but held nothing the importer can rebuild — typically a course whose content is entirely Flash, or a manifest whose pages are missing. The message says what was found. - **"Failed to parse file".** The file is damaged, is not what its extension says, or is a format the importer does not know. Re-download it from the LMS or authoring tool; try the original publish rather than a re-zipped copy. - **"Import limit reached. Try again tomorrow."** The 10-per-day limit. - **The course imported but looks thin.** Open the report: content that lives in Flash, in embedded pages, or on a web address outside the package is listed there. Check the package really contains the content — some LMS exports hold only a launch link. Before paying for anything, you can run the [free accessibility scan](https://scormbusters.com/scan) on the package: it uses the same readers and shows what the importer would see. ## Reading the import report URL: https://scormbusters.com/help/reading-the-import-report Last updated: 2026-10-07 Every part of the screen you see after an import — the counts, 'things need rebuilding by hand', 'Worth knowing', the accessibility fixes, problems during the import and error messages — what each means and what to do next. ### Why there is a report An importer that quietly drops what it cannot handle teaches you not to trust it. So every reader counts what it could not bring across and says why, and you see that before you open the course — not on slide 9 in front of a learner. The report has two lists with different meanings. **Things need rebuilding by hand** is loss: something in the source that is not in the new course. **Worth knowing** is not loss: something that came across in a different form, or a decision the importer made that you might want to revisit. ### The summary line - **Imported** and the course title, then **N lessons** — or **N slides, N objects in the Scenes editor** when the course came in on the slide canvas (Storyline, a Captivate .cptx, a Classic Captivate publish whose actions keep state, or an all-new one whose slides are also all free-positioned) — and **N media files**: the images, audio, video and caption files copied into your media library. - **Open in editor** opens the right editor for the course; **Preview as a learner** opens it as a learner sees it. - **Download SCORM 1.2** (block courses) or **Export from the Scenes editor** (slide courses) gets a package straight away. - For a slide-canvas import, **N accessibility fixes before every learner can use it**, counted rule by rule, with **Fix accessibility now**. See [Accessibility triage after an import](https://scormbusters.com/help/accessibility-triage). ### "N things need rebuilding by hand" Each line reads **count × feature**, with a sentence saying why and what to do. The count is how many were affected (for Flash content, how many Flash files). The common ones, by kind: - **Interactivity:** from Captivate (Classic, or an all-new publish on the slide canvas), the actions that could not run the same way here — Execute JavaScript actions, Apply Effect actions, actions that depend on the timeline pausing and the rest, each saying why — or, for a course that reflowed, Buttons and click interactions; Actions and variables (Lectora); Evolve triggers and variables; and, from Storyline, the trigger actions that could not run the same way here — Execute JavaScript triggers, Motion paths and animation triggers, Conditions mixing AND with OR, Hover triggers that restore on mouse leave and the rest, each saying why. Rebuild what the course needs, with the slide editor's triggers or the lesson editor's adaptive paths. Storyline's triggers, variables and states that did come across are noted, with counts. - **Questions that could not become gradable questions:** Questions without a readable answer key; Survey and Likert questions; Numeric questions with a range; Questions with picture choices; Drag-and-drop questions with pictures or unnamed shapes; Hotspot questions; Scored clicks and buttons. Their text is kept; turn it into a question block. - **Content that was never in the package:** Missing media files; Files missing from the package or backup; Lessons hosted outside the package; Images still hosted by Articulate or by the LMS. Upload the file again where the lesson shows it missing. - **Content that cannot run in a browser any more:** Flash and plug-in content; Slides and narration (Flash); Quiz questions, answer keys and feedback (Flash); Interaction steps and media (Flash). - **Things embedded from elsewhere:** Embedded pages; Web objects; Widgets; Embedded HTML and documents; Documents launched as lessons. Add them back as an embed or a file if still needed. - **Course rules:** Sequencing and navigation rules; Lesson prerequisites; Time limits. The imported lessons are open; set completion rules in course settings. - **Form fields and text entry** outside questions, **Caption tracks** to re-attach, and **Characters in a subsetted font** (a few Storyline glyphs that could not be decoded — check headings for missing letters). ### "Worth knowing" These are not losses. The ones you will see most: - **Slides converted to lessons** / **Pages converted to lessons** — the course reflows now; timing and slide layouts were not kept. - **Graded questions with answer keys** — how many questions came across gradable, by type. - **Hotspot questions rebuilt as choices**, **Drag and drop rebuilt as matching / categorize questions**, **Click-to-reveal buttons rebuilt as accordion sections**, **Sorting activities** imported as matching — a different control, the same learning, and none of them need a mouse. - **Random question draws**, **Question pools** — the draw was kept: see [question pools](https://scormbusters.com/help/export-to-lms#question-pools-and-slide-draws). - **Result slide pass marks differ**, **Mastery scores differ**, **Tests with different pass marks** — the source had several pass marks; Scormbusters has one per course, so none was set. Set it in course settings. - **Images without alt text** and **Hotspot areas without names** — the accessibility checker lists them to fix. - **Repeated headers and logos left out**, **Empty slides left out**, **Template placeholder text left out**, **Quiz results slides** left out — clutter removed on purpose. - **Closed captions kept as transcripts**, **Video captions**, **Narration clips**. - **Launch pages followed to their content**, **Other organizations in the manifest**, **Lessons hidden from the menu** — how the importer found the content. - **Media files that could not be uploaded** — those blocks show a missing image until the file is replaced. ### "Problems during the import" These are problems saving the course, not reading it — for example an asset upload that failed, or a module, lesson, slide or set of blocks that could not be written. The rest of the course was saved. If you see many, delete the draft course and import again; if they repeat, tell support with the message text. **Content review could not run** means the course imported fine but the optional content review (Review the content after import) did not complete. ### When no course is created If the package was recognized but nothing in it could become editable content, no empty course is created. Instead you get "Nothing in … could be converted" followed by the report's reasons — typically a Flash-only course. See [What to try when an import fails](https://scormbusters.com/help/import-published-scorm#what-to-try-when-an-import-fails) for the other messages. ### What to do next 1. Fix the **need rebuilding by hand** items the course actually needs — many old triggers only drove the player's own Next button, which the new course does not need. 2. Set the passing score if the report says the source had several. 3. Run the [accessibility checks](https://scormbusters.com/help/accessibility-checker) — or, for a slide-canvas import, [Fix accessibility now](https://scormbusters.com/help/accessibility-triage): imported images often have alt text that is only a file name. 4. Preview, then [export to your LMS](https://scormbusters.com/help/export-to-lms). ## Export a course to your LMS (SCORM 1.2, SCORM 2004, cmi5, xAPI) URL: https://scormbusters.com/help/export-to-lms Last updated: 2026-10-07 How to export a SCORM 1.2, SCORM 2004, cmi5 or xAPI package, which to choose, how to upload it to Moodle and SCORM Cloud, how question pools behave in an LMS, and how resume data is kept inside SCORM 1.2's 4,096-character limit. ### Steps 1. **Test it first.** In the course editor open **Export** and choose **Test in a SCORM player**. It runs the exported package against a built-in SCORM inspector, so you see what the LMS will see without uploading anything. 2. **Pick a language.** If the course has translations, choose the language in the **Language** list of the Export menu — or **All translated languages in one package** for a single package with a language picker (see [Translate a course](https://scormbusters.com/help/translate-course)). 3. **Choose the format.** **SCORM 1.2 package**, **SCORM 2004 package**, **cmi5 package** or **xAPI (Tin Can) package**. A zip downloads. 4. **Upload the zip to your LMS.** Upload the zip as it is — do not unzip it. Steps for Moodle and SCORM Cloud are below. 5. **Launch it once, then relaunch.** Check that completion and score arrive in the LMS, then leave partway through and relaunch to check the learner resumes where they left off. ### Which format to choose - **SCORM 1.2** — the one every LMS accepts. Choose it unless you have a reason not to. It has a single status field (passed, failed, completed, incomplete) and a score. - **SCORM 2004** (3rd Edition) — reports completion and success separately and a scaled score. Choose it if your LMS or reporting needs that split. - **cmi5** — the modern xAPI-based successor to SCORM. Only for an LMS that supports cmi5 and has a learning record store behind it. - **xAPI (Tin Can)** — the classic Tin Can launch, for an LMS that launches xAPI packages with an endpoint and credentials. Also in the Export menu: **Project export**, a `.opencourse.zip` of the whole course and its media that you can re-import or keep in version control. SCORM, cmi5 and xAPI packages are for delivery; the project export is what keeps the course editable if you ever leave. If you would rather not upload packages at all, [LTI 1.3](https://scormbusters.com/help/lti-setup) launches the course from your LMS while it stays hosted in Scormbusters. ### Courses built on the slide canvas Courses in the Scenes (slide) editor — including imported Storyline courses — export from the editor's **Export** menu: **SCORM 1.2**, **SCORM 2004**, **cmi5** or **xAPI (Tin Can)**. Before it exports, [preflight](https://scormbusters.com/help/preflight) runs: if anything in the course will definitely not work in an LMS, such as a trigger pointing at a deleted slide or a question with no correct answer, the export stops and the problems are listed so you can fix them. Accessibility problems do not stop it: if they are all that is left you can **Export with N known issues**, and the audit log records it (see [Accessibility triage](https://scormbusters.com/help/accessibility-triage)). ### Uploading to Moodle SCORM 1.2 verified on Moodle 4.5 (17 September 2026), including resume after a relaunch. The SCORM 2004 probe also passed there, but Moodle documents its native SCORM 2004 support as incomplete, so prefer SCORM 1.2 for Moodle. 1. In your Moodle course, turn editing on. 2. **Add an activity or resource** → **SCORM package**. 3. Give it a name and drop the exported zip into **Package file**. 4. Save and display, then launch it. Moodle reopens a completed attempt in review mode on relaunch, which is correct. A learner who leaves partway gets their progress back. ### Uploading to SCORM Cloud SCORM Cloud is Rustici's reference implementation, and a good neutral check before you blame an LMS. SCORM 1.2 export verified there on 17 September 2026: status, score, interactions and resume after a full relaunch all passed. Import the zip into your SCORM Cloud library, launch it, then relaunch to confirm resume. ### Other LMSs Canvas, Blackboard, Cornerstone, TalentLMS, Docebo and others have not been verified yet — not because anything is known to fail, but because nobody has run the check and recorded the result. Upload the zip wherever your LMS accepts a SCORM package. (In Canvas, SCORM support depends on the SCORM integration your institution has installed; if it has none, LTI 1.3 is the alternative.) Two behaviors of real LMSs are already handled: some open the SCORM session before the course does and report it as an error, and some report a returning learner's entry mode as empty rather than "resume". The package checks whether the session works and restores progress from its own saved data, so neither sends learners back to the start. ### Question pools and slide draws A lesson can show each learner only some of its questions: in the lesson editor, the pool control (**All questions** / **Draw N of M**) sets **Questions per attempt**. Imported question banks from Captivate and Storyline arrive with this already set. In an exported package the draw is made once per attempt and saved with the learner's progress, so a learner who resumes sees the same questions, and a new attempt draws again. The score counts only the questions that were drawn. Storyline slide draws on the slide canvas behave the same way, drawing slides instead of questions. ### Resume data and the suspend_data limit SCORM 1.2 guarantees only 4,096 characters of `cmi.suspend_data`, the field an LMS keeps for resuming, and many LMSs enforce exactly that. When a course writes more, the LMS usually truncates it silently, the saved data no longer parses, and the learner starts again from nothing. It is one of the most common reasons a SCORM course "does not resume". Scormbusters packages keep their resume data under 3,800 characters in both SCORM versions. A multi-language package also saves the learner's chosen language there (a few characters, never dropped). On the slide canvas, where more state is saved, the package sheds the least important state first — object appearance, then layers and visited slides, then variables — and always keeps completed lessons, the score and question-pool draws. cmi5 and xAPI packages do not use suspend_data; they save progress to the learning record store as an xAPI State document, with the learner's browser as a fallback when the LRS cannot be reached. ## Translate a course and ship every language in one package URL: https://scormbusters.com/help/translate-course Last updated: 2026-10-08 Add languages to a course, translate them in Scormbusters, with a translation vendor over XLIFF or with your own AI assistant, then export one SCORM or xAPI package that carries every language, with a learner language picker and progress that survives switching. The problem: One package per language means several LMS entries per course, and a learner's record split across them. ### Steps 1. **Add the languages.** In the course editor, open **More → Translations** and use **Add Locale** for each language. 2. **Translate.** Type translations in the table, or use **XLIFF** to download a file for a translation vendor and **Import** to load the finished file back. An AI assistant connected over MCP can fill them in for your review. 3. **Export every language at once.** In the **Export** menu set **Language** to **All translated languages in one package**, check which translations go in, then choose the format. 4. **Upload one zip.** Upload the package to your LMS as one course. Learners choose their language when they start and can change it at any time. ### What gets translated The course title and description, lesson and module titles, and the words in every block: text, headings, captions, alt text, question wording, options and feedback, flashcards, tabs and the rest. For a custom interaction, its title and text alternative are translated; its code is not, so text inside the interaction itself stays as written. Numbers, links, media files, answer keys and fill-in-the-blank answers stay as authored. A fill-in-the-blank sentence whose translation adds or loses a `[blank]` keeps the original wording, because its answers would no longer line up. The package's own controls (Next, Previous, Check, the language picker's heading and its Continue button) are in English in every language. Each language's name in the picker is written in that language. ### Choosing which languages go in With **All translated languages in one package** selected, the Export menu lists each translation with its status. Complete translations are checked. An incomplete one shows how many strings are missing and lists them under **Missing strings**. You can still check it, and its missing strings then show in the course's own language. The course's own language is always included and is the default. Over MCP, `export_course` takes `languages: ["all"]` for every complete translation, or a list such as `["fr", "de"]`. Its result names anything left out or incomplete. This is for block courses. Courses on the slide canvas (Scenes) have no translations yet, so they export in the language they were authored in. ### What the learner sees Before the first lesson, the package asks for a language. The option already chosen is the learner's language preference from the LMS if the package has it, otherwise the browser's language, otherwise the course's own. The preference comes from `cmi.student_preference.language` in SCORM 1.2, `cmi.learner_preference.language` in SCORM 2004 and the cmi5 learner preferences profile. A Tin Can launch has no such field, so the browser decides. A **Language** button in the sidebar opens the same choice at any time, and the current lesson reloads in the new language. The page's language and text direction change with it, so screen readers switch voice and Arabic, Hebrew, Persian or Urdu read right to left. The picker works with a keyboard: arrow keys move between languages, Tab reaches **Continue**, and Escape cancels a change made from the sidebar. A returning learner is not asked again: the choice is saved with their progress. ### Tracking does not depend on the language Every language is the same course to the LMS: one item in the manifest, the same lesson positions, the same question ids and the same grading. A learner who switches language halfway keeps their completed lessons and their score, and questions they already answered still count. The question shows unanswered in the new language, and answering it again cannot add a second point. Interaction reports in the LMS use the same ids whatever language the question was answered in. The chosen language is saved with the rest of the resume data: in `cmi.suspend_data` for SCORM (inside the same 3,800-character budget, and kept when other state has to be trimmed) and in the xAPI state document for cmi5 and Tin Can. ### Package size Images, video and audio are stored once and shared by every language. Each extra language adds only its lesson pages, which are text. After a multi-language export the Export menu shows the package's size and how many languages it carries. ## The accessibility checks, mapped to WCAG 2.1 AA URL: https://scormbusters.com/help/accessibility-checker Last updated: 2026-10-07 Every accessibility check Scormbusters runs — in the lesson editor, the slide editor, preflight and the free scan — with the WCAG 2.1 success criterion each one maps to, what it cannot check, and the ADA Title II and HHS Section 504 deadlines. ### Where the checks run - **Lesson editor:** a warning button with a count appears in the bottom-left corner whenever a lesson has something to fix. Expand it for the list (**Accessibility (N issues)**) and use **Jump to block**. - **Slide editor (Scenes):** the **Accessibility** panel checks the current slide; [preflight](https://scormbusters.com/help/preflight) runs its accessibility rules over the whole course as you work; **Alt text triage** walks through every image, video and hotspot whose description is missing or meaningless, grouping identical ones so you can describe them once. - **Before you have an account:** the [free scan](https://scormbusters.com/scan) reads a published course zip or URL and reports the same kinds of problem, plus a transcript of what a screen reader would announce. ### What is checked, criterion by criterion - **1.1.1 Non-text Content** — images with no alt text; alt text that is only a file name or a default shape name ("Picture 3", "Yellow-BG.png", "image"); hotspot pictures with no description. An image with deliberately empty alt text is treated as decorative and not flagged. - **1.2.2 Captions (Prerecorded)** — videos with no caption track (and, in the scan, audio and video items without one). - **1.3.1 Info and Relationships** — (scan) subheadings that appear before any heading in their lesson. - **1.4.3 Contrast (Minimum)** — text against its background below 4.5:1, or 3:1 for large text (24px, or about 18.7px bold), computed from the actual colors. - **2.1.1 Keyboard** — a slide object that responds to clicks but is set not to take focus, so a keyboard can never reach it; (scan) buttons and hotspots with no action. - **2.4.3 Focus Order** — two controls on a slide claiming the same tab position, or gaps in the tab order. - **2.4.6 Headings and Labels / 4.1.2 Name, Role, Value** — buttons, hotspots and question groups with no name a screen reader can announce; hotspot-question areas named only "Area 2", which leave a learner who cannot see the picture choosing blind. - **3.1.1 Language of Page** — (scan) a course that does not declare its language. The lesson editor also warns about a multiple-choice question with fewer than two options, which cannot be answered by anyone. ### What is built in rather than checked Some criteria are met by how the player works rather than by a check: matching, sequence, hotspot and categorize questions can be answered without dragging, by keyboard and by a single tap (2.1.1, and WCAG 2.2's 2.5.7); right and wrong answers are marked in words, not color alone (1.4.1); focus is visible in exported packages (2.4.7); the course language is declared in the export (3.1.1); and reduced-motion preferences are respected. ### What automated checks cannot tell you No checker can decide whether alt text is a good description, whether captions are accurate, whether reading order makes sense, or whether a course is understandable. Passing every check here means the mechanical problems are gone, not that the course conforms to WCAG 2.1 AA. Test with a screen reader and a keyboard, and for formal conformance get a manual audit. Scormbusters has not yet published a third-party-audited conformance report for its own output. ### The deadlines: ADA Title II and HHS Section 504 Two US rules name WCAG 2.1 AA as the standard for web content, which includes online courses: - **ADA Title II** (state and local governments, including public colleges and school districts): **April 26, 2027** for entities serving a population of 50,000 or more, and **April 26, 2028** for smaller ones and special districts. These are the dates after the Department of Justice's interim final rule of April 20, 2026, which pushed back the original ones ([Federal Register](https://www.federalregister.gov/documents/2026/04/20/2026-07663/extension-of-compliance-dates-for-nondiscrimination-on-the-basis-of-disability-accessibility-of-web)). - **HHS Section 504** (recipients of HHS funding): **May 11, 2027** for recipients with 15 or more employees and **May 10, 2028** for those with fewer, after HHS's interim final rule of May 2026 ([Federal Register](https://www.federalregister.gov/documents/2026/05/11/2026-09266/extension-of-compliance-dates-for-nondiscrimination-on-the-basis-of-disability-accessibility-of-web)). Dates have moved before and may move again; check the rule that applies to you. Warning: This is general information, not legal advice. Whether and how these rules apply to your organization and your courses is a question for your counsel. ## What is Scormbusters? URL: https://scormbusters.com/help/overview Last updated: 2026-10-07 What Scormbusters does, how courses are structured (course, module, lesson, block), and how building and taking a course fit together. ### Authoring and delivery in one place Scormbusters is a browser-based tool for building eLearning courses and delivering them to learners. Most teams run a separate authoring tool (such as Articulate Rise or Adobe Captivate) alongside a separate learning management system. In Scormbusters you build, publish, enroll learners and see their results in the same workspace. Because authoring and delivery share one database, a learner's quiz score on one lesson can decide which lesson they see next (see [Branching with the Adaptive editor](https://scormbusters.com/help/flow-editor)), and results are recorded against the same lessons you edit. Tip: Moving from another tool? Click **Import** on the Courses dashboard to bring in a published SCORM package or a source file. See [Importing a published SCORM package](https://scormbusters.com/help/import-published-scorm). ### Core concepts Everything lives inside an organization (org). Your org is created when you sign up and holds your team, courses and settings. Team members belong to the org with a role (see [Invite your team](https://scormbusters.com/help/invite-team)). A **course** contains **modules**, which group **lessons**. A lesson is built from **blocks**: text, media, interactive and question blocks stacked in order. Progress and scores are recorded per lesson and rolled up to the course. Courses imported from slide-based tools (Storyline, and Captivate courses whose actions keep state) are edited in **Scenes**, a slide editor where content is laid out on a canvas rather than stacked; see [The Scenes editor](https://scormbusters.com/help/scenes-editor). ### Building and taking a course Authors work in the course editor, opened from the Courses dashboard. Learners take courses from **My Learning** (`/my-learning`), which lists the courses they are enrolled in, and the course player at `/learn`. A course that is not published cannot be opened by learners, even if they are enrolled. Warning: Publishing is a switch, not a snapshot. Once a course is published, the edits you save reach learners the next time they load a lesson. Make large changes in a copy, or unpublish while you work. ### When you still need an LMS If your organization already has an LMS, you can export a course as a SCORM package or connect through LTI instead of moving learners. See [Exporting to an LMS](https://scormbusters.com/help/export-to-lms) and [LTI setup](https://scormbusters.com/help/lti-setup). ## Create Your First Course URL: https://scormbusters.com/help/create-first-course Last updated: 2026-10-07 Step by step: create a course, add modules and lessons, build a lesson from blocks, preview it, publish it and enroll learners. ### Starting from the dashboard After logging in you land on the **Courses** dashboard. Click **New course**, type a **Course name**, choose **Blank** under **Start from** (or a template; see [Start a course](https://scormbusters.com/help/course-templates)) and click **Create course**. A blank course has one module ("Module 1") containing one lesson ("Lesson 1"), and opens in the course editor. Click the course title at the top of the sidebar to rename it. Tip: To start from existing content instead, click **Import** next to New course. See [Importing a published SCORM package](https://scormbusters.com/help/import-published-scorm). ### Modules and lessons The left sidebar shows your course outline. Click **Add Module** at the bottom of the sidebar to add a module, and the **+** that appears when you hover a module (**Add lesson**) to add a lesson to it. To rename a module or lesson, right-click it and choose **Rename**, then press Enter; the same menu has **Duplicate** and **Delete**. On a lesson, Shift+F10 opens the menu from the keyboard. Drag lessons to reorder them or to move them into another module. ### Building a lesson with blocks Click a lesson in the sidebar to open it. In an empty lesson, pick a block type to get started. To add more, use the **+** between blocks (or **Add block** at the end) to open the block picker, where you can type to search by name. Press **Cmd+K** (Ctrl+K on Windows) to search blocks from the keyboard; the block you pick is added at the end of the lesson. Each block's settings are edited inline in the block itself. Hover a block for its toolbar: drag to reorder, move up or down, duplicate, or delete. Press **?** (outside a text field) for the keyboard shortcuts. **Cmd+Z** and **Cmd+Shift+Z** undo and redo outside a text field, **Cmd+D** duplicates the block you are working in, and **Cmd+S** saves straight away — saving is otherwise automatic a moment after you stop typing. Use Ctrl in place of Cmd on Windows. A typical lesson might open with a Heading, continue with Paragraphs and an Image or Video, and finish with a Multiple Choice question. See the [Block types reference](https://scormbusters.com/help/block-types) for every block. ### Previewing your course Click **Preview** in the top toolbar to open the course as a learner sees it, with lesson navigation and working quiz blocks. Previewing does not publish anything. To check the package your LMS will get, use **Export → Test in a SCORM player**. ### Publishing and enrolling learners Click **Publish** in the top toolbar and confirm. The course goes live: anyone with its public link can take it, and learners in your organization can find it in the catalog and enroll. Click **Published** again to see the link or to unpublish. See [Publishing and sharing](https://scormbusters.com/help/publish-and-share). To enroll people, open **More → Enrollments**, click **Enroll learners** and enter (or upload as CSV) the email addresses of people who are already members of your org. Enrolled learners see the course on their My Learning page. To enroll someone new, invite them to the org first from **Settings → Team** (the **Viewer** role is for learners). You can also set a due date for an enrollment. Warning: After publishing, your saved edits are visible to learners straight away. There is no separate "republish" step. ## Invite Your Team URL: https://scormbusters.com/help/invite-team Last updated: 2026-09-26 Invite teammates to your Scormbusters org, choose the right role (Owner, Admin, Member, Viewer) and manage pending invitations. ### Sending an invitation Owners and Admins can invite people. Go to **Settings → Team**, and under **Invite teammates** enter the person's email address, choose a role and click **Send Invite**. Scormbusters emails them a link to join your organization, and the link is also shown on screen so you can share it directly. Pending invites are listed with their expiry date. Click **Revoke** to cancel one. Tip: Invitations expire after 7 days. To re-invite someone whose invitation expired, or who never received the email, revoke the old invite and send a new one. ### Understanding roles Scormbusters has four roles: - **Owner**: the person who created the organization. Full access, and the only role that can change other members' roles. - **Admin**: can invite and remove members, manage billing, and configure settings and integrations. Admins can invite Members and Viewers. - **Member**: an author. Can create and edit courses in the org, use the question bank, and view analytics. - **Viewer**: a learner. Takes the courses they are enrolled in; cannot author. Learners are invited with the Viewer role and are not counted as authors. ### Changing a member's role Only the Owner can change roles. In **Settings → Team**, use the role dropdown next to the member and choose Admin, Member or Viewer. The change takes effect immediately; the member sees the new permissions the next time they load a page. The Owner's own role cannot be changed. Owners and Admins can remove a member from the same list. Warning: Changing an Admin to Member immediately removes their access to settings and integration configuration. Make sure they have handed off any setup in progress first. ## Block types reference URL: https://scormbusters.com/help/block-types Last updated: 2026-10-07 Every block in the Scormbusters lesson editor: text, layout, media, interactive and question blocks, what each does and when to use it. ### Text blocks **Heading** adds a section title at level H2, H3 or H4. **Paragraph** is the block for body copy, with a toolbar for bold, italic, underline, links and bulleted and numbered lists. **Callout** is a highlighted box in four styles: info (blue), warning (amber), success (green) and tip (blue, with a lightbulb). **Quote** shows a pull quote with an optional attribution. **Numbered List** is for ordered steps, **Table** for rows and columns of data, **Stat / Numbers** for large figures with labels, and **Citations** for a numbered reference list. ### Layout blocks **Two Column** places two rich-text columns side by side; choose the split ratio in the block. **Cover Slide** is a title panel with a background image or gradient, suited to lesson openers. **Divider** draws a horizontal rule and **Spacer** adds adjustable vertical space. **Button / CTA** is a styled button that links to a URL, for sending learners to a resource outside the course. ### Media blocks **Image** takes an upload, a file from your media library, or a URL. Set alt text, alignment and a caption. **Gallery** shows several images in a grid with a choice of column count and an optional lightbox. **Video** can link a YouTube, Vimeo or direct MP4 URL, upload through your org's streaming provider, upload a file directly, or reuse a file from the library; see [Adding video](https://scormbusters.com/help/video). **Audio** plays an uploaded, library or linked audio file. **Embed** shows another site's content (YouTube, Loom, Figma or any URL) in the lesson. **Text to Speech** reads the text you type into the block aloud using the learner's browser voices, with a play button. It is a convenience for learners, not a replacement for accessible text. ### Interactive blocks **Accordion** collapses content into expandable sections. **Tabs** splits content into tabbed panels. **Flashcard** flips between a front and back, for terms and quick recall without scoring. **Timeline** lays out dated events, and **Process Steps** shows a numbered sequence of steps. **Hotspot** places clickable markers on an image; each opens a title and description. **Labeled Graphic** adds labeled callouts on top of an image. Both have an alt text field for screen readers. **Scenario** is a character dialogue with choices for the learner. **Continue Button** is a pause point: when a learner clicks it, it shows a short message you write (for example, "You may now continue to the next section"). It does not hide the content below it. Tip: For Hotspot and Labeled Graphic, use high-resolution images (at least 1200px wide) so markers land precisely on every screen. ### Custom interaction **Custom interaction** runs your own HTML, CSS and JavaScript in a sandboxed frame inside the lesson, for anything the other blocks don't do. It has no network access, and it can report a score that counts toward the lesson. See [Custom interactions](https://scormbusters.com/help/custom-interactions) for how to build one. ### Question blocks These seven blocks are graded and count toward the lesson score: - **Multiple Choice**: one correct answer, up to six options. For a true/false question, choose **True / False** in the block picker: it adds a Multiple Choice with the options True and False already filled in, True marked correct. - **Multi-Select**: select all that apply. - **Fill in Blank**: learners type the missing words. Each blank can accept several answers, and matching ignores case unless you tick case-sensitive. - **Matching**: pair items from two lists. - **Sortable**: put items in the right order. - **Hotspot Question**: choose the right area of a picture. - **Categorize**: sort items into groups. **Reflection** asks learners to answer in their own words and is not marked. See [Building quizzes and assessments](https://scormbusters.com/help/quiz-blocks) for how scoring works. Tip: In Fill in Blank, add common misspellings as accepted answers so learners who know the concept are not marked wrong for a typo. ## Building Quizzes & Assessments URL: https://scormbusters.com/help/quiz-blocks Last updated: 2026-10-07 How Scormbusters scores quiz blocks, lessons and courses, how passing score and max attempts work, and how to reuse questions from the question bank. ### Choosing the right question block **Multiple Choice** has exactly one correct answer and shows radio buttons. **Multi-Select** has one or more correct answers and shows checkboxes; the learner must select every correct option and nothing else to get it right. **Fill in Blank** tests recall of a specific word or phrase, without distractors to hint at the answer. **Matching** suits terms and definitions. **Sortable** is best where sequence genuinely matters. **Hotspot Question** asks learners to pick an area of an image, and **Categorize** asks them to sort items into groups. Warning: Multi-Select has a "Partial credit" option, but it only changes what the player displays. The recorded score is all-or-nothing: the question is right only when every correct option, and nothing else, is selected. ### How scores are calculated Scores are worked out on the server from the answers learners submit, never from a total their browser reports. A lesson's score is the points earned out of the points available across its question blocks: - Multiple Choice, Multi-Select and Hotspot Question are worth 1 point. - Fill in Blank is worth 1 point per blank, Matching 1 per pair, Sortable 1 per item, and Categorize 1 per item, plus 1 for each group that must hold a set number of items. Learners can click **Try again** on a question; their latest answer is the one that counts. A question left unanswered scores zero. The course score adds up the points earned across all completed lessons and divides by the points available. If it meets the **Passing score** in Course Settings (80% unless you change it), the learner passes. **Max attempts** in Course Settings limits how many times a learner can start the course; leave it blank for unlimited. Tip: A lesson with no question blocks has no score and does not affect the course score. ### Question pools To give each learner a different selection, set a question pool on a lesson (**All questions** in the lesson toolbar, then **Questions per attempt**): each attempt shows every non-question block plus the number of the lesson's question blocks you choose, drawn at random. Put each pool in a lesson of its own, because the draw is taken from all the questions in the lesson. See [Question pools and slide draws](https://scormbusters.com/help/question-pools). ### Feedback on wrong answers Write per-option feedback on question blocks so a learner who answers wrongly learns why — the feedback field sits beside each option in the editor. An AI assistant connected over MCP can draft this feedback for every question in a course in one pass (see [What to ask your AI assistant](https://scormbusters.com/help/ai-workflows)). ### The Question Bank The question bank (**Questions** in the main navigation) is a library of reusable questions shared across your organization. It holds Multiple Choice, Multi-Select, Fill in Blank, Matching, Sortable, Hotspot Question and Categorize questions, with tags, difficulty and Bloom's level. Choose **True / False** as the type for a Multiple Choice question with True and False already filled in. Questions are edited with the same editor used in lessons. To reuse a question, open a lesson that has at least one block and click **Question Bank** at the bottom right of the editor (not shown on phones). Search by keyword or filter by type and difficulty, then insert. Inserting makes a copy: later edits in the bank do not change lessons that already use the question. ## Branching with the Adaptive Editor URL: https://scormbusters.com/help/flow-editor Last updated: 2026-10-07 Route learners to different lessons by score, pass or fail, completed lessons or the answer they chose, using the Adaptive tab: connections, conditions, priorities, the Path Simulator and validation. ### What branching is and when to use it Branching lets different learners take different routes through a course based on how they do. A learner who scores well on a check can skip the remedial lesson; one who struggles is sent to extra practice. It is most useful for onboarding where people arrive with different prior knowledge, and for courses with an optional remedial or advanced track. If everyone should cover the same material in the same order, leave the course linear. ### Turning on adaptive paths In the course editor, click the **Adaptive** tab next to **Outline**. The first time, click **Enable adaptive paths for this course**. You can switch back to linear mode at any time in Course Settings. The canvas shows each lesson as a node, colored by module, and starts with the lessons linked in outline order. The first lesson is marked as the entry and the last as the exit. Scroll to zoom, drag the background to pan, and use the controls and mini-map in the corners to find your way around large flows. **Auto Layout** tidies the arrangement. ### Connections and conditions Drag from one node's handle to another node to connect them. Click a connection, or right-click it and choose **Edit Condition**, to open the condition editor. Untick **Unconditional (always follow)** to make it conditional, then choose a condition type: - **Assessment Score**: the learner's percentage compared with a score you set (0 to 100), for example "≥ 80". - **Assessment Passed**: the learner's percentage is at least the course's **Passing Score** (set in Course Settings, 80% unless you change it). Change the passing score and every Assessment Passed connection follows it. - **Lesson Completed**: the learner has completed the lesson, in this attempt at the course. - **Choice Selected**: the learner's latest answer to a Multiple Choice or Multi-Select question in the lesson chose the option you type. Type the option's text as learners see it; capitals and extra spaces are ignored. Each condition has a **Lesson**. Leave it on **The lesson being left** to test the lesson the learner has just finished, or pick another lesson. Scores are the ones Scormbusters calculated from the learner's recorded answers, never a total sent by the browser. Each connection also has a **Priority** (lower is evaluated first). When a learner finishes a lesson, Scormbusters tries the conditional connections in priority order and follows the first that matches. If none match, it follows an unconditional (Always) connection. For example, from a check lesson add "score ≥ 80" to the advanced lesson with priority 1, "score ≥ 50" to the standard lesson with priority 2, and an Always connection to the remedial lesson as the fallback. Warning: Always give a branching lesson an Always connection as a fallback. A lesson with no questions has no score, so Assessment Score and Assessment Passed connections from it never match. Connections made before 26 September 2026 that use **Variable Value** are not followed by learners (Scormbusters does not keep learners' variable values), so the editor no longer offers that condition: change them to another type. ### Checking your flow Click **Validate** to check for problems: a missing or duplicate entry node, and lessons that nothing connects to, which no learner can reach. Click **Simulate** to open the **Path Simulator**. Pick a persona (Blank Learner, High Performer or Struggling Learner), enter a score and, for Choice Selected connections, the answer chosen for the current lesson, then step through to see which route is taken. Try the boundary cases, such as exactly your passing score, one point below it, and 0, for every branching lesson. Tip: The simulator routes by the same rules as the learner player, using the course's passing score for Assessment Passed. ### Variables and follow actions Adaptive paths route learners by score, pass, completion and chosen answer only; Scormbusters does not keep learner variables. Earlier versions of the editor had a **Variables** panel and an **Action on Follow** setting on connections. They have been removed because the Scormbusters web player never applied them. A course that still has them keeps them: the web player ignores them, exported SCORM packages still apply them, and the editor shows a note saying so. Rebuild that routing with score, completion or answer conditions so both behave the same. ### How branching affects learners Learners never see the diagram; they just move from lesson to lesson. The course is complete when a learner reaches a lesson with no onward connection, so every route should end at a lesson that has none. A learner does not have to visit every lesson to finish. Right-click a node to **Set as Entry (Start)**, **Set as Exit (End)** or **Remove from Flow**. ## Adding Video to Your Course URL: https://scormbusters.com/help/video Last updated: 2026-10-07 Add video to a Scormbusters lesson: link YouTube or Vimeo, upload through Cloudflare Stream or Mux, upload a file directly, and add captions. ### Inserting a video block Open a lesson, click **+** to open the block picker and choose **Video**. The block has four tabs: - **URL / Embed**: paste a YouTube, Vimeo or direct MP4 link. - **Upload Video**: upload through your organization's streaming provider (Cloudflare Stream or Mux). - **File**: upload an MP4, MOV or WebM file (up to 50 MB) that is stored and played as-is. - **Library**: reuse a video already in your media library. To change the video later, remove it with the **✕** on the player and choose again. ### Uploading through a streaming provider On the **Upload Video** tab, choose a file. A progress bar shows the upload, then the block shows "Processing video…" while the provider prepares it. The block checks for readiness automatically; you do not need to refresh. Scormbusters does not resell video delivery. An Owner or Admin connects your organization's own Cloudflare Stream or Mux account in **Settings → Video**, and the provider bills you directly. On the hosted service, uploading through this tab needs a connected provider. On-premises Enterprise installs can fall back to the operator's own storage. Tip: For large or frequently watched videos, prefer a streaming provider over the **File** tab: the provider handles transcoding and delivery. ### Linking YouTube or Vimeo On the **URL / Embed** tab, paste the video's URL. Scormbusters recognizes YouTube and Vimeo links and shows their player. Linked videos play from the hosting service, so they are subject to its availability and privacy settings; a video that is deleted or made private there will stop working in your lesson. ### Captions Click **Add captions (VTT)** on the video block and paste WebVTT captions — from your captioning tool, or ask your AI assistant to time a transcript into WebVTT and paste the result (see [Connect your AI assistant](https://scormbusters.com/help/ai-features)). The captions are saved with the block, shown in the player for uploaded and direct-file videos, and shipped in every export. YouTube and Vimeo play in their own player, so use their captions. ## Connect Your AI Assistant URL: https://scormbusters.com/help/ai-features Last updated: 2026-10-07 Scormbusters has no built-in AI and no AI fees. Connect the assistant you already use — Claude, ChatGPT, Claude Code or any MCP client — over OAuth or a personal token, and it works on your courses, on your own subscription. ### How AI works in Scormbusters Scormbusters never makes an AI call and never stores a model key. Instead, it is an **MCP server**: your own AI assistant connects to it and works on your courses through documented tools — reading and writing lessons and blocks, editing Scenes slides and objects, looking at a slide's pictures to describe them, building branching, running accessibility audits, handling review feedback, importing and exporting packages. That means the AI you use is the one you already pay for (a Claude or ChatGPT subscription, a Claude Code seat, or a model running on your own hardware through any MCP client), the conversation happens in that assistant's own app where you approve every change, and Scormbusters never bills you for AI — there are no credits, no allowance, and nothing that expires. Tip: Your organization's content is only ever sent where **you** send it: the assistant acts with your login, sees what your role can see, and can be revoked at any time. ### Connect from Claude (web or desktop) 1. In Scormbusters, open **Settings → AI assistant** (the page is headed **Connect your assistant**) and copy your **MCP server URL**. 2. In Claude, open **Customize → Connectors**, select **+ Add**, then **Add custom connector**. Name it Scormbusters, paste the address, and keep the recommended sign-in option. 3. Sign in to Scormbusters when asked and approve the connection. The approval page says what it may do: read or author courses, matching your role; it cannot delete courses, manage members or change billing. 4. Try *"List my courses."* ### Connect from Claude Code, ChatGPT and other clients **Claude Code**: run `claude mcp add --transport http scormbusters `, then type `/mcp`, choose scormbusters and sign in. The settings page shows the command with your address filled in, as well as the commands for Codex CLI and Gemini CLI. **ChatGPT**: add Scormbusters as a custom MCP server with the same address and choose OAuth sign-in (your plan or workspace may not allow custom MCP servers). **Cursor and VS Code**: the settings page has one-click install buttons. The Model Context Protocol is an open standard, so any compliant client works; setup for each one is in the [MCP reference](https://scormbusters.com/docs/mcp). ### Apps that cannot sign in: personal tokens Some apps — open-model front ends such as LM Studio or Open WebUI, scripts, older clients — cannot do the OAuth sign-in. Give them a personal token instead: 1. Open **Settings → API**, section **Personal tokens — connect an AI assistant**. 2. Give the token a **Name**, choose when it **Expires in** (30 days to 1 year; 90 days by default), and tick **Read-only** if the assistant should only look. 3. **Create token**, and copy it at once — it is not shown again. 4. Configure the app to send `Authorization: Bearer oc_pat_…` to your MCP server URL. Any member can create personal tokens for themselves. A personal token works with the MCP server only; the REST API takes organization API keys (see [API keys and webhooks](https://scormbusters.com/help/api-keys)). ### What it may do, and revoking it The assistant acts **as you**: a Viewer's assistant can only read, an Owner's, Admin's or Member's can write content, and nothing it does bypasses your organization's permissions. Changes it makes are recorded in the audit log. Every OAuth connection is listed in **Settings → Connected apps** with what it may do and when it was last used; **Revoke** cuts it off at once. Owners and Admins see every connection in the organization. Personal tokens are revoked from **Settings → API**. The full tool reference, with example conversations, is at [/docs/mcp](https://scormbusters.com/docs/mcp). Warning: Review what your assistant writes the way you would review a colleague's draft. It edits real course content; version history (see [Version history and compare](https://scormbusters.com/help/version-history)) and undo are there if you want to roll something back. ## What to Ask Your AI Assistant URL: https://scormbusters.com/help/ai-workflows Last updated: 2026-10-07 Working recipes for an AI assistant connected over MCP: modernize an imported course, draft quizzes from lesson content, write alt text, translate, audit accessibility and export. ### Modernize an imported course After a legacy import, the report lists what did not come across and — if you ticked **Review the content after import** — dated references and images without descriptions. Ask your assistant: *"Open the course I just imported, read each lesson, and rewrite any paragraph over 200 words for readability. Keep the meaning, keep the terminology, and tell me what you changed in each lesson."* Because the work happens in your chat, you review each rewrite before moving on — nothing lands silently. ### Draft knowledge checks *"Read lesson 3 of my Safety Onboarding course and draft two multiple-choice questions that test its key points. Make the distractors plausible mistakes, not jokes, and add per-option feedback explaining why each wrong answer is wrong."* The assistant writes real question blocks with answer keys; you adjust wording and placement in the editor. ### Write alt text that actually describes the image *"List every image in this course that has no alt text, look at each one, and propose a description that serves its teaching purpose — not just what it looks like. Put your proposals in a list for me to approve before writing any of them."* For diagrams and screenshots, tell it what the learner is supposed to take from the image; that context produces far better descriptions than the picture alone. Tip: On a Scenes course the assistant can look at a slide's pictures itself (the view_scene_images tool), so it describes what is actually there. On a block course, the import's content review flags images that arrived without descriptions, so the list is already on the **Import report** panel. ### Translate a course *"Build a Spanish version of my Forklift Refresher course as a new course: same modules, lessons and blocks, all text translated, quiz logic and media unchanged, question feedback translated too. Flag anything you were unsure about."* The assistant reads the course and builds the new one block by block (there is no one-step copy over MCP). For vendor workflows, Scormbusters also exports and re-imports XLIFF per locale under **More → Translations** in the course editor — use that when a human translation agency is involved. ### Audit and fix accessibility *"Run an accessibility audit on this course, then fix what can be fixed mechanically — heading order, missing names — and give me a list of what needs a human decision, with your recommendation for each."* The audit_course tool runs the same checks as the editor's checker, so the assistant's list matches what you would see in the app. ### Export and hand off *"Export this course as SCORM 2004 and give me the download link."* For a course you imported from an LMS package and want to upload over the old one: *"Export this as a replacement for the original in our LMS."* The assistant uses the same **Replace the original in your LMS** option as the export menu, in the format the original was published in; it refuses a format the original never had (for example cmi5 for a SCORM original) and passes on the same warnings — a changed SCORM version, an original in several parts. Try the replacement in a test copy of the course first. The assistant can also build a course end to end from source material you paste into the chat — outline first, then lessons, then questions — with you steering at each step. The build-course prompt in the MCP server walks it through the structure Scormbusters expects. ## Custom Interactions: Your Own Code, Tracked URL: https://scormbusters.com/help/custom-interactions Last updated: 2026-10-08 Run your own HTML, CSS and JavaScript in a lesson, sandboxed, and have it report a score, completion and saved state to Scormbusters and to the LMS through a small postMessage API. The problem: I built an interaction with Claude or ChatGPT and it works in the browser, but the LMS cannot see the score and the learner loses their place when they come back. ### Steps 1. **Add the block.** In the block picker choose Custom Interaction (under Interactive) and give it a title. 2. **Paste your code.** Paste self-contained HTML with inline script and style. A new block starts with a working example. 3. **Call the API.** Use OpenCourse.reportScore, OpenCourse.complete and OpenCourse.saveState where your code knows the result. 4. **Set points and preview.** Set Points if it should score, then click Run preview to try it in the editor. ### What the block does A **Custom Interaction** runs your own code in a lesson and tracks it like a built-in question. It can report a score that counts toward the lesson and the course pass mark, mark itself complete, save a small state so a returning learner picks up where they left off, and size its frame to its content. The same code behaves the same way in the Scormbusters player and in an exported SCORM 1.2, SCORM 2004, cmi5 or xAPI package: both build the frame from the same source and accept the same messages. Tip: An assistant connected to Scormbusters over MCP can write the block for you: ask it to add a `custom_html` block, and it reads the field reference from `list_block_types`. ### The sandbox Your code runs in a frame sandboxed to scripts alone (`sandbox="allow-scripts"`, loaded from `srcdoc`). It has no cookies, no storage shared with Scormbusters or the LMS, no access to the page around it and no learner session. It cannot open pop-ups, submit forms or show `alert` dialogs. The frame also has its own content policy, so code must be self-contained: - inline `` ### The messages underneath `OpenCourse` is a thin wrapper over `postMessage`. Every message is an object with `protocol: "opencourse-interaction"` and a `type`: `ready`, `score` (`score`, `max`, optional `passed`), `complete`, `state` (`state`) or `resize` (`height`). The course replies with `init`, `scored`, `saved`, `completed` or `error`. The course accepts a message only from the block's own frame, only from the sandbox's `null` origin and only in those shapes. A message over 4,000 characters is refused, and messages are rate limited: a burst of 30, then 10 a second, and a score at most once a second. - [Full protocol reference](https://scormbusters.com/docs/custom-interactions) ### Scoring Set **Points** (1 to 100) to make the block a scored question; 0 leaves it unscored. A report of `score` out of `max` earns that fraction of the block's points. It counts as passed when your code sends `passed: true`, or at full marks when it sends no `passed`. In Scormbusters the result is recorded like any other answer: it counts toward the lesson score and the pass mark, respects the attempt limit, and shows in analytics and the `quiz.submitted` webhook, marked as self-reported. In an exported package it is one question in the lesson score and reaches the LMS as a numeric interaction. Warning: A self-reported score is not tamper-proof: your code decides it in the learner's browser, like any client-side SCORM content. Use the built-in question blocks where a result must be checked by the server. ### Saved state and resume `saveState` keeps one value per learner, per attempt, and `ready` hands it back. In Scormbusters it is saved with the learner's attempt. In a SCORM package it is kept in `suspend_data` within the 4,096-character SCORM 1.2 limit; a save that would not fit is refused (the reply says `ok: false`) and earlier saves stay. Keep state to answers and positions, not content. ### Accessibility The **Title** is required: screen readers announce it as the name of the interaction, and the accessibility checker flags a block without one. The optional **Text alternative** appears under the frame and is linked to it as its description. What happens inside the frame is the author's responsibility, and no automated check can see inside it. Make it work from the keyboard, label every control, keep text contrast at 4.5:1 and announce results with a `role="status"` element. ## The Scenes editor: slides, objects and layers URL: https://scormbusters.com/help/scenes-editor Last updated: 2026-10-09 Find your way around the Scenes slide canvas: which courses open in it, the slide panel, the insert toolbar, the Properties panel, layers, undo, keyboard shortcuts, preview and exporting a package. ### Which courses open in Scenes Scenes is the slide editor: every slide has a fixed size and every object sits where you put it, the way it did in Storyline or Captivate. Courses land in it when they are imported from a source that is laid out on slides: a Storyline publish, a Captivate Classic `.cptx`, a Captivate Classic publish whose actions keep state, or an all-new Captivate (12/13) publish whose actions keep state and whose slides are all free-positioned (see [Import a Captivate course](https://scormbusters.com/help/import-captivate)). Everything else imports into the block editor, where lessons reflow on any screen. A Scenes course opens straight into the editor at `/courses//scenes` when you open it from the Courses dashboard. New courses made with **New course** use the block editor; there is no way to start an empty Scenes course from the dashboard. ### The slide panel Slides are listed on the left under **Slides**, numbered in order. Click one to edit it. - **Add Slide** adds a slide after the others, the same size as the slide you are on, with a white background and one layer called **Base Layer**. - Right-click a slide for **Duplicate**, **Rename** and **Delete**. A duplicate copies the slide's layers and objects. The last slide cannot be deleted. - Double-click a slide's name, or press **F2**, to rename it. - Drag a slide to reorder it, or press **Alt+↑** / **Alt+↓**. The arrow keys move between slides and **Delete** deletes the current one. ### The insert toolbar Pick a tool from the toolbar above the canvas, then click the slide where the object should go; the tool goes back to **Select** afterwards. The tools, with their keys: - **Select** (V), **Text** (T), **Image** (I), **Button** (B), **Hotspot** (H). - **Shape**, which opens a picker: Rectangle, Rounded Rect, Circle, Triangle, Diamond and Arrow. - **Video** and **Audio**. Audio opens **Record Voiceover**, so you can record narration in the browser. - **Quiz Question** (Q), which asks for the type: Multiple Choice, True / False, Fill in the Blank, Matching, Sequence or Hotspot. Questions on a slide are graded the same way in the preview and in the exported package. - **Drag Item** and **Drop Zone**, for ungraded drag-and-drop. Learners can drag, or select an item and then a zone, so it works without a mouse. - **Interactive Video**. You can also drop an image or video file onto the canvas to upload it and place it. The rest of the toolbar holds the **Media Library**, alignment and distribution, **Toggle Grid** and **Snap to Grid**, **Variables**, zoom, and a responsive preview that shows the slide at Desktop (1280×720), Tablet (768×600) or Mobile (390×700) size, read-only. ### Objects and the Properties panel Click an object to select it; Shift+click adds to the selection, and dragging a box on an empty part of the slide selects everything inside it. Drag to move, drag a handle to resize (Shift keeps the proportions on a corner). With one object selected the **Properties** panel has four tabs: - **Style**: its name, position and size, rotation, stacking order, **Locked** and **Hidden**, and its look (fill, border, corner radius, text color and size, opacity). Quiz objects show their question editor here instead. - **States**: the looks the object can switch between. See [Triggers, variables and states](https://scormbusters.com/help/scenes-triggers). - **Triggers**: what happens when the learner does something. - **Animation**: an entrance and an exit (Fade, Fly, Zoom, Bounce, Wipe or Spin) with duration, delay and easing, and when the object appears on the timeline. With nothing selected the panel shows **Slide Properties**: the slide's name, its background (color, gradient or image), its transition, its size (shown, not changed here) and **Random draw** (see [Question pools and slide draws](https://scormbusters.com/help/question-pools)). With several objects selected you can lock, unlock, hide or show them all at once. ### Layers Every slide has a **Base Layer**, and can have more: a layer is a set of objects that triggers show and hide together, such as a feedback panel or a pop-up. The **Layers** tab under the canvas lists them, top of the stack first. - **Add Layer** adds one and makes it the layer new objects go onto. - The eye button hides a layer **in the editor only**, so you can work on what is underneath; it does not change what learners see. - Double-click or press F2 to rename; **Alt+↑** / **Alt+↓** reorder; **Delete layer** removes a layer and its objects (undo brings both back). The last layer cannot be deleted. - **Starts shown** / **Starts hidden** sets what learners see when the slide opens. Layers you add start shown; click the button on a layer's row to make it start hidden, so it appears only when a trigger shows it (a feedback panel, say). A layer that starts hidden keeps a **Starts hidden** tag on its row, and you can still see and edit it in the editor. Imported layers keep whether they started visible in the original. The same panel has a **Notes** tab for the slide's speaker notes. ### Undo, shortcuts and the command palette **Undo** and **Redo** are in the top bar (⌘Z and ⌘⇧Z, or Ctrl on Windows), and their tooltips say what will be undone. Undo covers slides, objects, layers and variables, up to 200 steps, and it is saved: undoing really changes the course, not just the screen. Press **?** or use the toolbar's keyboard button for the full list of shortcuts. The ones used most: the tool keys above; Tab to move between objects and Enter to select one; ⌘D to duplicate; the arrow keys to nudge by 1px (Shift for 10px, Alt to resize); F2 to edit an object's text; ⌘F to find in slides. **⌘K** opens the command palette ("What do you want to do?"), which reaches every command in the editor by name, and says why one cannot run right now. The **Tools** menu holds the rest: slide masters, the scene map, the question bank, branching, the component library, the **Player theme**, design tokens, **Accessibility**, **Alt text triage**, **Version history** and the analytics heatmap. ### Player theme **Tools → Player theme** styles the player around your slides: the accent (Next button), progress bar, navigation bar and its text, the background, a logo you upload (top left, top right or hidden), the navigation font, and rounded corners and a drop shadow on slides. Text on slides keeps its own font and colors. The preview and every exported package (SCORM 1.2, SCORM 2004, cmi5 and xAPI) look the same, and a package carries its own copy of the logo, so nothing loads from Scormbusters. Anything you leave unchanged follows **Settings → Branding** (brand color and logo); the course's own choices win. If navigation text or the progress bar would be hard to read on your navigation bar, the dialog says so and learners see a readable shade instead. There is no custom CSS for Scenes. See [Theming and branding](https://scormbusters.com/help/theming-branding). ### Checking, previewing and exporting - **Preflight**, in the top bar, checks the whole course as you work and says whether it will work in an LMS. Click a finding to jump to the slide or object. See [Preflight](https://scormbusters.com/help/preflight). - **Accessibility** (in Tools) checks the current slide: keyboard tab order, each object's alt text, label, language and role, and a WCAG audit. **Alt text triage** works through every picture in the course; see [Accessibility triage after an import](https://scormbusters.com/help/accessibility-triage). - **Preview** opens the course in a new tab in the real learner player, with triggers, variables and slide draws working. Progress you make there is saved like a learner's. - **Export** downloads a package: **SCORM 1.2** (works in every LMS), **SCORM 2004** (more room for resume data), **cmi5**, or **xAPI (Tin Can)**. If preflight has found something that will not work in an LMS, the export stops and the problems are listed. If the only problems left are accessibility ones, you can still export, and the audit log records that the course shipped with known issues. **PDF** opens a print view of the slides. Tip: The Scenes editor has no Publish button: export a package to deliver the course. To share it for comment first, open **Tools → Share for review**; the reviewers' comments come back to **Review** in the top bar. See [Stakeholder review](https://scormbusters.com/help/stakeholder-review). ## Scenes triggers, variables and states URL: https://scormbusters.com/help/scenes-triggers Last updated: 2026-10-07 How interactivity works on the Scenes slide canvas: the events and actions a trigger can use, conditions, course variables, object states, the order triggers run in, and how Storyline triggers and Captivate actions arrive on import. ### Triggers belong to objects A trigger is "when this happens, do these things". Every trigger lives on an object: select it and open the **Triggers** tab in the Properties panel. **Add Trigger** creates one that reads **When user clicks** → **Go to next slide**; change the event and actions from there. Each trigger card reads as a sentence, and anything it points at that no longer exists shows as "(deleted)". Triggers that respond to the slide rather than to the learner (when the slide starts or ends, a point on the timeline) are still set on an object on that slide. Imported courses put them on the slide's first object. **Flow View**, at the top of the Triggers tab, shows the same triggers as a diagram and has quick starts for common ones: Click → Next, Click → Prev, On load → Show layer, Click → Set variable, Hover → Change state, Click → Open URL. ### Events - **When user clicks**, **When user double-clicks**, **When user hovers**, **When mouse leaves**. - **When slide starts**, and **When slide ends**: when the slide's timeline runs out. - **At timeline position**: a number of seconds into the slide; it fires once each time the slide plays. - **When variable changes**: any variable, or one you name. - **When state changes**: this object or another, entering any state or a particular one. ### Actions A trigger runs its actions in order: - **Jump to slide**, **Go to next slide**, **Go to previous slide**. - **Show layer**, **Hide layer**, **Toggle layer**. - **Show object**, **Hide object**, **Change object state**. - **Set variable**, **Adjust variable** (adds its **Amount** to a number, in the Triggers tab and Flow View alike; a negative amount subtracts) and **Toggle variable** (flip true and false). - **Open URL**, in a new tab unless you untick it. - **Play media**, **Pause media**. - **Complete course**, **Submit results** and **Show correct/incorrect**. Imported Storyline courses can also open and close lightbox slides; those actions come only from an import. ### Conditions Add conditions to a trigger to make it run only sometimes. Choose what a condition tests, then pick the thing it tests from the list under it: - **Variable**: pick the variable. A number variable compares with is, is not, is more than, is at least, is less than or is at most; a text variable with is, is not or contains; a true/false variable is true or false. - **Object state**: pick the object, then the state (an object that has never changed state counts as **Normal**). - **Slide visited**: pick the slide, then **has been visited** or **has not been visited**. - **Layer showing**: pick the layer, then **is showing** or **is hidden**. With two or more conditions, choose **ALL** (every one must hold) or **ANY** (at least one). Both the Triggers tab and Flow View edit conditions the same way; in Flow View, click an **IF** pill to edit it. Conditions on imported triggers arrive already pointing at their variable, object, slide or layer. ### The order triggers run in When an event happens, the object's matching triggers run one after another, in the order they are listed, and each one checks its conditions against the state the triggers before it left. That is how an imported if/else works: it arrives as one trigger per branch, and the second branch sees what the first one set. The preview and the exported package run triggers with the same code, so a course behaves the same in both. ### Variables Variables belong to the whole course. Open them with **Variables** on the toolbar (or ⌘K → Variables): the **Course Variables** dialog lists each one's name, type and starting value. **Add Variable** creates one. - Types are **text**, **number** and **boolean** (true or false). Changing the type resets the starting value to empty text, 0 or false. - Names start with a letter, underscore or $, and contain only letters, numbers, underscores or $. - Double-click a name to rename it. In an exported SCORM package variables are saved with the learner's progress, so a learner who leaves and comes back finds them as they were. When resume data runs short, variables are kept ahead of how objects looked; see [resume data](https://scormbusters.com/help/export-to-lms#resume-data-and-the-suspenddata-limit). ### Object states A state is a named look for an object: a button can be Normal, Hover, Visited or Disabled; a shape Normal, Hover or Selected. Normal, Hover, Visited, Disabled, Selected, Correct and Incorrect are built in. On the **States** tab, click a state to edit how it looks, or **Add State** to name a new one. **Change object state** switches an object to a state by name; a condition can test which state an object is in. When a learner answers a question on a slide it switches to Correct or Incorrect. ### Imported Storyline triggers A Storyline HTML5 publish carries its triggers, and they arrive as Scenes triggers: clicks, double-clicks, hovers, slide start and end, timeline cues on the base layer and variable changes; jumps (including into a lightbox), layers shown and hidden (Storyline's "hide other layers" included), objects shown and hidden, variables set, adjusted and toggled, state changes, media and links. If/else becomes one trigger per branch: AND is ALL, OR is ANY, and Else gets the opposite condition. Anything that would run differently is left out and counted in the import report by reason, for example **Execute JavaScript triggers**, **Motion paths and animation triggers**, **Conditions mixing AND with OR**, **Triggers using built-in Selected, Disabled or Visited states**, **Hover triggers that restore on mouse leave**, **Custom Next and Previous button behavior**, **Result-slide actions** and **Triggers reading a variable that is no longer kept up to date**. See [Import a published Storyline course](https://scormbusters.com/help/import-storyline). ### Imported Captivate actions Captivate Classic actions arrive the same way, from a `.cptx` or from a Classic publish whose actions keep state: the success action of a button, click box or smart shape used as a button becomes a click trigger; a slide's On Enter becomes **When slide starts**, and its On Exit **When slide ends** on a slide that never pauses for a click. Show, hide, jumps, variables, conditional and shared actions, and change state come across; a jump runs last, as Captivate makes it once the whole action has run. An action that changes the variable its own condition tests gets a helper variable named `branch_1` (and on) so it reads its condition once. Left out and counted by reason: **Execute JavaScript actions**, **Apply Effect actions**, **Actions that depend on the timeline pausing**, **Conditional actions testing system variables or other variables**, **Conditional actions mixing AND with OR**, **Changes to Captivate's built-in states**, **Actions on a missed click or last attempt**, **Jumps Scenes cannot make the same way** and **Actions with no equivalent**. From a `.cptx`, change state and conditions with more than one test are counted rather than converted; import the HTML5 publish when they matter. An all-new Captivate (12/13) publish arrives on the slide canvas when its actions keep state and every slide is free-positioned (a PowerPoint deck imported into Captivate, for example): clicks, On Enter and hover; jumps, show, hide, assigning a value, decisions and change state to the author's own states. A click set to run once gets a `once_1` (and on) variable that slide entry clears. Enable and disable, animations, delayed or repeated actions, slide exit actions and conditions on Captivate's own variables or on objects are counted instead. See [Import a Captivate course](https://scormbusters.com/help/import-captivate). ## Question pools and slide draws URL: https://scormbusters.com/help/question-pools Last updated: 2026-10-07 Give each learner a random selection: set Questions per attempt on a lesson, or a Random draw bank on Scenes slides. How the draw is made, kept on resume, scored and exported. ### A pool on a lesson In the lesson editor's toolbar, the pool button reads **All questions** until you set one. Click it and enter **Questions per attempt**, then **Save**. The button then reads **Draw N of M**: each learner gets N of the lesson's M question blocks, drawn at random. Leave the number blank for every question. Only question blocks are drawn. Headings, text, media and every other block always show, so a lesson that mixes teaching and questions keeps its teaching. The draw is taken from all the questions in the lesson, so put each pool in a lesson of its own. Tip: If you enter a number as large as the lesson's question count, there is no pool: every learner gets every question. ### How the draw behaves - **Kept on resume.** The draw comes from the learner's attempt, so a learner who leaves and comes back sees the same questions. A new attempt draws again. - **Answered questions stay.** A question the learner has already answered is always part of their attempt. - **Scored on what was drawn.** The score counts only the drawn questions, out of the points they are worth. - **Nothing else can be answered.** The server refuses an answer to a question that was not drawn for that attempt. ### A slide draw in Scenes On the slide canvas the unit is a slide. Select a slide with nothing on it selected, and in **Slide Properties** find **Random draw**: 1. Type a **Bank** name. Slides with the same bank name are one bank. 2. Set **Show**: how many of that bank's slides each attempt gets. 3. Give every slide in the bank the same bank name and the same number. Each attempt shows that many of the bank's slides at random, in the order you authored them, and the same ones when the learner resumes. Slides that were not drawn are not part of the attempt, and their questions do not count toward the score. Clear the bank name to take a slide out of the draw. Warning: The bank uses the number set on its first slide, so a different number on a later slide is ignored. ### Imported pools and banks Question pools come across from imports already set: a Captivate question pool becomes a lesson that draws as many questions per attempt as Captivate did (or a slide bank, when the course lands on the slide canvas), and a Storyline scene that drew slides from a question bank becomes a slide bank that draws the same number. The import report lists them as **Question pools** or **Random question draws**. ### In an exported package An exported SCORM, cmi5 or xAPI package makes the draw once per attempt and saves it with the learner's progress, so resuming in the LMS shows the same questions or slides and a new attempt draws again. The draw is one of the things the package always keeps when SCORM 1.2's resume space runs short. See [Export to your LMS](https://scormbusters.com/help/export-to-lms#question-pools-and-slide-draws). ## Publishing and sharing a course URL: https://scormbusters.com/help/publish-and-share Last updated: 2026-10-07 Three ways a course leaves the editor: publish it with a public link and your organization's catalog, share it for review, or export a package — and how to test that package in a SCORM player first. ### Publish, share or export - **Publish** puts the course live in Scormbusters: anyone with its public link can take it, and learners in your organization can find it in the catalog and enroll. - **Share** creates a review link for people who comment rather than learn; see [Stakeholder review](https://scormbusters.com/help/stakeholder-review). - **Export** downloads a package for your LMS. You do not need to publish a course to export it; see [Export to your LMS](https://scormbusters.com/help/export-to-lms). ### Publishing a course In the course editor, click **Publish** in the top bar. The first time, a dialog asks you to confirm and says what publishing does; click **Publish** to go ahead or **Not yet** to leave it as a draft. The button then reads **Published**. Publishing records who published the course and when, which is what **Compare versions** compares against (see [Version history and compare](https://scormbusters.com/help/version-history)), and sends a `course.published` webhook if your organization has one. Any member who can edit courses can publish them. Unpublishing returns the course to draft: the public link stops working and learners can no longer open it. Warning: Publishing is a switch, not a snapshot. Edits you save to a published course reach learners the next time they load a lesson. Make large changes in a copy, or unpublish while you work. ### The public link Click **Published** to see the **Public course link** with a **Copy** button. Anyone with the link can view the course without signing in; it has no expiry and no password. The same popover has **Unpublish course**. To give the course only to named people, enroll them instead (**More → Enrollments**; see [Enrolling learners](https://scormbusters.com/help/enrollment)) and send them to **My Learning**. ### Test in a SCORM player Before you upload a package to an LMS, open **Export → Test in a SCORM player**. It runs the exported package against a built-in SCORM inspector, so you see what the LMS will see without uploading anything: - switch between **SCORM 1.2** and **SCORM 2004**; - watch the status, score, success, bookmark, session time, suspend data and interactions the course reports; - read every API call in the log, with a filter; - **Restart**, or **Simulate resume** to check a learner comes back where they left off. The SCORM player covers block courses. A Scenes course is checked with the Scenes editor's **Preview** and preflight instead; see [The Scenes editor](https://scormbusters.com/help/scenes-editor). ### Preview **Preview** in the top bar opens the course as a learner sees it in Scormbusters, with lesson navigation and working questions. Previewing does not publish anything. In the lesson editor, **Preview lesson** shows just the lesson you are editing. ## Stakeholder review: links, feedback and the author inbox URL: https://scormbusters.com/help/stakeholder-review Last updated: 2026-10-08 Send a subject-matter expert or client a review link — no account or seat needed — and work through their feedback: the kinds of feedback, approvals, change detection, replies and applying a suggested rewrite in one click. ### Create a review link In the course editor, open **More → Share**; in the Scenes editor, open **Tools → Share for review** (or ⌘K → Share for review). In **Share for Review**, give the session a title if you like ("Client Review — April 2026") and click **Create Review Link**, then **Copy** and send the link however you normally would. Or fill in **Email this link to the reviewer** (and an optional **Message**) and click **Create and email link**: Scormbusters sends them the link, and says so; if the email could not be sent, it tells you, so you can send the link yourself. - Reviewers do not need an account and do not use a seat: the link is their access. Reviewers are free and unlimited on every plan. - A link shows the whole course. A block course is shown lesson by lesson; a Scenes course plays every slide in the real player. - Links expire after 30 days. **Existing review links** lists each one with its verdict (**Approved** or **Changes requested**), when it expires, and how many comments are open. **Revoke** (then **Confirm revoke**) ends a link at once; its comments are kept. Everyone on the team who can see the course sees all of its review links. ### What the reviewer does The reviewer opens the link, types their name, and comments. On a block course they select the block a comment is about; on a Scenes course a comment attaches to the slide on screen. A comment with no block or slide is **General**. Each comment has a kind, chosen from **What kind of feedback is this?**: - **This is wrong** — a factual error, with room to write the correct version. - **Something is missing**. - **Someone will not be able to use this** — an accessibility problem. - **Say it differently** — wording, with room to write it the way they want it. - **Wrong image or video**. - **I have a question**. - **This looks good**. For **This is wrong** and **Say it differently** the reviewer can fill in **Write it the way you want it**: that suggested text is what you can later apply as written. The reviewer can also give the whole course a verdict with **Approve** or **Request changes** (on wider screens), and click it again to withdraw it. Their page refreshes every 30 seconds, so your replies and resolutions appear without reloading. ### The author inbox Back in the course editor, **Feedback** in the top bar carries a count of comments waiting for you, and opens **Review feedback**. In the Scenes editor the same inbox is **Review** in the top bar (or ⌘K → Review feedback). It sums up how many comments are to act on, how many approvals and how many questions, and groups comments by lesson (with **Open lesson**), by slide (**Open slide**) or as General. In the Scenes editor, **Show slide** on a comment selects its slide, and **Show the text** selects the text object a suggestion would replace. The most urgent kinds come first — factual errors, then missing content, then accessibility — oldest first within each. Resolved comments are hidden until you show them with the **Show N resolved** toggle. Each comment shows the text it was written about, the reviewer's suggested wording if any, and replies. You can **Reply** (the reviewer sees your answer on their page, marked **Author**), **Mark resolved**, or **Reopen**. On a course restricted to assigned authors, only they and the workspace's owner and admins can reply, resolve or apply; everyone else can read the feedback. New comments are also emailed, gathered up: about every half hour, once a reviewer has paused for ten minutes, each author gets one email listing the new comments on their courses with a link straight to **Review feedback** (in the Scenes editor for a Scenes course), however many comments there are. It goes to whoever created the review link, whoever created the course and its assigned authors (viewers are left out). Turn it off for a course in **More → Settings → Notifications → Reviewer comments**. ### When the content has changed since Every comment remembers what the block or slide said when it was written. If you edit the content afterwards, the comment says **This has been edited since the comment was written**; if you delete it, **This content has been deleted**. The reviewer sees the same note on their side, so nobody argues about text that is no longer there. ### Apply as written When a reviewer wrote the correct wording for **This is wrong** or **Say it differently** on a block, **Apply as written** replaces the block's text with theirs and resolves the comment in one step. It is offered only while the block still says what the reviewer saw: if the block has been edited since, apply the change by hand instead. On a Scenes course a comment is attached to a slide rather than to one object, so **Apply as written** is offered when the slide's words are in a single text object: it replaces that object's text, resolves the comment, and shows the change at once in every open Scenes editor. When the slide has several text objects (or none), which one the reviewer meant is your call: make the edit by hand and **Mark resolved**. ### With an AI assistant A connected AI assistant can create review links, read the feedback, reply, resolve comments and apply suggestions through the same rules, with your permissions. See [Connect your AI assistant](https://scormbusters.com/help/ai-features). ## Version history and comparing versions URL: https://scormbusters.com/help/version-history Last updated: 2026-10-07 How Scormbusters keeps earlier versions of lessons and Scenes courses, how to restore one, and how Compare versions shows what a learner would see differently — every change to a question called out first. ### Lesson versions (block editor) Each lesson keeps its own history. Open it with the clock button at the bottom right of the lesson editor (**Version history**; not shown on phones). The **Version History** panel lists versions newest first, named or marked **Auto-save**, each with **Compare** and **Restore**. - A version is saved automatically when you open a lesson whose latest version is more than 30 minutes old, and before every restore. - Up to 20 versions are kept per lesson; the oldest go first. **Restore** replaces all of the lesson's current blocks with the version you chose, after you confirm. The lesson as it stood is saved as a version first, so you can restore back to it. ### Course snapshots (Scenes) A Scenes course is versioned as a whole. Open **Tools → Version history** (or ⌘K → Version history). - **Save Snapshot**: give it a name (and a description if you like) and click **Save Now** before a big change. - An automatic snapshot is taken every five minutes while you work, labeled **Autosave** with the time. - Each snapshot shows whether it was **Auto**, **Manual** or **Before restore**, and how many slides and objects it holds, with **Compare**, **Restore** and **Delete snapshot**. Click a manual snapshot's name to rename it. **Restore** replaces the whole course with the snapshot. The course as it stands is saved first, so you can come straight back; the editor then reloads. Up to 50 snapshots are kept; at the limit, delete older ones to save new manual snapshots. ### Compare versions **Export → Compare versions** in the course editor (or **Compare** next to any version) opens a comparison of two versions of the course: what a learner would see differently, with every change to a question — answer keys, options, points — called out first. Choose **From (older)** and **To (newer)**. Either can be the **Current draft**, any publication (every time the course was published), a Scenes snapshot, or a lesson version; the swap button reverses them. The usual question — what changed since the last publish? — is the latest publication against the current draft. Tip: There is also a link to compare two published packages instead, for when the versions you have are exported zips. ### Evidence pack When the newer side is a publication or the current draft, **Evidence pack (printable)** and **Evidence pack (JSON)** export the comparison as a record you can hand to an auditor or a regulator. The evidence pack is part of the Enterprise plan. ### Which plans include what Version history and restore are on every plan. Comparing versions needs a plan (the trial included); the evidence pack is Enterprise. See [Plans and limits](https://scormbusters.com/help/plans-and-limits). ## Start a course: blank, from a template, or from an import URL: https://scormbusters.com/help/course-templates Last updated: 2026-10-07 The three ways to start a course in Scormbusters — a blank course, one of four templates with sample content, or an import of a course you already have — and exactly what each template contains. ### The New course dialog On the **Courses** dashboard, click **New course**. Type a **Course name** (you can change it any time), choose what to **Start from**, and click **Create course**. The course opens in the editor as a draft. - **Blank** gives you one module ("Module 1") with one empty lesson ("Lesson 1"), ready to write in. - A **template** gives you modules and lessons with sample content to edit or replace. If you leave the name empty, the course takes the template's name. Creating a course needs a plan or a trial; see [Plans and limits](https://scormbusters.com/help/plans-and-limits). ### The templates - **Compliance training** — why it matters, the rules, a knowledge check, a summary. Two modules: *Introduction* ("Why this matters", and "The policy in brief" as an accordion) and *Check your understanding* (a two-question knowledge check and a summary list). - **Software onboarding** — what you'll do, step by step, tips by role, a quick check. One module, *Getting started*: "What you'll be able to do", "Step by step" (process steps with a tip callout), "Tips for your role" (tabs) and a one-question "Quick check". - **Scenario practice** — a realistic situation, a decision with consequences, what good looks like. One module, *Scenario*: "The situation", "What would you do?" (a multiple-choice decision) and "What good looks like" (an accordion). - **Knowledge check** — a short scored quiz you can drop into any LMS. One lesson, "Questions", with three placeholder multiple-choice questions. The template questions shuffle their options and show feedback. Replace the placeholder text, answers and feedback with your own before you publish or export. ### Starting from a course you already have If the course exists in another tool, import it rather than rebuilding it: **Import** sits next to New course on the dashboard (and the New course dialog links to it). A published package is enough — SCORM, AICC, cmi5 or xAPI, or a Storyline, Rise, Captivate, Lectora or iSpring publish. See [Import a published package](https://scormbusters.com/help/import-published-scorm). Imports from slide-based tools (Storyline, and Captivate courses whose actions keep state) open in the Scenes slide editor; everything else, including every course you create with New course, uses the block editor. ### What next [Create your first course](https://scormbusters.com/help/create-first-course) walks through modules, lessons and blocks. The [Block types reference](https://scormbusters.com/help/block-types) lists every block, and [Theming and branding](https://scormbusters.com/help/theming-branding) sets how the course looks. ## Theming and branding URL: https://scormbusters.com/help/theming-branding Last updated: 2026-10-09 Set a course's theme (presets, colors and fonts) and your organization's branding (name, logo, color, export footer), and where each one shows: the preview, the hosted player and exported packages. ### A course's theme In the course editor, open **More → Theme**. The **Theme editor** has: - **Presets**: Corporate (the default), Modern, Warm, Bold, Academic, Minimal, Playful and Dark Mode. - **Colors**: Primary, Accent, Background and Text. - **Fonts**: a body font (Inter, Roboto, Lato, Open Sans or System) and a heading font (the same, plus Playfair Display and Merriweather). A font shows when the learner's device has it; otherwise their system font stands in. - **Lesson title**: how the title above each lesson looks: **Plain**, **Banner** (a band in the primary color) or **Gradient** (a band shading from primary to accent). The title's text turns white or dark, whichever reads better on the band. A lesson that opens with a heading matching its title shows that heading instead, with no title above it. - **Custom CSS**: your own rules, added after the theme's. Use it for small changes such as `.block-callout { border-radius: 0; }`. For safety it is cleaned before use: `<` and backslashes are dropped, `url()` may hold only an inline `data:image` picture (nothing loads from another site), and `@import`, `expression()`, script URLs and rules whose braces do not close are left out. The editor lists anything it left out as you type. Click **Save theme**. The course preview and exported packages show the whole theme: colors, both fonts, the lesson title style and your custom CSS. The hosted course player uses the primary and background colors and the body font. ### Contrast is yours to check The theme editor does not stop you choosing text and background colors that are hard to read. Body text needs a contrast of at least 4.5:1 against its background (3:1 for large text) to meet WCAG 2.1 AA. On the slide canvas the accessibility audit flags text below that; see [The accessibility checks](https://scormbusters.com/help/accessibility-checker). Whatever theme the author's own screen uses, learner pages — the player, the preview, the public link and the review page — always use the light look. ### Scenes courses Courses on the slide canvas style the player around the slides instead: **Tools → Player theme** in the Scenes editor. It sets the accent (the Next button), the progress bar, the navigation bar and its text, the background around the slides, a logo (top left, top right or hidden), the navigation font (system sans-serif, serif or monospace, which every computer has, so nothing is downloaded), and whether slides have rounded corners and a drop shadow. The preview player and every exported package (SCORM 1.2, SCORM 2004, cmi5 and xAPI) show the same result; the package carries its own copy of the logo. Anything you leave unchanged follows **Settings → Branding**: the brand color becomes the accent and the logo appears top left, with the brand name as its text alternative. A course's own choice always wins over the workspace's, field by field, and **Use workspace branding** clears the course's choices. Navigation text needs 4.5:1 contrast against the navigation bar and the progress bar 3:1. If a color you pick falls short, the dialog says so and learners see it moved toward black or white just far enough to read. Button text is white or black, whichever reads on the accent. The Player theme has no custom CSS. ### Your organization's branding **Settings → Branding** sets how your organization appears in exported courses and review links, and is the starting point for every Scenes course's player theme. Only the organization's Owner can save it. - **Brand Name** replaces "Scormbusters" in exported course headers. - **Logo**: **Upload Logo** or **Remove**. - **Brand Color**, as a hex color. - **Custom Footer HTML**, added to the exported package's page after it is cleaned. Click **Save Branding**. ### Scormbusters' own branding Exported packages carry no Scormbusters branding on any plan. Removing Scormbusters branding from the hosted learner experience, and the custom export footer, are part of Studio and Enterprise. A custom domain is Enterprise. See [Plans and limits](https://scormbusters.com/help/plans-and-limits). ## Plans and limits URL: https://scormbusters.com/help/plans-and-limits Last updated: 2026-11-04 What Designer, Studio and Enterprise include — authors, monthly migrations, storage, library scans and features — how migrations and credits are counted, how the 14-day trial works, what happens at a limit, and why learners and reviewers are always free. ### Who counts, and who is free Plans are priced per organization, not per learner. Only **authors** use seats. Learners and reviewers are free and unlimited on every plan: people with the Viewer role, learners who take a published course, and anyone commenting through a [review link](https://scormbusters.com/help/stakeholder-review) are never counted. Pending invitations to an author role do count toward seats until they are accepted or revoked. AI is not metered or sold: you connect your own assistant over MCP, on your own subscription. See [Connect your AI assistant](https://scormbusters.com/help/ai-features). ### What each plan includes - **Designer** ($20/month): 1 author, 5 migrations a month, 10 GB of media storage, library scans of up to 25 packages at a time, and version compare. - **Studio** ($149/month per organization, not per seat): up to 10 authors, 25 migrations a month, 50 GB, library scans of up to 100 packages, and a white-label hosted player. On annual billing, Rise courses migrate without counting for the subscription's first 60 days. - **Enterprise**: unlimited authors, migrations, storage and scan size, plus the audit log, a custom domain, LTI 1.3 hosted delivery, the audit evidence pack, and library search and bulk replace across every course. Enterprise can also run on-premises under an Enterprise agreement. Building is never metered: courses, blocks, Scenes, branching, review and exports to SCORM, cmi5 and xAPI are on every plan. Annual billing takes 20% off. Prices are on the [pricing page](https://scormbusters.com/pricing). ### The 14-day trial An organization that has never subscribed can start a 14-day trial of Designer or Studio from **Settings → Plan and billing** or the dashboard banner. A card is required; cancel any time before the trial ends and you are not charged. The trial includes 3 migrations in total and library scans of up to 5 packages; importing and previewing during the trial are free. ### Migrations and credits Importing is free: import and preview as many courses as you like. A **migration** is counted the first time an imported course is exported (any format, including the project export) or published, once per course — exporting it again never counts, a duplicate of it shares its migration, and a course built in Scormbusters never counts. Each month's allowance resets on the 1st (UTC). When the month's allowance is used, a **migration credit** is used instead. Credits are $99 a course, 10 for $790 or 50 for $2,950, bought from **Settings → Plan and billing**; they never expire. With no allowance or credit left, the export is refused with a message saying how many were used; nothing already counted is affected. For a whole library, the **Library Pass** ($4,900 one-time) covers up to 150 course migrations, 12 months of Studio and a dated accessibility evidence report; **Library Pass Plus** ($9,500) covers up to 500 and 12 months of Enterprise LTI 1.3 hosted delivery. Both are bought by card or invoice through us. We can also migrate courses for you at $600–$1,200 a course. To stop abuse, an organization can import up to 200 courses a month (50 on Designer). Separately, each person can run up to 10 imports in 24 hours, and an upload can be up to 100 MB. Scanning a library first imports and counts nothing. ### At a limit Nothing is deleted when you reach a limit; the action is refused with a message saying what would lift it: - **Authors**: "This is a single-author workspace" on Designer; Studio adds up to 10 authors. - **Migrations**: the month's allowance and your credits are used; buy credits or wait for the 1st. - **Storage**: "This upload would exceed your plan's … storage." - **A feature on a higher plan**: the message names the plan that includes it. ### Billing, and when a subscription ends Owners and Admins manage the plan in **Settings → Plan and billing**: start a trial, subscribe monthly or annually (annual takes 20% off), upgrade, or open **Manage subscription** to change the card or cancel. If a payment fails, the plan keeps working while the card is retried, and the page shows **Update payment method**. When a subscription ends, the organization has no plan: existing courses still open and export, but creating and importing courses stop until you subscribe again. There is no standing education or nonprofit discount. If your situation is unusual, talk to us. ## Accessibility triage after an import URL: https://scormbusters.com/help/accessibility-triage Last updated: 2026-10-07 The first accessibility pass on an imported course: Fix accessibility now, alt text triage (describe once, or mark decorative), the lesson editor's checker, and what Export with known issues means. ### Why imports need a pass Courses built in older tools often describe their pictures with a file name ("Yellow-BG.png"), a default name ("Picture 3") or nothing at all, so a screen reader announces noise or skips something that matters. The importer cannot know what a picture is for. Only you can decide that, and the triage below makes it one decision per picture rather than one per copy. ### Fix accessibility now When an import lands on the slide canvas (Storyline, a Captivate `.cptx`, or a Captivate publish whose actions keep state), the import screen counts what needs fixing — "N accessibility fixes before every learner can use it" — rule by rule. **Fix accessibility now** opens the Scenes editor with **Alt text triage** already open. If there are no pictures to decide on, it opens **Preflight** instead, with the other problems listed. You can come back to it any time: **Tools → Alt text triage** (the number shows how many are left), ⌘K → Alt text triage, or **Describe N pictures** in Preflight. ### Describe, decorative or skip Triage shows one picture at a time, what a screen reader announces for it now, and **What should a learner hear instead?** - **Describe** (or Enter) saves your description as the picture's alt text. Describe what the picture tells the learner, not what it looks like. - **Decorative** tells screen readers to skip the picture silently, and takes it out of the keyboard order. Use it for backgrounds, dividers and ornaments that carry no information. - **Skip** leaves it for later in this session. The same picture used on many slides appears once — "N copies across K slides — one decision covers all" — with the most-repeated pictures first. Each decision can be undone like any other edit. Warning: A picture that is clickable cannot be marked decorative: it needs a description that says what clicking it does. Triage says so when it reaches one. ### Courses in the block editor Imports that reflow into lessons get their first pass in two places: - Tick **Review the content after import** on the import screen, and the report flags images without alt text and dated references, so the **Import report** panel in the editor lists them. - In each lesson, the accessibility checker at the bottom left of the lesson editor shows a count when something needs fixing; expand it for the list (**Accessibility (N issues)**) and **Jump to block** to fix each one. The lesson editor has no decorative setting yet, so every image there needs alt text. See [The accessibility checks](https://scormbusters.com/help/accessibility-checker) for every rule and the WCAG criterion it maps to. ### Export with known issues On the slide canvas, preflight decides whether a course can be exported. Problems that would break the course in an LMS — a trigger pointing at a deleted slide, a question with no correct answer — stop the export until they are fixed. Accessibility problems do not: if they are all that is left, the export asks first. The dialog lists them ("N accessibility problems left"), explains that the package will work but some learners — people using a screen reader or a keyboard — will be stopped by them, and offers **Fix them first** or **Export with N known issues**. Exporting with known issues is recorded in the audit log, so there is a record that the course shipped knowing what it still needs. Block courses export without this step; use the lesson checker before you export. ### What triage cannot do Triage makes sure every picture has a decision; it cannot judge whether a description is good, whether captions are accurate, or whether the reading order makes sense. Test the course with a screen reader and a keyboard before you rely on it. A connected AI assistant can look at the pictures on a slide and draft descriptions for you to approve; see [What to ask your AI assistant](https://scormbusters.com/help/ai-workflows). ## Preflight: catching problems before you publish URL: https://scormbusters.com/help/preflight Last updated: 2026-10-07 30 checks that run as you build a Scenes course and stop the export on definite errors — broken triggers, unanswerable questions — and ask before exporting with accessibility gaps. ### What preflight is Preflight reads your course the way the player will and tells you what will not work — while you are building, not after you have uploaded a package to your LMS and watched someone hit a dead button. There are 30 checks, 11 of which are definite failures rather than suggestions. Open it from the toolbar in the Scenes editor: the button shows a count as soon as something needs attention, and shows a tick and **Ready** when nothing does. The panel filters findings by **All**, **Must fix**, **Worth checking** and **Suggestion**. Findings are grouped by slide, because the fix is almost always “go and look at that slide”. Clicking one takes you there and selects the object. Tip: Errors that would break the course in an LMS stop export from the Scenes editor: the export stops and the panel opens on what needs fixing. Accessibility errors do not stop it: when they are all that is left, a dialog offers **Fix them first** or **Export with N known issues**, and the audit log records an export with known issues. See [Accessibility triage after an import](https://scormbusters.com/help/accessibility-triage). ### Things that point at nothing The most common way a course breaks silently. Triggers refer to slides, layers, objects and variables by an internal reference. Delete the thing they point at and the trigger survives, looking perfectly healthy in the editor, doing nothing at all for the learner. Every check in this group is definite: if one fires, that trigger will not work. - A trigger jumps to a slide that no longer exists — Must fix - A trigger shows or hides a layer that no longer exists — Must fix - A trigger targets an object that no longer exists — Must fix - A trigger switches an object to a state it does not have — Must fix - A trigger uses a variable that no longer exists — Must fix ### Triggers that can never fire Logic that is well-formed but unreachable. A timed trigger set for later than the slide lasts, a layer nothing ever shows, a variable checked by a condition that nothing ever changes. None of these are errors in the strict sense — the course still runs — but none of them do what you meant. - A trigger has no actions — Worth checking - A timed trigger is set past the end of its slide — Worth checking - An object leaves the timeline before it arrives — Worth checking - A variable is never used — Suggestion - A variable is checked but never changes — Worth checking - A layer can never be shown — Worth checking - A lightbox slide is never opened — Worth checking - A trigger jumps to the slide it is already on — Suggestion ### Questions nobody can answer A question with no correct answer marked, or whose correct option was deleted after the fact, can be answered but never passed. Learners discover this; you should first. - A question has no correct answer — Must fix - A question's correct answer is not one of its options — Must fix - A multiple-choice question has fewer than two options — Worth checking - A question is worth no points — Worth checking ### What the LMS actually receives The score your LMS records is not always the score you think you are sending. If every question in a course can be skipped with Next, a learner who skips them all is scored on how many slides they visited instead — and the gradebook will not say so. - A learner can finish without answering the questions — Worth checking - A scored course has no results slide — Suggestion ### Whether a learner can actually use it These checks run continuously against the course you are building, not against a published package after the fact. A control with no name, an image with no alt text, text that fails contrast, or a click target a keyboard can never reach will show up here as you create it. - A control a learner must use has no name — Must fix - An image has no alt text — Must fix - A hotspot question cannot be answered without seeing it — Worth checking - Text does not have enough contrast against its background — Must fix - Two controls on a slide claim the same tab position — Worth checking - A control can only be used with a mouse — Must fix - A video has no captions — Worth checking - A slide with text moves on by itself — Worth checking ### Content a learner will never see Empty slides and objects dragged off the edge of the canvas. Cheap to fix, easy to miss in a long course. - A slide has nothing on it — Suggestion - An object sits outside the slide — Worth checking - Text is too long for the box it sits in — Worth checking ### Three levels, and what they mean **Must fix** — definitely broken for some or all learners. A trigger pointing at a deleted slide does nothing; a question with no correct answer cannot be passed; an image with no alt text is skipped by a screen reader. Broken references and unanswerable questions stop export from the Scenes editor; accessibility errors ask first. **Worth checking** — probably not what you meant, but the course still runs. A layer nothing shows, a question worth zero points, a video with no captions. **Suggestion** — worth a look at some point. An unused variable, an empty slide. Preflight is deliberately quiet: a check that fires on a healthy course teaches you to ignore the panel, which costs you every other check too. If you see a finding you believe is wrong, it is a bug in preflight and worth reporting. ### Why check while you build A trigger pointing at a deleted slide, a question with no correct answer or a button a keyboard user cannot reach is easy to create and hard to spot by clicking through. Left alone, it surfaces when a learner hits it, or when someone runs an accessibility audit months later. Preflight treats the course as something that can be checked the way code is: every rule runs over the whole course on each change, so a problem shows up the moment you create it and disappears the moment you fix it. ## Setting Completion Rules URL: https://scormbusters.com/help/completion-rules Last updated: 2026-10-07 Set a course's passing score, attempt limit, availability dates, lesson unlock schedule and completion certificate, and see which settings learners are held to today. ### Opening Course Settings In the course editor, open **More → Settings**. The Course Settings panel slides in from the right, grouped into collapsible sections: Completion & Scoring, Cover & Navigation, Availability Window, Prerequisites, Content Settings, Drip Content and Notifications. Changes are not saved as you type. Click **Save Settings** at the bottom of the panel; it confirms with “Saved”. The rules are read when a learner starts a session, so a learner already partway through keeps the rules they started with. ### Passing score Passing score is the percentage a learner needs for the course to be marked passed. The default is 80%. It is measured across the whole course: when the learner finishes, Scormbusters adds up the points they scored on every question and divides by the points available. If that is at or above the passing score the course is **passed**, otherwise **failed**. A course with no scored questions is simply **completed**. There is no separate pass mark per lesson. Tip: Set the passing score to 0 for informational courses with no assessment, so finishing is enough. ### Max attempts Max attempts limits how many times a learner can start the course. Leave it blank for unlimited. When a learner has used every attempt, starting the course again is refused with “Maximum attempts reached”. ### Availability window Available from and Available until set when learners can open the course. Before the start date, or after the end date, starting the course is refused as not available. Leave both blank for always available, or set just one to open on a date or close on a date. Under **Drip Content** you can also schedule individual lessons: unlock a lesson a number of days after the learner enrolled, or on a fixed date. ### Settings that are saved but not yet enforced Three settings in the panel are stored with the course but are **not yet applied to learners**. Do not rely on them to restrict access: - **Time limit (minutes)**: no timer is shown and nothing is submitted when the time passes. - **Prerequisites**: you can tick other courses from the list, but learners are not blocked from starting. - **Require sequential completion** (Content Settings, off by default): learners can still open lessons in any order. Warning: If a deadline or ordering matters, say so in the course description and first lesson until these are enforced. ### Certificates **Issue completion certificate** is on by default. You can set the certificate title and an “Authorized by” name and role. The certificate page uses your organization's logo, name and brand color from Settings → Branding, and shows the learner's name, the course, the completion date and a Certificate ID. Learners find it under the Certificates tab of My Learning and use **Print Certificate**; to keep a PDF, choose “Save as PDF” in the browser's print dialog. ## Enrolling Learners URL: https://scormbusters.com/help/enrollment Last updated: 2026-10-07 Enrol existing org members in a course by email or through a group, set due dates, track progress and remove enrollments. ### Enrolling individuals In the course editor, open **More → Enrollments**. On the Enrolled tab, click **Enroll learners** and paste one or more email addresses, one per line (or upload a CSV), with an optional due date. Only people who are already members of your organization can be enrolled. Any email that does not match a member is listed as “not found in your org” and nothing is sent for it; invite them first from Settings → Team. Enrolling does not email the learner, so tell them the course is waiting. Tip: You can enroll up to 200 people or groups in one go. ### Enrolling a group Switch to the **Groups** tab in the same panel. Create a group there (**New group**) and enroll it in the course (**Enroll group**). Click **Members** on a group to see who is in it, **Add** people from the workspace (filter by email) and **Remove** them; owners and admins can change a group's members. Only people already in the workspace can be added, so invite someone new from Settings → Team first. Someone who leaves the workspace is listed as having left until you remove them. Access is checked against group membership each time a learner starts the course, so people added to the group later can open it too. ### Tracking progress The Enrolled tab lists each learner with the date they were enrolled, their due date (click to add or change it), a progress bar and a status of **In progress** or **Complete**. For per-lesson detail and scores, use Analytics → Advanced Reports → Learners → View transcript. ### Removing an enrollment Hover over a learner's row and click the X at the end of it. Their enrollment is removed and they can no longer start the course; their past progress and events stay in your analytics. There is no reset-progress option. Removing an enrollment does not revoke a certificate already issued. ### Who can enroll Only Owners and Admins can enroll or remove learners. Members, even on courses they built, need an Admin to do it. Authors (Owner, Admin, Member) can open any course in the org without being enrolled, so they can test it. ## LTI 1.3 Integration (Canvas, Moodle, Blackboard) URL: https://scormbusters.com/help/lti-setup Last updated: 2026-10-07 Connect Canvas, Moodle or Blackboard to Scormbusters with LTI 1.3 so learners launch courses from the LMS without a separate login. ### What LTI 1.3 does here LTI 1.3 lets your LMS launch Scormbusters with a signed token that says who the learner is and which course to open. The launch provisions a learner account automatically, so the learner does not log in to Scormbusters separately, and the LMS assignment counts as their enrollment. LTI support is **beta**. What is supported today: launching a course, in a new tab/window or embedded in the LMS page, and **grade passback** (Assignment and Grade Services) — when the learner finishes, their score and completion post to the LMS gradebook. Launch and passback are verified end to end on Canvas (as an assignment or a module item) and Moodle 5.2.3; Blackboard has not been tested yet. What is not supported: **Deep Linking** (picking content from inside the LMS course builder). On the hosted service, LTI delivery is part of the **Enterprise** plan, because every launch serves the learner from our infrastructure. On-premises Enterprise deployments include it. Embedded (iframe) launches depend on third-party cookies, which some browsers block by default. If learners see a login screen inside the frame, configure the LMS activity to open in a new window. ### Step 1: Give your LMS Scormbusters' tool values Go to Settings → **LTI integration**. The **Your LTI Tool Configuration** card shows three values to copy into your LMS: - **Tool URL (Launch URL)** - **Login URL (OIDC Initiation URL)** - **JWKS URL (Public Key Set)** — copy it exactly: it ends in your organization's id, and without it the LMS cannot verify grade passback Canvas: Admin → Developer Keys → + LTI Key. Use the Tool URL as the Target Link URI, the Login URL as the OpenID Connect Initiation URL and the JWKS URL as the public JWK URL. Save, turn the key On and note its Client ID. Moodle: Site administration → Plugins → Activity modules → External tool → Manage tools → configure a tool manually, LTI version 1.3, with Tool URL, Initiate login URL and Public keyset URL set to the three values. For grade passback, set **IMS LTI Assignment and Grade Services** to "Use this service for grade sync and column management". In Canvas, enable the LTI Advantage gradebook scopes on the developer key. The LTI integration page also has step-by-step setup notes for Canvas, Moodle, Blackboard and Schoology. ### Step 2: Register the LMS as a platform Back in Settings → LTI integration, click **Add Platform** and fill in the fields from your LMS: - **Platform Name**: your own label - **Issuer URL**: e.g. `https://canvas.instructure.com` — every Instructure-hosted Canvas uses exactly this, not the school's own domain - **Client ID**: from the key or tool you created - **Auth Login URL**: the LMS's OIDC authorization endpoint - **Auth Token URL**: the LMS's OAuth2 token endpoint - **JWKS URL**: the LMS's public key set - **Deployment ID(s)**: optional for a single LMS, required for Blackboard; separate several with commas Registered platforms are listed under **Registered Platforms**, where you can edit or delete them. Only Owners and Admins can manage platforms. ### Step 3: Point a launch at a course Each launch needs to know which Scormbusters course to open. In the LMS activity or module item, add the custom parameter `course_id=`. The UUID is in the course editor's address: `/courses/`. If no `course_id` is sent, Scormbusters falls back to the LMS resource link id, which usually will not match a course, so always set it. Tip: One platform registration serves every course: use a different `course_id` in each LMS activity. ## Connecting an xAPI / LRS URL: https://scormbusters.com/help/xapi-lrs Last updated: 2026-09-26 Send xAPI statements to SCORM Cloud, Learning Locker, Watershed or any xAPI 1.0.3 LRS, and see exactly which statements Scormbusters sends. ### What xAPI and an LRS are xAPI (Tin Can) records learning as statements of the form “actor verb object”, e.g. “Jane completed Introduction to Safety”. A Learning Record Store (LRS) receives and stores them. Connecting one lets you keep Scormbusters activity alongside records from your other tools. ### Configuring the connection Go to Settings → **xAPI / LRS** and enter two values: - **LRS Endpoint URL**: the statements base URL from your LRS, e.g. `https://lrs.example.com/xapi` - **Auth Token**: either `username:password` (your LRS key and secret) or a Bearer token Click **Test Connection** to send a test statement, then **Save Configuration**. ### Which statements are sent Scormbusters sends these statements, as the learner acts: - **launched** the course: when a learner starts a course session - **completed** a lesson: when they finish a lesson, with the lesson score if it has scored questions - **passed**, **failed** or **completed** the course: when they finish the last lesson, depending on the passing score, with the course score The actor is the learner's name and `mailto:` email. Activity ids are URLs of the form `https:///courses/` and `…/courses//lessons/`; lesson statements carry the course as their parent. Individual question answers are not sent. Warning: Delivery is best-effort: each statement is sent once, with an 8-second timeout, and is not retried if your LRS is down. ### Previewing and downloading The **Statement Preview** section on the same page shows the five most recent learning events for your organization, labeled with their xAPI verb. **Download as JSON** under Export Statements builds xAPI statements from your 100 most recent learning events and downloads them. It is a sample for checking, not a full archive, and it is not a copy of what your LRS received. ## Understanding Your Analytics Dashboard URL: https://scormbusters.com/help/analytics Last updated: 2026-09-26 What each Analytics card and chart measures (learners, completions, average score, completion rate, drop-off by lesson) and how to filter by course and period. ### The four key metrics The top of the Analytics page shows four cards for the selected course and period: - **Unique learners**: people with at least one learning event - **Course completions**: course sessions finished - **Avg score**: the average score across every question answered - **Completion rate**: of the learners who started a course in the period, the share who finished it ### Filtering Use the **Course** dropdown (default: All courses) and the **Period** dropdown (Last 7, 14, 30 or 90 days; default 30). Every card, chart and table on the page updates together. ### Events over time A daily bar chart of learning events over the selected period. Hover over a bar to see that day's count. Spikes usually line up with launches and reminders; long flat stretches are worth a nudge to learners. ### Course performance A table of courses with their completions and average score in the period. A course with plenty of completions but a low average score is a good candidate for revision. ### Block engagement and drop-off **Block engagement heatmap**: pick a lesson to see how learners engaged with each of its blocks. **Drop-off by lesson**: for each lesson, how many learners started it, how many completed it and the drop-off between the two. Lessons with more than 50% drop-off are highlighted. Start with the biggest drop: open that lesson, go through it as a learner and look for length, confusing content, a hard quiz or broken media. Tip: Drop-off is shown however few learners there are, so treat small numbers with care. ### More views **Team View** shows learner activity by group, and **Advanced Reports** has learner transcripts, question analysis and time on task. Both are linked from the top of the Analytics page. ## Advanced Reports URL: https://scormbusters.com/help/advanced-reports Last updated: 2026-10-07 Learner transcripts, question-level quiz analysis and time on task per lesson, each exportable to CSV. ### Opening Advanced Reports On the Analytics page, click **Advanced Reports**. The page has three tabs: **Learners**, **Quiz Analysis** and **Time on Task**. Each has an **Export CSV** button. ### Learners One row per learner: Email, Started, Completed, Avg score and Last active. Filter by course, search by email, and page through the list. Click **View transcript** on a row to expand that learner's record: each lesson with its score, time spent and completion date. ### Quiz Analysis Pick a course to see every question in it with the number of attempts, the percentage answered correctly, a difficulty rating and a correct-versus-incorrect bar. A question that most learners get wrong is either hard or badly worded; read it again before blaming the learners. ### Time on Task Pick a course to see, per lesson, the average time learners spent, the number of completions and the drop-off. A lesson that takes far longer than similar ones may be confusing; one that takes almost no time may be getting skipped. ### Exporting Each tab's **Export CSV** downloads the full dataset, not just the visible page: - Learners: one row per learner, as `learners-YYYY-MM-DD.csv` - Quiz Analysis: one row per question for the selected course, as `quiz-analysis-YYYY-MM-DD.csv` - Time on Task: the raw learning events for the selected course (one row per event, with durations), as `time-on-task-YYYY-MM-DD.csv` To automate, pull raw learning events from `GET /api/analytics/events` with an API key that has the `read:analytics` scope; the Learners and Quiz Analysis exports are only available from this page. Warning: Exports contain learner email addresses. Handle them under your organization's data protection policy. ## Team Roles and Permissions URL: https://scormbusters.com/help/team-roles Last updated: 2026-10-08 What Owners, Admins, Members and Viewers (learners) can do, how one person works in several workspaces, how to hand over ownership or remove someone, and how to restrict a course to assigned authors. ### Owner Every workspace has exactly one Owner — at first, the person who created it. Only the Owner can change other people's roles (Settings → Team, the role dropdown on each member) and invite Admins. The Owner cannot be removed or demoted; to step down, hand ownership to someone else (below). ### Admin Admins run the workspace day to day. They can invite Members and Viewers, remove anyone except the Owner, enroll learners, manage plan and billing, configure integrations (LTI, xAPI, API keys and webhooks), read the Audit Log, and edit every course, including restricted ones. They cannot change roles. ### Member Members are authors. They can create courses, edit every course in the workspace that isn't restricted to other authors, use the question bank, and open any course without being enrolled so they can test it. They cannot enroll learners, manage the team, configure integrations or read the Audit Log. ### Viewer — the learner role Viewers are learners. They can open only the courses they are enrolled in (individually or through a group), track their own progress, and earn certificates. They cannot create or edit content, see other learners' data, or reach any settings — the authoring environment is closed to them at the database level, not just hidden in the UI. Viewers are free and unlimited on every plan and never count against your author seats, so enrolling your whole company costs nothing extra. Owners, Admins and Members each take a seat, as do pending invites for those roles. ### One person, several workspaces One account can belong to several workspaces — a contractor working for two clients, say — with a different role in each. Accepting an invite adds that workspace to your account; the workspaces you already belong to stay yours. You work in one workspace at a time. When you belong to more than one, your account menu (top right) lists them; choose one to switch. Courses, settings, the team page and billing always show the workspace you're in. Someone who belongs to two workspaces takes a seat in each one where they author. Tip: Personal tokens and connected AI assistants belong to the workspace they were created in. Switching workspace in the browser doesn't move them; create a separate token or connection in each workspace you want an assistant to work in. ### Transferring ownership The Owner can hand the workspace to one of its Admins or Members: Settings → Team, **Make owner** on that person's row. A confirmation names who will become Owner. The new Owner takes over role changes; the previous Owner becomes an Admin. The plan, billing and every course stay with the workspace — nothing moves. ### Removing someone, or leaving Owners and Admins remove a member from Settings → Team. Removal is immediate: the person loses access to the workspace's courses, and any personal tokens or connected apps they set up for it stop working. If it was the workspace they were working in, they're moved to another of their workspaces, or — with none left — shown a page where they can create their own workspace (which starts the usual trial) or ask for an invite. Courses they built stay with the workspace. Anyone but the Owner can leave a workspace themselves from the bottom of Settings → Team. The Owner transfers ownership first. ### Assigned authors: restricting who can edit a course By default every author in the workspace can edit every course. To limit one course, an Owner or Admin opens it and chooses **Who can edit** — in the block editor's course settings, or the Scenes editor's **Tools** menu — then picks **Only assigned authors** and ticks the Members who should edit it. Owners and Admins can always edit it. Everyone else in the workspace can still open and preview the course; opening it in the editor shows it as read-only with the names of its assigned authors. Restricted courses carry a **Restricted** lock on the dashboard. The restriction also applies to bulk find-and-replace, question-bank updates, translations and changes made through an AI assistant connected with someone's own token. Assigned authors can see the list but only Owners and Admins can change it. ## Audit Log URL: https://scormbusters.com/help/audit-log Last updated: 2026-10-07 See which admin and integration changes are recorded in the Scormbusters Audit Log, how to filter them, and how to export them. ### What is recorded Settings → **Audit log** (Owners and Admins, on the Enterprise plan) lists these actions: - Course created, imported, duplicated or exported — including a Scenes export that shipped with known accessibility issues — and an audit evidence pack exported - Course deleted - Member removed, member role changed - API key created, updated or revoked - Webhook created or deleted - Video provider credentials and AI assistant connections added or revoked - Connected apps (OAuth) approved or revoked - Personal access tokens created or revoked - Learner data exported, library find-and-replace (and its undo), and review verdicts - Changes made through the MCP server, one entry per write-tool call Inviting someone, changing course settings and publishing from the course editor are not recorded yet. Each entry shows the timestamp in your local time, the user, the action, the resource and details. Tip: Entries can be added but not edited or deleted from the app. ### Filtering and exporting Filter by **Action Type** (All actions, Courses, Lessons, Members, Blocks, Learner data, API keys, Webhooks), by **User ID** (paste the person's user id) and by a **From** / **To** date range. There is no free-text search. **Export CSV** downloads the entries currently loaded in the table. ### Using it When a member disappears, a role changes or an integration stops working, filter to the date range and check who changed what. For compliance, export the relevant period as evidence of who changed access and integrations. ## API Keys & Webhooks URL: https://scormbusters.com/help/api-keys Last updated: 2026-10-07 Create scoped organization API keys for the REST API, personal tokens for AI assistants, and verify signed webhooks for course, learner and organization events. ### Creating an API key Owners and Admins: go to Settings → **API** and, under **API Keys**, click **Create API Key**. Organization keys start `oc_live_`. Give it a name you will recognize later (e.g., 'HR Integration'), choose its scopes, and optionally an expiry (30, 90 or 180 days, or 1 year). The secret is shown exactly once, so copy it straight into a password manager or secrets vault; if you lose it, revoke the key and create another. A key carries only the scopes you give it, whoever created it: Read Courses (`read:courses`), Write Courses (`write:courses`), Read Analytics (`read:analytics`), Read Users (`read:users`) and Write Completions (`write:completions`). Grant the fewest a job needs. Revoke a key at any time from the same page; it stops working immediately. Warning: Treat API keys like passwords. Never commit them to version control, put them in client-side JavaScript or paste them into chat tools. Revoke any key that may have leaked. ### Using a key with the REST API Send the key in the `X-API-Key` header, against your Scormbusters address: `curl -H "X-API-Key: " https:///api/analytics/events`. The REST API covers creating courses, enrollments, analytics events and webhooks; the full reference, with request and response shapes, is at [/docs/api](https://scormbusters.com/docs/api). To read and build course content programmatically, use the MCP server: it is the authoring API, for AI agents and scripts alike. Setup is at [/docs/mcp](https://scormbusters.com/docs/mcp). Tip: An organization key also works with the MCP server, sent as `Authorization: Bearer `. To connect an AI assistant as yourself, any member can instead create a **personal token** (`oc_pat_…`) in the **Personal tokens** section of the same page; personal tokens work with the MCP server only, not the REST API. See [Connect your AI assistant](https://scormbusters.com/help/ai-features). - [MCP server reference: client setup, tools, errors and limits](https://scormbusters.com/docs/mcp) - [REST API reference](https://scormbusters.com/docs/api) ### Setting up webhooks Webhooks send an HTTP POST to your server when something happens, so you do not have to poll. In Settings → API, click **Add Webhook**, enter your endpoint URL and choose its events: - `course.published` and `course.unpublished` - `enrollment.created`: a learner enrolls themselves from the course catalog (enrollments made by an admin in the editor or through the REST API do not send it) - `enrollment.completed`, `lesson.completed`, `quiz.submitted` and `certificate.issued` - `user.joined`, `user.removed` and `invite.accepted` Payloads for each event are in the [webhooks reference](https://scormbusters.com/docs/webhooks). Each request carries the event name in the `X-OpenCourse-Event` header, with a JSON body. Recent deliveries are listed under each webhook. ### Verifying webhook payloads Every request has an `X-OpenCourse-Signature` header of the form `sha256=`: an HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (shown when you create it). Compute the same HMAC over the raw body you received, compare it to the header with a constant-time comparison, and reject the request with a 401 if they differ. Tip: Respond with a 2xx within 10 seconds. Each event is delivered once and not retried, so if your endpoint may be down, record events as they arrive and reconcile from the REST API. ## Keep your courses: exporting everything, and what happens if you cancel URL: https://scormbusters.com/help/keep-your-courses Last updated: 2026-11-04 Your courses are yours. Download any course or the whole library as an open project export, export LMS packages that work without Scormbusters, and keep doing both for at least 90 days after a subscription ends. The problem: I'm worried about losing my courses if we stop paying. ### The guarantee - **On every plan** you can download any course as a project export — its complete, editable source and media — and as SCORM 1.2, SCORM 2004, cmi5 or xAPI packages. - **If your subscription ends**, your workspace becomes read-only rather than closed. For **at least 90 days** every course still opens and previews, every course you built and every imported course you have already exported or published still exports in every format, and owners and admins can still download the whole library. - **Packages you have already exported keep working** in your LMS whether or not you subscribe, because they do not depend on Scormbusters at all. ### Download one course Any author can download a course's project export: - From **Courses**, use the download icon on the course's card. - In the block editor, open **Export** and choose **Project export**. You get a `.opencourse.zip` holding the course as JSON and every image, video and audio file it uses. See [The project export format](https://scormbusters.com/help/project-export) for what is inside. ### Download the whole library Owners and admins can open **Settings → Library export** and download every course in the workspace — restricted courses included — as project exports. Imported courses that have never been exported are left out and listed, since exporting one counts it as a migration; export them one by one to keep them. A large library comes in parts of ten courses, so each download finishes in one go; each zip holds a folder per course and a `library.json` listing them. ### If your subscription ends Nothing is deleted when a subscription is canceled or a trial ends without one. The workspace becomes read-only: - You can open and preview every course, and export it as a project export or as a SCORM, cmi5 or xAPI package. - An imported course that was never exported or published has not been counted as a migration, and with no plan there is no allowance to count it against: exporting it uses a [migration credit](https://scormbusters.com/help/plans-and-limits), which you can still buy. Courses you built, and imported courses already counted, never need one. - You cannot edit, publish, create or import courses, or open new review links. This lasts for at least 90 days from the day the subscription ended; **Settings → Plan & billing** shows the date. Subscribe again at any time and editing comes straight back, with everything where you left it. Tip: Before you cancel, download the library from Settings → Library export. It takes a few minutes and leaves nothing to chance. ### Exported packages do not depend on Scormbusters A package you export runs entirely in the learner's browser inside your LMS: - Every image, video and audio file the course keeps in Scormbusters is copied into the package — in blocks, inside text, in themes and on Scenes slides — so nothing is loaded from Scormbusters when a learner takes it. - The player in the package talks only to the LMS (or, for cmi5 and xAPI, the learning record store the LMS gives it at launch). It never contacts Scormbusters, and needs no account, license key or subscription. - The code inside the package is MIT-licensed, so you may host, copy and redistribute it freely. Two things stay links by design: media you embedded from elsewhere on the web (a YouTube or Vimeo video), and any file that could not be read at the moment of export, which keeps its address rather than breaking the package. ### What is not in an export Exports hold courses, not your workspace's records. Learner progress, scores and completions from courses delivered by Scormbusters, review comments, version history and workspace settings are not included. Results from courses you delivered through your LMS are in your LMS. ## The project export format URL: https://scormbusters.com/help/project-export Last updated: 2026-10-08 What is inside a Scormbusters project export: project.json, the media folder and the JSON Schema — how courses, Scenes slides, triggers, question pools and translations are written, and how to import one back. ### What is in the zip - `project.json` — the whole course. - `media/` — every file the course keeps in Scormbusters storage. - `opencourse-course.schema.json` — the JSON Schema for `project.json`, also published at [/formats/opencourse-course.schema.json](https://scormbusters.com/formats/opencourse-course.schema.json). - `README.md` — a short description of the above. ### How project.json is written The file starts with `"format": "opencourse.course"` and `"version": 2`, then `course` and `media`. - **Field names are Scormbusters' own column names**, such as `passing_score`, `question_pool_size` or `visible_by_default`, so nothing is renamed between the product and the file. - **Nesting says what belongs to what**: `course.modules[].lessons[].blocks[]` for block lessons; `course.scenes.slides[].layers[]` and `.objects[]`, `course.scenes.masters[]` and `course.scenes.variables[]` for a Scenes course; `course.objectives`, `course.locales` and `course.translations` alongside. - **Array position is the order.** There are no sort fields to keep consistent. - **`id` fields are references within the file**: a trigger names the slide it jumps to and the layer it shows by id, a flow graph names lessons, a translation names the block it translates, a lesson lists the `objective_ids` it teaches. ### Media Each file in `media/` is named `<8 characters>-`. Wherever the course used the file — a block's `url`, an `` inside a paragraph's HTML, a slide background — `project.json` says `media/`. The `media` list at the end gives each file's size, type and SHA-256. Media embedded from elsewhere on the web stays a web address. ### Question pools, triggers and the rest - A block lesson's question pool is `question_pool_size` on the lesson: each attempt shows every non-question block and that many of its question blocks. - A Scenes slide pool is `settings.draw` on the slide: `{ "group": …, "pick": … }`. - Scenes objects carry their `states`, `triggers`, animations, timeline and accessibility fields as stored; variables are listed under `course.scenes.variables` and triggers refer to them by name. - The course's theme, settings, pass mark, certificate and completion email are fields on `course`. ### Importing a project export Choose **Import** on the Courses page and pick the `.opencourse.zip`. It becomes a new draft course: every id is reassigned and every reference rewritten, so importing the same file twice gives two independent courses, and the media is uploaded to your workspace. Bringing back your own course is not a migration and is never counted. From a library export, zip one course's folder and import that zip. Older `.opencourse.json` files (format version 1, block lessons only) still import too. ### Editing the file by hand `project.json` is plain, pretty-printed JSON, so it diffs well in version control and can be generated by a script. Rows you add need no `id` — one is assigned on import. On import every field is checked against its type and anything the format does not define is ignored, so a file cannot change who owns the course or who may edit it. # Documentation (full text) ## LTI 1.3 setup https://scormbusters.com/docs/lti (last reviewed 2026-10-05) # LTI 1.3 Setup (beta) Scormbusters supports LTI 1.3 launches, which means learners can launch courses directly from Canvas, Moodle, Blackboard, or any LTI 1.3-compliant LMS without creating a separate Scormbusters account. On the hosted service, LTI delivery is an **Enterprise plan feature**: every LTI launch serves the learner from Scormbusters' infrastructure, so it is priced with learner volume in mind. SCORM and HTML5 export reach any LMS on every plan. **Verified end to end against Canvas and Moodle 5.2.3** (5 October 2026): OIDC login, signed launch, automatic learner provisioning, and **grade passback (Assignment and Grade Services)** — passing and failing scores, with the failure's comment, arrive in each gradebook; on Canvas both as an assignment and as a module item. The Canvas run used Instructure's open-source canvas-lms. The runs are automated (`npm run probe:canvas:lti`, `probe:moodle:lti`, and a strict spec check against saLTIre), so they are repeated rather than remembered. LTI stays **beta** until Blackboard is tested. Deep Linking is **not implemented**. --- ## Table of contents 1. [How it works](#how-it-works) 2. [Step 1 — Register your LMS in Scormbusters](#step-1--register-your-lms-in-scormbusters) 3. [Step 2 — Register Scormbusters in your LMS](#step-2--register-scormbusters-in-your-lms) - [Canvas](#canvas) - [Moodle](#moodle) - [Blackboard](#blackboard) 4. [Step 3 — Add a course link in your LMS](#step-3--add-a-course-link-in-your-lms) 5. [What learners experience](#what-learners-experience) 6. [Grades and completion](#grades-and-completion) 7. [Troubleshooting](#troubleshooting) --- ## How it works LTI 1.3 is an industry standard for embedding learning tools inside an LMS. The flow: 1. Learner clicks a course link inside Canvas (or Moodle, etc.) 2. The LMS sends a signed JWT to Scormbusters' launch endpoint 3. Scormbusters verifies the JWT, looks up or creates the learner's account, and redirects them to the course player 4. Progress, scores and completion are recorded in Scormbusters, and — when the platform offered AGS in the launch — the final score is posted back to the LMS gradebook on completion No separate login. No password. The learner's LMS session carries through. --- ## Step 1 — Register your LMS in Scormbusters **Settings → LTI Integration** (owner only) You'll need the following values from your LMS (collected in Step 2): | Field | Description | |-------|-------------| | Platform name | A label for your own reference, e.g. "Canvas Production" | | Issuer | The LMS's issuer URL, e.g. `https://canvas.instructure.com` | | Client ID | The client ID assigned by the LMS when you register Scormbusters | | JWKS URL | The LMS's public key endpoint — used to verify signed JWTs | | Auth endpoint | The LMS's OIDC auth endpoint | | Token endpoint | The LMS's token endpoint | | Deployment ID | The deployment ID from the LMS. **Required for Blackboard**, and whenever more than one workspace registers the same issuer and client ID: launches are routed to a workspace by issuer + client ID + deployment ID, and Scormbusters refuses a launch it cannot route unambiguously rather than guess. | After saving, Scormbusters shows you three values to configure in your LMS: | Value | Where to find it | |-------|-----------------| | **Tool URL / Launch URL** | `https://yourdomain.com/api/lti/launch` | | **Login URL (OIDC initiation)** | `https://yourdomain.com/api/lti/login` | | **Public JWKS URL** | `https://yourdomain.com/api/lti/jwks?orgId=` | Copy the JWKS URL exactly as Settings → LTI Integration shows it — it carries your organization's id. Keys are served per organization, so the bare `/api/lti/jwks` returns an empty key set and the LMS will reject every grade passback. Registering a platform also creates your organization's signing key if it does not have one yet. | **Redirect URI** | `https://yourdomain.com/api/lti/launch` | --- ## Step 2 — Register Scormbusters in your LMS ### Canvas 1. **Admin → Developer Keys → + Developer Key → LTI Key** 2. Configure: - **Key Name**: Scormbusters (or your preferred label) - **Redirect URIs**: `https://yourdomain.com/api/lti/launch` - **Method**: Manual Entry - **Title**: Scormbusters - **Target Link URI**: `https://yourdomain.com/api/lti/launch` - **OpenID Connect Initiation URL**: `https://yourdomain.com/api/lti/login` - **JWK Method**: Public JWK URL → `https://yourdomain.com/api/lti/jwks?orgId=` - **LTI Advantage Services**: enable "Can retrieve user data", "Can create and view assignment data in the gradebook" 3. Save, then toggle the key to **On** 4. Copy the **Client ID** (numeric value shown in the key list) 5. **Admin → Settings → Apps → View App Configurations → + App** - Configuration Type: By Client ID - Client ID: paste the value from step 4 6. Note the **Deployment ID** shown after installation Now go back to Scormbusters Settings → LTI Integration and fill in: - **Issuer**: `https://canvas.instructure.com` — the same for every Instructure-hosted Canvas, whatever your school's domain. Not your institution's URL: Canvas does not send it, and the launch will fail with "Platform not found". - **Client ID**: from step 4 - **JWKS URL**: `https://sso.canvaslms.com/api/lti/security/jwks` - **Auth endpoint**: `https://sso.canvaslms.com/api/lti/authorize_redirect` - **Token endpoint**: `https://sso.canvaslms.com/login/oauth2/token` - **Deployment ID**: from step 6 Instructure moved these three endpoints from `canvas.instructure.com` to `sso.canvaslms.com`; the old domain still answers for now, but Instructure has said it will stop. Canvas's **beta** and **test** environments are separate platforms with their own values — issuer `https://canvas.beta.instructure.com` / `https://canvas.test.instructure.com` and endpoints on `sso.beta.canvaslms.com` / `sso.test.canvaslms.com` — so register each environment you launch from as its own platform (the Client ID is shared). Self-hosted Canvas uses whatever issuer and domain its operator configured. For grade passback, add Scormbusters to a course as an **assignment** (Canvas then names the gradebook column in the launch) or as a module item (Scormbusters finds or creates its own column, which needs the line item scope). --- ### Moodle 1. **Site Administration → Plugins → External tool → Manage tools → Configure a tool manually** 2. Configure: - **Tool URL**: `https://yourdomain.com/api/lti/launch` - **LTI version**: LTI 1.3 - **Client ID**: leave blank (Moodle generates one) - **Public keyset URL**: `https://yourdomain.com/api/lti/jwks?orgId=` - **Initiate login URL**: `https://yourdomain.com/api/lti/login` - **Redirect URI**: `https://yourdomain.com/api/lti/launch` 3. Save. Moodle will display a **Client ID** and configuration details. 4. Copy the Moodle-provided values back into Scormbusters Settings → LTI Integration: - **Issuer**: your Moodle URL, e.g. `https://moodle.yourschool.edu` - **Client ID**: from step 3 - **JWKS URL**: `https://moodle.yourschool.edu/mod/lti/certs.php` - **Auth endpoint**: `https://moodle.yourschool.edu/mod/lti/auth.php` - **Token endpoint**: `https://moodle.yourschool.edu/mod/lti/token.php` - **Deployment ID**: shown in Moodle tool configuration --- ### Blackboard Blackboard registers tools centrally: the tool is an application on Blackboard's developer portal, and each Blackboard site installs it by that application's ID. Blackboard checks grade passback against the key set the application lists — and Scormbusters' keys are per workspace — so **each workspace registers its own (free) application**: 1. At [developer.blackboard.com](https://developer.blackboard.com), register an application with your values from Settings → LTI Integration: - **Login Initiation URL**: `https://yourdomain.com/api/lti/login` - **Tool Redirect URL(s)**: `https://yourdomain.com/api/lti/launch` - **Tool JWKS URL**: `https://yourdomain.com/api/lti/jwks?orgId=` - Signing algorithm RS256. Note the **Application ID**. 2. In Blackboard Learn: **System Admin → Integrations → LTI Tool Providers → Register LTI 1.3/Advantage Tool**, paste the Application ID as the **Client ID**, and save. Blackboard shows a **Deployment ID** — copy it. Allow the tool to send user name and email, and enable grade service access (Assignment and Grade Services) so scores can post back. 3. In Scormbusters, add the platform: - **Issuer**: `https://blackboard.com` — the same for every Blackboard site - **Client ID**: the Application ID - **Auth Login URL**: `https://developer.blackboard.com/api/v1/gateway/oidcauth` - **Auth Token URL**: `https://developer.blackboard.com/api/v1/gateway/oauth2/jwttoken` - **JWKS URL**: `https://developer.blackboard.com/api/v1/management/applications//jwks.json` - **Deployment ID**: from step 2 — **required**: every Blackboard site shares the issuer, so the deployment ID is what routes launches to your workspace. Blackboard has not yet been verified against a live Blackboard Learn site; its published keys are confirmed to load in Scormbusters' verifier. --- ## Step 3 — Add a course link in your LMS Once the tool is registered, instructors add an activity that tells Scormbusters which course to open, via the custom parameter the launch route reads: ``` course_id= ``` **Canvas:** Add an External Tool assignment or module item, select Scormbusters, and add `course_id=` under Custom Fields on the tool configuration (or per-assignment custom parameters). **Moodle:** Add an External Tool activity, select Scormbusters, and put `course_id=` in the activity's Custom parameters box. The course UUID is shown in the course editor URL (`/courses//edit`). If no `course_id` is sent, Scormbusters falls back to the LMS resource link id, which usually will not match a course — always set it. --- ## What learners experience 1. Learner clicks the course link in their LMS 2. They are silently authenticated — no Scormbusters login screen 3. They complete the course in the Scormbusters player 4. Their progress and score are recorded in Scormbusters' analytics and reports First-time learners get a Scormbusters account created automatically, linked to their LMS identity (not to their email address — an LMS-claimed email is never used to sign in to an existing Scormbusters account). **Embedded (iframe) launches depend on third-party cookies.** Safari and some privacy-hardened browsers block them, in which case the learner sees a Scormbusters login screen inside the frame. Configure the LMS activity to open in a new tab or window if your learners hit this. --- ## Grades and completion Grade passback (LTI Advantage Assignment and Grade Services) **is implemented**. When the platform includes the `lti-ags` endpoint claim in the launch token (in Moodle: enable *IMS LTI Assignment and Grade Services* in the tool's Services; in Canvas: scopes are granted by the developer key), Scormbusters stores the offer at launch and, when the learner finishes the course, posts a score to the gradebook: - `scoreGiven` / `scoreMaximum` — the final percentage out of 100 (omitted for unscored courses, which still report completion) - `activityProgress: Completed`, `gradingProgress: FullyGraded` - posted with an OAuth2 client-credentials token obtained via a signed JWT assertion (the same org key your JWKS endpoint publishes) If the launch names a specific line item it is used; otherwise Scormbusters finds or creates one for the resource link (this needs the `lineitem` scope, not just `score`). Scores also remain in Scormbusters' own Analytics regardless. Launches without the AGS claim behave exactly as before — nothing is posted. --- ## Troubleshooting **"No active session found" error on launch** The OIDC login → launch flow didn't complete correctly. Check that your Login URL (`/api/lti/login`) and Redirect URI (`/api/lti/launch`) match exactly what's registered in the LMS — including the protocol (`https://`). **"Platform not found" error** The `iss` (issuer) and `client_id` in the JWT don't match any registered platform in Scormbusters. Verify the Issuer field in Settings → LTI Integration matches what the LMS sends exactly. **"Nonce already used" or "Nonce expired"** LTI nonces expire after 10 minutes and are single-use. This usually means the launch is being replayed (e.g., a cached page). Ensure the launch URL is not being cached. **JWT signature verification failed** Scormbusters fetches the LMS's public keys from the JWKS URL to verify launch JWTs. Check that the JWKS URL is reachable from your Scormbusters server. If you're running locally, the LMS may not be able to reach your dev server. ## Webhooks https://scormbusters.com/docs/webhooks (last reviewed 2026-10-03) # Webhooks Scormbusters sends HTTP POST requests to your configured endpoints when course lifecycle events occur. Use webhooks to sync completion data to your HR system, trigger Slack notifications, update a data warehouse, or integrate with any external service. --- ## Table of contents 1. [Setting up a webhook](#setting-up-a-webhook) 2. [Security — verifying signatures](#security--verifying-signatures) 3. [Payload envelope](#payload-envelope) 4. [Events reference](#events-reference) 5. [Delivery behavior](#delivery-behavior) 6. [Delivery logs](#delivery-logs) --- ## Setting up a webhook **Settings → API Keys & Webhooks** (owner or admin required) 1. Click **Add webhook** 2. Enter your endpoint URL (`https://your-server.com/hooks/scormbusters`) 3. Select the events you want to receive 4. Copy the generated **signing secret** — it's shown once Your endpoint must: - Accept `POST` requests - Return a `2xx` status code within 10 seconds - Be reachable from the internet (localhost won't work in production) --- ## Security — verifying signatures Every request includes an `X-OpenCourse-Signature` header with an HMAC-SHA256 signature of the raw request body, using your webhook's signing secret. **Always verify this signature before processing the payload.** Without verification, anyone who discovers your endpoint URL can send fake events. ### Verification examples **Node.js / TypeScript:** ```typescript import crypto from "crypto"; function verifyWebhook( rawBody: string, signature: string, secret: string ): boolean { const expected = "sha256=" + crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } // In your Express handler: app.post("/hooks/scormbusters", express.raw({ type: "*/*" }), (req, res) => { const sig = req.headers["x-opencourse-signature"] as string; if (!verifyWebhook(req.body.toString(), sig, process.env.WEBHOOK_SECRET!)) { return res.status(401).send("Invalid signature"); } const event = JSON.parse(req.body.toString()); // process event... res.sendStatus(200); }); ``` **Python:** ```python import hmac, hashlib def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool: expected = "sha256=" + hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected) ``` --- ## Payload envelope All events share the same outer envelope: ```json { "event": "enrollment.completed", "timestamp": "2026-04-21T14:23:00.000Z", "data": { // event-specific fields } } ``` | Field | Type | Description | |-------|------|-------------| | `event` | string | Event type (see below) | | `timestamp` | ISO 8601 string | When the event was generated | | `data` | object | Event-specific payload | --- ## Events reference ### `course.published` Fired when a course status changes to `"published"`. ```json { "event": "course.published", "timestamp": "2026-04-21T14:00:00.000Z", "data": { "courseId": "uuid", "status": "published" } } ``` --- ### `enrollment.created` Fired when a learner enrolls in a course. ```json { "event": "enrollment.created", "timestamp": "2026-04-21T14:05:00.000Z", "data": { "courseId": "uuid", "userId": "uuid" } } ``` --- ### `lesson.completed` Fired each time a learner completes a lesson. ```json { "event": "lesson.completed", "timestamp": "2026-04-21T14:10:00.000Z", "data": { "courseId": "uuid", "lessonId": "uuid", "userId": "uuid", "score": 85, "maxScore": 100 } } ``` `score` and `maxScore` are `null` if the lesson has no scored content. --- ### `enrollment.completed` Fired when a learner completes all lessons in a course (via the learner player) or when a completion is recorded directly via the API. ```json { "event": "enrollment.completed", "timestamp": "2026-04-21T14:20:00.000Z", "data": { "courseId": "uuid", "userId": "uuid", "status": "passed", "score": 85, "maxScore": 100 } } ``` | `status` value | Meaning | |----------------|---------| | `"passed"` | Learner met the course's passing score threshold | | `"failed"` | Learner completed all lessons but did not meet the passing score | | `"completed"` | Learner completed all lessons; course has no scored content | `score` and `maxScore` are `null` if the course has no scored content. --- ### `course.unpublished` Fired when a published course is taken back to draft (or archived). It fires only on a real transition — republishing an already-published course emits nothing, and archiving a draft is not an unpublish. ```json { "event": "course.unpublished", "timestamp": "2026-10-03T09:00:00.000Z", "data": { "courseId": "uuid", "status": "draft" } } ``` --- ### `quiz.submitted` Fired when the server grades a learner's answer to a question block. One event per graded submission, including retries (see `attemptNumber`). ```json { "event": "quiz.submitted", "timestamp": "2026-10-03T09:05:00.000Z", "data": { "courseId": "uuid", "lessonId": "uuid", "blockId": "uuid", "userId": "uuid", "isCorrect": true, "score": 1, "maxScore": 1, "attemptNumber": 1 } } ``` --- ### `certificate.issued` Fired when a learner **first earns** a certificate: they pass a course that has certificates enabled. A repeat pass does not fire it again, and a later failed attempt never revokes it (completions keep the best result). ```json { "event": "certificate.issued", "timestamp": "2026-10-03T09:10:00.000Z", "data": { "courseId": "uuid", "userId": "uuid", "certificateId": "uuid", "score": 92 } } ``` `certificateId` is the id behind the public `/verify/` page. --- ### `user.joined` and `invite.accepted` Both fire when someone accepts an organization invite; `invite.accepted` is the invite-centric view, `user.joined` the member-centric one. ```json { "event": "user.joined", "timestamp": "2026-10-03T09:15:00.000Z", "data": { "userId": "uuid", "email": "person@example.com", "role": "member" } } ``` ```json { "event": "invite.accepted", "timestamp": "2026-10-03T09:15:00.000Z", "data": { "userId": "uuid", "role": "member" } } ``` --- ### `user.removed` Fired when an owner or admin removes a member from the organization. ```json { "event": "user.removed", "timestamp": "2026-10-03T09:20:00.000Z", "data": { "userId": "uuid", "role": "member" } } ``` --- ## Delivery behavior - Webhooks are fired **fire-and-forget** — they don't block the learner's request - Timeout: **10 seconds** per delivery attempt - **No automatic retry** on failure — failed deliveries are logged (see below) but not retried - If your endpoint returns a non-2xx status, the delivery is logged as failed > If you need guaranteed delivery, log the incoming webhook immediately and process it asynchronously. Return `200` as fast as possible. --- ## Delivery logs **Settings → API Keys & Webhooks → View deliveries** Each delivery log shows: - Event type - Timestamp - Response status from your endpoint - Response body (first 500 characters) - Duration in milliseconds - Success / failure Use delivery logs to debug endpoint issues or confirm that events are being received. ## xAPI / LRS integration https://scormbusters.com/docs/xapi (last reviewed 2026-10-03) # xAPI / Tin Can Integration Scormbusters can forward learning activity to any xAPI-compatible Learning Record Store (LRS). This lets you aggregate data from Scormbusters alongside other tools in a central LRS for reporting and analytics. --- ## Table of contents 1. [What is xAPI?](#what-is-xapi) 2. [Configuration](#configuration) 3. [Statements sent](#statements-sent) 4. [Statement schemas](#statement-schemas) 5. [Supported LRS providers](#supported-lrs-providers) --- ## What is xAPI? xAPI (Experience API, also called "Tin Can") is a standard for recording learning activity as **statements** — structured JSON objects in the form *"actor did verb to object."* Statements are stored in an LRS. Example: `"Alice completed Lesson 1 in Safety Training, scoring 85 out of 100."` xAPI is especially useful if you need: - A single analytics view across multiple learning tools - Long-term compliance records - Custom reporting beyond what Scormbusters' built-in analytics provides --- ## Configuration **Settings → xAPI / LRS** (owner only) | Field | Description | |-------|-------------| | **LRS Endpoint** | Base URL of your LRS, e.g. `https://lrs.yourcompany.com/xapi` — must be HTTPS | | **Auth token** | Credentials in `username:password` format — sent as `Basic` authorization header | Click **Test connection** to verify Scormbusters can reach your LRS before saving. Once configured, all lesson completions and course completions are forwarded automatically. There is nothing to enable per-course. > **Security:** The LRS endpoint is validated server-side. Private IP ranges (localhost, 10.x, 192.168.x, etc.) are blocked to prevent server-side request forgery. --- ## Statements sent Scormbusters sends two types of xAPI statements: | Event | Verb | Activity type | |-------|------|--------------| | Learner completes a lesson | `completed` | `lesson` | | Learner passes a course | `passed` | `course` | | Learner fails a course | `failed` | `course` | | Learner finishes a course with no scored content | `completed` | `course` | Statements are sent **best-effort** — if the LRS is unreachable, the error is logged but the learner's session is not interrupted. --- ## Statement schemas All statements use xAPI 1.0.3. ### Lesson completed ```json { "actor": { "objectType": "Agent", "name": "Alice Smith", "mbox": "mailto:alice@company.com" }, "verb": { "id": "http://adlnet.gov/expapi/verbs/completed", "display": { "en-US": "completed" } }, "object": { "objectType": "Activity", "id": "https://yourdomain.com/courses//lessons/", "definition": { "name": { "en-US": "Introduction to Safety Procedures" }, "type": "http://adlnet.gov/expapi/activities/lesson" } }, "result": { "completion": true, "score": { "raw": 85, "max": 100, "scaled": 0.85 } }, "context": { "contextActivities": { "parent": [ { "objectType": "Activity", "id": "https://yourdomain.com/courses/" } ] } }, "timestamp": "2026-04-21T14:10:00.000Z" } ``` `result.score` is omitted if the lesson has no scored content. --- ### Course passed ```json { "actor": { "objectType": "Agent", "name": "Alice Smith", "mbox": "mailto:alice@company.com" }, "verb": { "id": "http://adlnet.gov/expapi/verbs/passed", "display": { "en-US": "passed" } }, "object": { "objectType": "Activity", "id": "https://yourdomain.com/courses/", "definition": { "name": { "en-US": "Safety Training Fundamentals" }, "type": "http://adlnet.gov/expapi/activities/course" } }, "result": { "completion": true, "success": true, "score": { "raw": 85, "max": 100, "scaled": 0.85 } }, "timestamp": "2026-04-21T14:20:00.000Z" } ``` For a **failed** course, the verb is `http://adlnet.gov/expapi/verbs/failed` and `result.success` is `false`. For a course with **no scored content**, the verb is `completed` and `result.score` is omitted. --- ### Actor resolution The actor `name` comes from the learner's `full_name` in their Scormbusters profile (falls back to `"Learner"` if not set). The `mbox` is their email address. --- ## Supported LRS providers Scormbusters has been tested with the following LRS providers: | Provider | Notes | |----------|-------| | [SCORM Cloud](https://scorm.com/scorm-cloud/) | Widely used, free tier available | | [Watershed](https://watershedlrs.com) | Strong analytics and reporting | | [Learning Locker](https://learninglocker.net) | Open source, self-hostable | | [Veracity](https://veracity.it) | Enterprise-focused | Any LRS that implements the xAPI 1.0.3 specification and accepts statements via `POST /statements` with Basic authentication will work. ## LMS compatibility https://scormbusters.com/docs/lms-compatibility (last reviewed 2026-10-03) # LMS compatibility & conformance This page tracks how Scormbusters exports are verified. The policy: **no green check without a receipt** — a claim appears here only with the evidence that produced it. ## Standards conformance | Standard | Status | Evidence | |---|---|---| | SCORM 1.2 | Spec-conformant in code | 100+ package tests: manifest schema, API call order, status vocabulary, suspend-data limits, cross-session resume, `cmi.interactions` | | SCORM 2004 3rd Ed. | Spec-conformant in code; **full-course export verified on SCORM Cloud 2026-09-24**; probe passed on Moodle 4.5, 2026-09-17 (smoke test — see note) | Same suite: dual completion/success status, `cmi.score.scaled`, sequencing namespaces. Moodle documents its native SCORM 2004 support as incomplete, so the Moodle run verifies the data model and API calls, not SCORM 2004 conformance; the conformance claim rests on SCORM Cloud. | | SCORM Cloud validation | **SCORM 1.2 probe verified 2026-09-17; full-course exports verified under SCORM 1.2 and SCORM 2004 2026-09-24** | Probe: 22 checks against a live registration, results below. Full course: a real multi-lesson export with a quiz, walked like a learner by the automated runner — registration recorded completed / passed / score 100 under both standards, and a deliberately failed attempt recorded failed with the remediation path shown. | | LTI 1.3 launch + AGS grade passback | **Verified on Canvas and Moodle 5.2.3, 2026-10-05** (beta until Blackboard) | OIDC login, JWKS, nonce replay protection, provisioned learner sign-in; AGS score passback on completion. Automated end-to-end run: passing and failing learners' scores both land in Moodle's gradebook — results below. No Deep Linking. | | xAPI statement forwarding | Implemented | Statements forwarded to the LRS endpoint configured for the organization | ## Per-LMS verification matrix Practitioners know that "SCORM-conformant" and "works in my LMS" are different claims — Cornerstone, SumTotal, and Moodle each have documented quirks that break conformant packages. This matrix records real imports into real LMS instances. Empty cells mean **not yet verified**, not "broken". | LMS | SCORM 1.2 | SCORM 2004 | LTI 1.3 | Notes | |---|---|---|---|---| | SCORM Cloud | ✅ probe 2026-09-17 + 2026-10-03, full course 2026-09-24 + 2026-10-03 | ✅ probe 2026-10-03, full course 2026-09-24 + 2026-10-03 | n/a | Pre-opens the session; reports `entry` as empty on resume. Both handled. Full-course runs are automated (`scripts/lms-probe/run-scorm-cloud.mjs`). | | Moodle 4.5 | ✅ 2026-09-17 | ⚠️ probe passed 2026-09-17 — smoke test only, see note | — | Automated — `npm run probe:moodle`. Same two quirks as SCORM Cloud. Moodle's own docs call its native SCORM 2004 support unsupported/incomplete (no sequencing), so a passing probe there does not establish 2004 conformance. | | Moodle 5.2.3 | ✅ package replacement 2026-10-07 | — | ✅ launch + AGS 2026-10-05 | Automated — `npm run probe:moodle:lti` (registration, launch, provisioning, grade passback) and `npm run probe:moodle:replace` (an imported course replacing its original keeps completions and grades); see below. | | saLTIre (ceLTIc platform emulator) | n/a | n/a | ✅ launch + AGS 2026-10-05 | Strict, schema-validating second implementation. Automated — `npm run probe:saltire:lti`. Both line item paths; see below. | | Canvas (open-source canvas-lms, 2026-04-30) | — | — | ✅ launch + AGS 2026-10-05 | Assignment and module-item placements. Automated — `npm run probe:canvas:lti` in a Codespace; see below. | | Blackboard | — | — | — | | | Cornerstone | — | — | — | | | TalentLMS | — | — | — | | | Docebo | — | — | — | | ## SCORM Cloud — SCORM 1.2, 17 September 2026 Run with the conformance probe (`npm run build:probe`) against a live registration on SCORM Cloud, the engine written by the authors of the spec. A failure here is ours, not the platform's, which is why it is the first platform tested and the only one where "the LMS is wrong" is never the explanation. **Result: all data-model checks passed.** Two behaviours differ from a naive reading of the spec, and both are now handled in the driver with tests. | Check | Result | |---|---| | API discovered | pass — 1 frame up | | Learner name and id supplied | pass | | `lesson_location` round-trip | pass | | `suspend_data` round-trip at 256 / 512 / 1024 / 4096 chars | pass at every size | | `suspend_data` meets the spec floor | pass — 4096 chars survived, which is the SCORM 1.2 requirement | | `lesson_status` = incomplete / completed / passed | pass | | `score.raw`, `score.min`, `score.max` | pass | | `session_time` accepted | pass — `0000:02:30.00` | | `cmi.interactions` write | pass | | Invalid element reports an error | pass — 201, "Invalid argument error" | | `Commit` | pass | | **Resume after a full relaunch** | **pass** — `suspend_data` and `lesson_location` both survived | | Registration state at the LMS | completion COMPLETED, success PASSED, score 75 | ## SCORM Cloud — full-course exports, 24 September 2026 The probe proves the driver; it does not prove a real export. On 2026-09-24 a real multi-lesson course with a graded quiz was exported under each standard and walked like a learner by the automated runner (`scripts/lms-probe/run-scorm-cloud.mjs`, which imports the zip, launches it in SCORM Cloud, clicks through every lesson and answers the quiz): | | SCORM 1.2 | SCORM 2004 3rd Ed. | |---|---|---| | Import accepted | pass | pass | | Launches and plays | pass | pass | | Completion recorded | COMPLETED | COMPLETED | | Success recorded | PASSED | PASSED | | Score recorded | 100 | 100 | | Deliberate wrong answers | FAILED recorded, remediation path shown | FAILED recorded, remediation path shown | Worth recording rather than hiding: this run is what *first made exports work in a real LMS*. Until that day every lesson was packaged as its own SCO (so the player never initialized and nothing was ever recorded), branching dropped quiz scores, and media was never bundled. The whole class of defect is why this page's policy exists — the unit suite was green throughout. ## SCORM Cloud — re-verified 3 October 2026 Re-run with the then-current exporter (after slide masters, per-object language, cmi5/xAPI format parity and the audit-trail work landed): a fresh single-lesson course with a graded multiple-choice question, exported under both standards and walked by the automated runner. Both registrations recorded **completion COMPLETED, success PASSED, score 100**. The 68-check probe was also run on SCORM Cloud under both standards the same day (the 2004 probe's first SCORM Cloud run — 2026-09-17 covered 1.2 there and 2004 only on Moodle). SCORM 1.2: all checks pass, same two known quirks. SCORM 2004: every data-model, interaction and resume check passes — including `entry = "resume"`, which 1.2 leaves empty — with one new observation: SCORM Cloud reads `cmi.success_status` back as `"unknown"` within the session even after accepting a write of `"passed"`, and a probe-style session that never re-terminates after resume is left UNKNOWN at the registration. Real exports are unaffected (the full-course walk above records PASSED under 2004): the driver writes status and never depends on reading it back. Recorded here so nobody mistakes the probe's read-back line for an export defect. ### Two things worth knowing about SCORM Cloud **It opens the session before the content does.** `LMSInitialize` returns `"false"` to the content, because the session is already open — not because anything failed. Every subsequent call works normally. Content that treats a false return as fatal will break on the reference implementation, which is a sharp edge worth knowing about if you are writing your own player. Our driver asks `LMSGetLastError` whether the session is usable rather than trusting the return value, and warns the learner only when it genuinely is not. **`cmi.core.entry` is empty on resume, not `"resume"`.** A player that decides whether to restore progress by reading `entry` will start a returning learner from the beginning. Ours reads `lesson_location` and `suspend_data` directly and never consults `entry`. Both are recorded as regression tests in `packages/scorm/src/__tests__/scorm-driver.test.ts`. ## Moodle 4.5 — SCORM 1.2 and 2004, 17 September 2026 **What the 2004 column here does and does not show.** Moodle's own documentation ([SCORM FAQ](https://docs.moodle.org/500/en/SCORM_FAQ)) says Moodle is not fully SCORM 2004 compliant — it implements the 2004 run-time data model but not sequencing and navigation. Our 2004 probe passing in Moodle therefore shows that the exported package launches, that the data model round-trips (including `score.scaled` and the 64,000-character `suspend_data` floor) and that resume works **in Moodle** — a useful smoke test, not SCORM 2004 conformance. The 1.2 columns are the verified claim; 2004 verification belongs to SCORM Cloud, where the full-course run passed on 2026-09-24 (table above). Run against a Moodle installed from scratch in Docker, driven end to end in headless Chromium: log in, create a course, upload the package through Moodle's file picker, launch, read the report, relaunch to test resume. No step is manual, so this is the one platform where a regression is caught here rather than reported by a customer. ```bash npm run build:probe && npm run probe:moodle:up npm run probe:moodle -- scorm12 npm run probe:moodle -- scorm2004 ``` | | SCORM 1.2 | SCORM 2004 3rd Ed. | |---|---|---| | Checks passed | 22 | 46 | | Failures | **0** | **0** | | Warnings | 2 (both expected, below) | 2 (both expected, below) | | `suspend_data` ceiling reached | 4,096 chars — the full 1.2 spec floor | 64,000 chars — the full 2004 spec floor | | Resume across a relaunch | `suspend_data` and `lesson_location` both survived | survived | | `cmi.interactions` | accepted; read back empty, which 1.2 permits | accepted and read back (`probe-q1`) | | Invalid element reports an error | 201, "Invalid argument error" | 401, "Undefined Data Model" | | Completion / success / score | recorded correctly | recorded correctly, including `score.scaled` | Moodle reopens a **completed** attempt in `review` mode on relaunch, which is correct — the probe finishes the course on its first pass, so the second launch is a review of a finished attempt rather than a resume. A learner who leaves mid-course gets `normal` mode and their state back; that is the 1.2 row above, where the probe stops short of completion. ### The same two quirks appear on both platforms That SCORM Cloud and Moodle — independent implementations, one of them the reference — both do these things makes them properties of the category, not one vendor's bug: **Initialize returns false because the session is already open.** Moodle reports it as error 101 ("General exception") under SCORM 1.2 and 103 ("Already Initialized") under 2004; SCORM Cloud returns false with no error at all. Three different signals for one situation, which is why the driver asks whether the session *works* — it reads a value the LMS always supplies and checks whether that read errored — instead of trying to interpret the return code. **`cmi.core.entry` is empty on resume rather than `"resume"`.** On both platforms. A player that decides whether to restore progress by reading `entry` sends every returning learner back to slide one, on the two most common SCORM hosts in the world. Ours reads `lesson_location` and `suspend_data` directly. ## Moodle 5.2.3 — LTI 1.3 launch and grade passback, 5 October 2026 SCORM proves the packages; LTI is hosted delivery, so it gets its own run. `scripts/lms-probe/run-moodle-lti.mjs` stands it up end to end with nothing typed by hand: it registers Scormbusters in Moodle as an LTI 1.3 tool with grade sync, registers Moodle in Scormbusters **through the same API the settings page uses, signed in as the organization's owner**, then launches as two Moodle students. One answers the course's graded question correctly, one does not, and both mark the course complete. It then reads Moodle's gradebook. | Check | Result | |---|---| | OIDC login → platform auth request | pass — a GET, as the spec expects | | Signed launch verified, learner provisioned and signed in | pass — no Scormbusters login screen | | Launch lands on the player | pass — a GET | | Passing learner's score in the Moodle gradebook | pass — **100** | | Failing learner's score in the Moodle gradebook | pass — **0**, with the comment "Did not reach the passing score" | | Learner names passed through from Moodle | pass | Worth recording rather than hiding, as with the SCORM exports: **the first run is what made grade passback work for anyone who followed our own setup screen.** Three defects, each invisible to the unit suite: - Nothing in the product ever created the organization's signing key, so the token request grade passback depends on could not be signed. Registering a platform now creates the key. - The JWKS URL the settings page (and this documentation) told admins to register returned an empty key set — keys are served per organization and the URL lacked the organization's id. Both now show the full URL. - Both handshake redirects were 307s, which re-POST. The hop to the platform's auth endpoint has to be a GET: a cross-site POST does not carry an LMS session cookie set `SameSite=Lax`, which is how Moodle sets it. Both are now 303s. Launches had worked throughout; grades silently never arrived. That is the whole case for running this against a real LMS rather than trusting a green unit suite. Canvas and Blackboard are next — until they are verified, LTI stays labelled beta. ## saLTIre — strict LTI 1.3 + AGS conformance, 5 October 2026 Moodle is lenient: it accepted a launch handshake that broke the spec until the fix above. So the same flow was run against [saLTIre](https://saltire.lti.app), the ceLTIc project's platform emulator — an independent implementation that validates service requests against the specs' JSON schemas — reading saLTIre's own log of what it received and what it answered (`scripts/lms-probe/run-saltire-lti.mjs`). | Check | Line item named in the launch | Only the line item container offered | |---|---|---| | OIDC login → platform auth request is a GET | pass | pass | | Signed launch verified, learner provisioned | pass | pass | | Token request (our signed client assertion) | pass — 200 | pass — 200 | | Tool finds its own line item by resource link | — | pass — 200 | | Score accepted | pass — 204 | pass — 204 | | Score body | 100 / 100, Completed, FullyGraded | 0 / 100 with comment, Completed, FullyGraded | The second column is how Canvas behaves when Scormbusters is added as a module item rather than an assignment: the launch carries only the line item container, and the tool must find or create its own column. Reading that path while it ran exposed a latent defect, fixed the same day: the tool took the **first** line item the container returned. A platform that ignores the `resource_link_id` filter returns every column in the course, so a learner's score could have been written into another assignment. The tool now only uses a line item whose `resourceLinkId` matches, and otherwise creates its own. **What this does not replace.** saLTIre proves conformance to the spec, not a platform's quirks — the Canvas run below found one it could not have. ## Canvas — LTI 1.3 launch and grade passback, 5 October 2026 Instructure's own code: `instructure/canvas-lms` at commit `1c9f0bb8` (2026-04-30), built with Canvas's docker dev setup in a GitHub Codespace (recipe in `scripts/lms-probe/README.md`). Canvas is provisioned through its REST API as the site admin, exactly as a school's admin would configure it: an LTI 1.3 developer key with the AGS scopes, turned on and installed account-wide; a course with a 100-point external-tool **assignment** and a **module item**. Scormbusters registers Canvas as the org owner, with Canvas's issuer `https://canvas.instructure.com`. Three Canvas students launch. | Check | Result | |---|---| | OIDC login → Canvas `authorize_redirect` → `authorize` | pass — GETs | | Canvas-signed launch verified, learner provisioned | pass | | Assignment, passing learner — Canvas gradebook | pass — **100**, graded | | Assignment, failing learner — Canvas gradebook | pass — **0**, graded, comment "Did not reach the passing score" | | Module item — tool creates its own gradebook column | pass — "LTI Validation Course", 100 pts | | Module item, passing learner — that column | pass — **100**, graded | **Found on real Canvas, fixed the same day:** - **Module-item placements never reached the gradebook.** When Canvas names no column, the tool creates one. We bound it to the launch's resource link — standard, and accepted by Moodle and saLTIre — but Canvas binds only links that already belong to an assignment, and a module item's doesn't: it answered 404 and the grade was lost. The tool now falls back to an unbound column (Canvas's documented placeholder assignment) stamped with its own `resourceId`, so every learner of that placement finds the same column rather than each creating one. - **The launch wrote a learner session that could never be written**: an upsert against a partial unique index, which the database API cannot target, failed on every launch on every platform and was logged as a warning. Nothing read it — the player creates the real session — so the write is gone. Setting up this Canvas also confirmed our verifier refuses undersized keys: Canvas's sample dev config ships 512-bit LTI signing keys, and every launch was rejected ("RS256 requires key modulusLength to be 2048 bits or larger") until they were replaced with 2048-bit keys, as production Canvas uses. What remains untested on Canvas: Instructure's *hosted* service, which runs the same code but may run ahead of the open-source tree, and Canvas's sso.canvaslms.com endpoints (a local build serves them on its own domain). ## Shared registrations — two organizations, one LMS, 5 October 2026 Hosted Canvas sends one issuer for every school; Blackboard sends one issuer — and, when schools share a tool application, one client ID — for every site. Routing by issuer + client ID alone could not tell two Scormbusters customers apart. Run against saLTIre with two Scormbusters organizations registering the **same** issuer and client ID, separated only by deployment ID, and the **same** student launching into both: | Check | Result | |---|---| | Each organization registers the shared LMS with its deployment ID | pass — 201, 201 | | Each launch lands in its own organization's course | pass | | The student gets a separate identity and learner account per organization | pass — 2 and 2 | | No enrollment crosses organizations | pass — 0 | | Each organization records its own completion | pass | | Registering another organization's deployment ID | refused — 409 | | Login initiation for an unregistered deployment | refused — 400 | Before this, a second organization's registration made every launch for that LMS fail (two matching registrations), login initiation sent learners to whichever registration came first, the deployment ID was never saved at registration, login read a parameter name the spec doesn't use (`deployment_id` for `lti_deployment_id`), and a student shared between two customers mapped to one identity whose organization flipped on every launch. All fixed: routing is issuer + client ID + deployment ID, refused when ambiguous; identities are unique per organization (migration `20261005000100`); clashing registrations are refused without naming the other workspace. Production keys: Instructure's (sso.canvaslms.com, canvas.instructure.com, beta) and Blackboard's (developer.blackboard.com, including its RS512 key) all import cleanly in the launch verifier. ## Moodle 5.2.3 — replacing an imported course's package, 7 October 2026 "Replace the original in your LMS" exports an imported course under the identifiers of the package it came from. Moodle keeps a learner's SCORM tracking per SCO and, when an activity's package is replaced, matches the new SCOs to the old ones by identifier. Run with `npm run probe:moodle:replace`: an "original" SCORM 1.2 package (`ACME_FIRE_SAFETY_SCO`) is imported through the import page and exported twice; in Moodle a student passes two activities built on the original at 80%, and each activity's package is then replaced through the activity's own settings form. | Activity | SCO after replacement | Student's tracking | Gradebook | |---|---|---|---| | Replaced with the export that keeps the original identity | same row, `ACME_FIRE_SAFETY_SCO` | passed, 80 — still attached | 80 | | Replaced with an ordinary export (control) | new row, our item id | gone | 0 | Both activities ran the new package afterwards (revision 2). So in Moodle the option is the difference between a corrected course and one whose existing completions and grades are wiped. Not tested: other LMSs — Cornerstone and SCORM Cloud version courses their own way, and the identifiers alone do not decide what they keep. ## Reproducing this yourself The probe is a SCORM package that interrogates whatever LMS it is running in and reports what it found. It is not our player — it talks to `window.API` directly — so it measures the LMS, not us. ```bash npm run build:probe # dist/probe/opencourse-conformance-probe-scorm12.zip # dist/probe/opencourse-conformance-probe-scorm2004.zip ``` Import one into any LMS, launch it, and press "Copy the report". Relaunch to test resume. Paste the result into an issue and we will add it here, pass or fail. To contribute a verification: export a course, import it into your LMS, confirm launch, completion, score reporting, and resume, and open an issue with the LMS name/version and what you observed — pass or fail. Failures are listed here too, with workarounds when we have them. --- The public, always-current version of this page is `/scorm-conformance` on the marketing site (the domain is deployment-configured); this file is its working copy in the repository. ## Accessibility https://scormbusters.com/docs/accessibility (last reviewed 2026-10-03) # Accessibility Scormbusters treats accessibility as a property of the product, not a checkbox in a marketing table. This page states what we support, how it is enforced in code, and what is not done yet. It covers two different things, because they are different things: 1. **The output** — the courses you publish (in-app player, SCORM/HTML5 exports) that learners experience. 2. **The authoring tool** — the editor itself, which an author using a screen reader or keyboard must be able to operate. (Most vendors publish nothing about this; ATAG — the Authoring Tool Accessibility Guidelines — is the relevant standard.) ## Published output Target: **WCAG 2.1 AA**, with WCAG 2.2's dragging-movements criterion (SC 2.5.7) treated as in scope even though most of the industry formally concedes it. What is implemented and enforced by code today: - **Drag interactions work without dragging, by pointer *and* by keyboard.** Matching and sortable are select-then-place: tap the thing, tap where it goes. Dragging is one route to that, a single tap is another, Enter/Space is a third. The distinction matters and is the one most conformance reports get wrong — **SC 2.5.7 asks for a single-pointer alternative, not a keyboard one**. Someone on a head pointer or a switch-adapted mouse can press but cannot drag, and a keyboard path does nothing for them; that satisfies SC 2.1.1 and leaves 2.5.7 failing. Until 2026-09-17 this page claimed 2.5.7 on the strength of the keyboard path alone. That was wrong, and it is recorded here rather than quietly edited. The single-pointer path now exists and `apps/web/lib/__tests__/dragging-alternatives.test.ts` fails if either block loses it. The leading desktop authoring tools mark this criterion "Does Not Support" in their own reports. - **Block hotspot and categorise questions need no pointing or dragging.** `hotspot_question` is answered by choosing areas by name from radios (or checkboxes when several are right); the picture is outlined and numbered to match, and clicking an area only picks its choice. `categorize` is a labelled drop-down per item. After checking, each choice and item says in words whether it was right and where it belonged. Captivate hotspot and drag-and-drop questions import into them, and the editor's checker flags areas with no descriptive name. - **Scenes matching, sequence and hotspot questions need no dragging at all.** They are what Storyline and Captivate drag-and-drop and hotspot questions import as. Every step is a single tap on a native control — a dropdown per item, Move up / Move down buttons, a radio button per area of the picture — so they are operable by single pointer and by keyboard alike, announced by what they are, graded the same in preview and in the LMS, and reported as SCORM matching, sequencing and choice interactions. A hotspot is answered without sight by choosing among its areas by name, so preflight warns when an area is called only "Area 2" or the picture has no description. - **Captions** are rendered wherever they are stored (SC 1.2.2) — in the player and in exports. - **Focus visibility** in exported packages (SC 2.4.7). - **Correctness is never color-only** — fill-in-blank and quiz feedback carry text/iconography, not just red/green (SC 1.4.1, 1.3.3). - **Language declared** from the course locale, not hardcoded (SC 3.1.1). - **`prefers-reduced-motion`** respected in the player and exports. - **Editor-side audit**: the Scenes editor ships a WCAG audit panel (alt text, tab order, contrast, reading order) and scene objects carry first-class accessibility fields (alt text, ARIA attributes, focusability, tab order). Known gaps in the output today: - A formal, third-party-audited ACR (Accessibility Conformance Report) has not been produced yet. The intent is a WCAG-EM-scoped audit published on this site — not a PDF on a file-sharing link. - Scenes' free-form `drag_item` / `drop_zone` objects can be operated without dragging (select an item, then a zone) in both players, but they are not scored or reported to the LMS. For anything graded, use a matching or sequence question; the importers already do. ## The authoring tool itself Target: **ATAG 2.0 Part A** (the authoring UI is accessible) and **Part B** (the tool helps authors produce accessible content). On 2026-09-17 the authoring UI was audited against WCAG 2.2 AA and ATAG 2.0 Part A, and it failed several Level A criteria. What that audit found and what has been done about it, rather than a summary that flatters either: **The Scenes canvas was unusable without a mouse.** Objects rendered as bare `div`s with no tab stop, so an object could not be selected — and every other gesture in the editor, including the whole properties panel, operates on a selection. Slide and layer rows were non-focusable `onClick` divs, so there was no way to change slides. Reordering was HTML5 drag-and-drop, which is never keyboard-operable. Now: objects are tab stops that announce their type and selection state, Enter selects, Shift+Enter extends, F2 edits text, arrows move and Alt+arrows resize. Slide and layer panels are listboxes with roving tabindex — arrows navigate, Alt+arrows reorder, F2 renames, Delete removes. Tested in `apps/web/lib/__tests__/editor-keyboard.test.ts`. **About 45 Properties-panel controls had no name.** The captions beside them were `span`s, so a screen reader announced "edit blank" for X, Y, width, height, rotation, every colour and all sixteen selects. The panel's input primitives now require a name in their type signature, so a control cannot ship without one. **Text contrast failed systemically.** `text-gray-400` was the most-used text colour in the app at 2.5:1 on white, and it was also the placeholder colour — so on placeholder-labelled fields the only visible name was the least readable text on the page. The dark course sidebar reached 1.22:1. Corrected across 68 files and held by `apps/web/lib/__tests__/contrast.test.ts`, which computes the ratios rather than trusting a convention. The app now ships a dark theme (system preference by default, with a manual override). Dark is not exempt from the same bar: the design tokens live as paired light/dark values, text and surface roles are split where one value cannot pass as both (an accent that is a button ground needs 4.5:1 under white label text *and* 4.5:1 as link text on the page ground — in dark mode those constraints exclude each other, so `text-cobalt` and `bg-cobalt` resolve to different values), and the contrast test asserts every token pairing the UI uses — ink on all three grounds, white labels on every accent, accent text on grounds and washes — in **both** themes. **Nothing was ever announced.** The app-wide toast — the only feedback channel, covering every save, publish and delete — had no live region. Sign-in, sign-up and password-reset errors were unassociated coloured text, so a screen-reader user who mistyped a password heard silence. Both fixed. Also fixed: a skip link with a target on every page that has a main landmark; page titles on all 51 pages (7 had them); and single-character tool shortcuts no longer fire while the author is typing into slide text, which was both a functional bug and an SC 2.1.4 failure. Not yet done, stated plainly: - **No ACR or VPAT is published for the authoring tool, and publishing one today would be premature.** The remediation above is recent and unaudited by anyone outside the project. The intent is a third-party WCAG-EM assessment, published on this site, with honest "Partially Supports" rows — not a self-graded PDF. - Freeform canvas editing without sight remains an unsolved interaction problem across the industry. Keyboard operability is not the same as a good screen-reader experience, and we claim only the first. - A full screen-reader pass (NVDA, JAWS, VoiceOver) has not been run. - Remaining known gaps are tracked per-criterion with file references in the project's internal pre-deploy log. ## Why this page exists No mainstream authoring vendor publishes a conformance report for its authoring application — only (sometimes) for published output, and those reports concede keyboard access for the interactions that matter most in eLearning. Accessibility procurement teams deserve better than that, and every claim here can be checked against an exported course, which keeps this page honest. If you find an accessibility defect, please open an issue — they are triaged as bugs, not feature requests. --- The public, always-current version of this page is `/accessibility-conformance` on the marketing site (the domain is deployment-configured); this file is its working copy in the repository. ## Custom interactions https://scormbusters.com/docs/custom-interactions (last reviewed 2026-10-08) # Custom interactions A **Custom Interaction** block (`custom_html`) runs your own HTML, CSS and JavaScript inside a lesson: a drag-free simulation, a calculator, a branching mini-game, anything you or your assistant can write as one self-contained page. The block tracks it like a built-in question. It can report a score that counts toward the lesson and the course pass mark, mark itself complete, save a small state so a returning learner picks up where they left off, and size its frame to its content. It behaves the same in the Scormbusters player and in an exported SCORM 1.2, SCORM 2004, cmi5 or xAPI package. --- ## Table of contents 1. [Adding one](#adding-one) 2. [The sandbox](#the-sandbox) 3. [The `OpenCourse` object](#the-opencourse-object) 4. [The message protocol](#the-message-protocol) 5. [Scoring](#scoring) 6. [Saved state](#saved-state) 7. [Accessibility](#accessibility) 8. [Limits](#limits) --- ## Adding one In the block editor, open the block picker and choose **Custom Interaction** (under Interactive). Give it a **Title**, paste your code, and set **Points** if it should score. **Run preview** runs it in the editor. An assistant connected over MCP creates the same block with `add_block`: ```json { "type": "custom_html", "content": { "title": "Sort the hazards", "html": "

Is a frayed cable a hazard?

", "textAlternative": "A frayed cable is a hazard: stop and report it.", "points": 1 } } ``` `list_block_types` gives the full field reference, and `audit_course` flags a custom interaction with no title. --- ## The sandbox Your code runs in an `iframe` loaded from `srcdoc` with `sandbox="allow-scripts"` and nothing else. Its origin is opaque (`"null"`), so it has no cookies, no storage shared with Scormbusters or the LMS, no access to the page around it and no learner session. It cannot open pop-ups, submit forms, show `alert` dialogs or navigate the page. The frame's document also carries its own Content Security Policy: ``` default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob: https:; media-src data: blob: https:; font-src data:; connect-src 'none'; form-action 'none'; base-uri 'none' ``` So the code must be self-contained: inline ` ``` --- ## The message protocol `OpenCourse` is a thin wrapper. Underneath, the frame and the course exchange `postMessage` objects carrying `protocol: "opencourse-interaction"`; anything else is ignored. From the interaction to the course: | `type` | Fields | |---|---| | `ready` | none; the course replies with `init` | | `score` | `score` (number), `max` (number above 0, at most 1,000,000), `passed` (optional boolean) | | `complete` | none | | `state` | `state` (any JSON value, at most 1,000 characters serialized) | | `resize` | `height` (number; clamped to 80 to 4,000 pixels) | From the course to the interaction: `init`, `scored` (`score`, `maxScore`, `passed`, `recorded`), `saved` (`ok`), `completed`, and `error` (`for`, `error`). Error codes: `bad_score`, `bad_state`, `state_too_large`, `bad_height`, `unknown_type`, `too_large`, `not_json`, `not_scored`, `rate_limited`. The course accepts a message only from the block's own frame and only with the `"null"` origin. A message over 4,000 characters is refused, and messages are rate limited (a burst of 30, then 10 a second; a score at most once a second). --- ## Scoring Set **Points** (1 to 100) to make the block a scored question; 0 leaves it unscored. A report of `score` out of `max` earns `score / max` of the block's points, rounded to two decimals. It counts as passed when you send `passed: true`, or, when you send no `passed`, at full marks. In the Scormbusters player the result goes through the same answer route as every other question: it is stored as an attempt, counts toward the lesson score and the course pass mark, respects the block's attempt limit, and appears in analytics and the `quiz.submitted` webhook. It is recorded with `selfReported: true`. In an exported package the block counts as one question in the lesson score (like every exported question, by whether it was passed) and is reported to the LMS as a `numeric` interaction with its points as the weighting. **A self-reported score is not tamper-proof.** Your code decides it in the learner's browser, like any client-side SCORM content, and a determined learner can change it. Where a result must be checked by the server, use the built-in question blocks. A custom interaction is never drawn by a question pool; it always shows. --- ## Saved state `saveState` keeps one JSON value per learner, per attempt, per block, and `ready` hands it back. In the Scormbusters player it is saved with the learner's attempt (a restarted attempt starts empty). In a SCORM package it lives in `suspend_data` alongside the course's own progress, inside the 4,096-character SCORM 1.2 budget; a save that would overflow it is refused and the interaction gets `saved` with `ok: false`, while everything already saved stays. In cmi5 and xAPI packages it is part of the progress record in the LRS State API. Keep state small: answers and positions, not content. --- ## Accessibility The **Title** is required: it names the frame for screen readers, and the editor's accessibility checker and `audit_course` flag a custom interaction without one. The optional **Text alternative** is shown under the frame and linked to it as its description. Everything inside the frame is the author's responsibility, and no automated checker can see inside it: make it work from the keyboard, label every control, keep text contrast at 4.5:1, and announce results (a `role="status"` element works). --- ## Limits | Limit | Value | |---|---| | Code size | 100,000 characters (enforced by the database) | | Saved state | 1,000 characters of JSON | | One message | 4,000 characters | | Points | 0 to 100 | | Frame height | 80 to 4,000 pixels | | Sandbox | `allow-scripts` only | | Network | none |