SCORM Packages
If your course was built in Articulate Storyline or Rise, Adobe Captivate, iSpring, Lectora or any other tool that exports SCORM, you can publish the exported zip on edu.games as it is. Choose SCORM Package for the browser build instead of Standard HTML5 — the player reads your imsmanifest.xml, launches the course, and provides the LMS runtime (window.API for SCORM 1.2, window.API_1484_11 for SCORM 2004) the course expects. Progress, completion and scores are recorded for teachers exactly as they are for xAPI games.
Which option do I pick? Standard HTML5 is for a game you built yourself that opens from index.html. xAPI Package is an HTML5 game that sends its own xAPI statements. SCORM Package is for an authoring-tool export that talks to an LMS through the SCORM API — the tell-tale sign is an imsmanifest.xml at the top of the zip. A SCORM export uploaded as Standard HTML5 is rejected because it has no index.html, and it would not be able to save progress even if it loaded.
Package layout
Upload the zip your authoring tool produced — do not repackage it. The manifest must be at the zip root or exactly one folder down, the same rule as index.html for HTML5 games. Every other packaging check applies unchanged: the 1 GB size cap, the file-count and compression-ratio limits, and the executable blocklist.
OK — manifest at the root (what every authoring tool exports)
course.zip
├── imsmanifest.xml
├── story.html
├── story_content/
└── ...
Also OK — the export folder zipped as a whole
course.zip
└── my-course/
├── imsmanifest.xml
└── ...
Rejected — nested deeper than one folder
course.zip
└── exports/
└── my-course/
└── imsmanifest.xmlWhat we read from the manifest
- SCORM version — from
<schemaversion>(1.2, or 2004 in any edition). If it is missing we infer it from theadlcp:scormTypeattribute casing. - Launch file — the
hrefof the resource referenced by the first<item identifierref>in the default organization, with anyxml:baseapplied. The file must exist in the zip under exactly that path (paths are case-sensitive — the most common cause of a rejected package). - Title — the launching item’s
<title>, used as the activity name in statements. - SCO count — exactly one launchable SCO is allowed. A package with several SCOs in its default organization is refused at upload; export the course as a single SCO (every major tool offers this — Storyline and Captivate do it by default).
The manifest is checked when your upload finalizes, so a broken export fails immediately with a message that names what was wrong rather than at play time. <adlcp:dataFromLMS> and parameters on the item are read but not applied —cmi.launch_data is always empty.
The runtime
Courses run inside the same sandboxed, opaque-origin frame as every other browser build (see Packaging). Because the frame’s parent is cross-origin, the SCORM API lives on the course document’s own window, injected ahead of the first course script — the standard “walk up the parent chain” finder that every authoring tool ships finds it on the first hop. Both API objects are installed regardless of the manifest version, so a mislabelled export still works.
- Full RTE API for both versions: Initialize / Terminate, GetValue / SetValue, Commit, GetLastError / GetErrorString / GetDiagnostic (the 1.2
LMS-prefixed names for SCORM 1.2), with the standard error codes. - The complete
cmidata model, including_childrenand_count, objectives, interactions and learner preferences. Vocabulary and ranges are validated onSetValue. cmi.core.student_id/cmi.learner_idis the learner’s edu.games account id, and the name is their display name. Anonymous plays (a teacher’s free preview, a public demo) get an empty id.- On SCORM 1.2 a status of
not attemptedbecomesincompleteat Initialize, as most LMSs do. We do not apply the 1.2 “completed on exit if the SCO never set a status” rule — set the status explicitly.
Resume and total time
Every Commit and Terminate saves the whole data model (suspend data, bookmark, status, score, interactions) to the LRS State API as the document scorm-cmi for that learner and course, under the learner’s own launch token. The next time they open the course the player loads it before the first script runs, so Initialize returns immediately with everything in place. cmi.core.entry / cmi.entry reads resume when the course exited with suspend or left suspend data or a bookmark behind, and ab-initio otherwise; status and score are kept either way so a completion sticks.
total_time accumulates the session_time your course sets, or the wall-clock session length if it never sets one. Commits are debounced to one save per second; Terminate saves immediately, and closing the tab mid-session triggers a final Terminate. Nothing is saved for anonymous plays — the course still runs, it just starts fresh every time.
What teachers see
The runtime translates the SCORM data model into xAPI statements using the same verbs the Emission Profile defines, so a SCORM course lights up the same Learning Intelligence presets as an instrumented HTML5 game. The object of every statement is your game’s activity IRI, https://edu.games/games/<your-subdomain>, with the SCORM category context and the SCORM version as an extension.
| Course does | Statement | Notes |
|---|---|---|
Initialize / LMSInitialize | launched (every session) and attempted (first session of an attempt) | The learner opened the course. |
lesson_status = completed / completion_status = completed | completed | Marks the play as finished for Learning Intelligence. |
lesson_status = passed / success_status = passed | passed (plus completed on 1.2) | Carries the score as result.score (raw, min, max, scaled). |
lesson_status = failed / success_status = failed | failed | Carries the score. Never reported as a completion. |
cmi.interactions.n.* with a response | answered, one per question | Object is <activity>/interactions/<id>; result has the response and correct/incorrect. |
Terminate / LMSFinish without a terminal status | terminated | The abandonment signal, with the session duration. |
Each status statement is sent once per session, at the first Commit or Terminate after the status changed, and carries the score and the session duration. Statements you can see arriving live on edugames.dev — launch a test session from your game’s page in the dev portal exactly as you would for an xAPI game.
Limitations
- One SCO per package. SCORM 2004 sequencing and navigation (
imsss,adl.nav.request) are not implemented: the request element is writable but ignored, andadl.nav.request_valid.*always readsunknown. Multi-SCO packages are refused at upload. - No LMS-authored data.
cmi.launch_data,comments_from_lms, mastery score, time limits and completion thresholds are always empty. - Objectives are stored, not reported.
cmi.objectives.n.*round-trips through the saved state, but only the SCO-level status and the interactions become statements. If you want per-objective analytics, instrument the course with xAPI directly (see xAPI Overview). - Frames inside the course must find the API on their own window or its ancestors inside the package, which is how every authoring tool’s player is built. A course that opens a popup window and expects the API there is not supported.
- Everything else from Packaging applies — sandboxed iframe, opaque origin, in-memory
localStorage. Persistent progress goes through the SCORM API, not browser storage.
Troubleshooting
- “No imsmanifest.xml found” — the manifest is nested more than one folder down, or you zipped a folder that contains the export folder. Zip the contents of the export folder, or the export folder itself, not its parent.
- “… launches X but that file is not in the zip” — the href in the manifest does not match a file path in the zip. Check capitalisation and any
xml:base. - The course loads but never completes — it is setting a status vocabulary the spec does not allow (for example
completeinstead ofcompleted). Open the test session on edugames.dev and watchGetLastErrorin the browser console. - Progress does not resume — the course must call
Commit(or Terminate) after writing suspend data, and setexittosuspendif it wants a resume regardless of bookmark. Anonymous plays never resume.