Add scorm-export: wrap a DoenetML activity as an LMS-ready SCORM 2004 package - #3019
Open
cqnykamp wants to merge 5 commits into
Open
Add scorm-export: wrap a DoenetML activity as an LMS-ready SCORM 2004 package#3019cqnykamp wants to merge 5 commits into
cqnykamp wants to merge 5 commits into
Conversation
…ckage New workspace package `@doenet-tools/scorm-export`: the basis for a "Download SCORM" button on doenet.org. Given one DoenetML activity, it produces an LMS-ready SCORM 2004 (4th Edition) zip with no PreTeXt toolchain and no book chrome. Contents: - build.mjs: template substitution + zip packaging (Node built-ins only). - templates/: chrome-free index.html shell, activity.html embedding the activity and loading @doenet/standalone from CDN, and a minimal SCORM 2004 4th Edition manifest. - vendor/: PreTeXt's SCORM bridge (ptx_scorm_events.js) and SPLICE resize handler (lti_iframe_resizer.js), plus lz-string; see vendor/VENDORED.md. Local modifications to the vendored bridge (all marked VENDOR-MOD), a candidate to contribute upstream to PreTeXt: - Capture Doenet state in a Runestone-free package (upstream only saved it when RunestoneBase was present). - Persist that state (compressed, LZ-string) into cmi.suspend_data so it restores across LMS launches, since localStorage does not survive them; 4th Edition is declared for the 64,000-char suspend_data limit, with a size guard that degrades gracefully on overflow. Verified end-to-end on Canvas: score + state save, persist, and restore. The vendored files are Prettier-ignored to keep them verbatim. A separate DocViewer state-restore race in @doenet/standalone is filed against the DoenetML repo and is not addressed here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ring it lz-string is an unmodified, published package, so npm is a better fit than a committed minified blob: version + integrity now live in package.json and the lockfile, and `npm audit`/Renovate can track it. - Pin `lz-string@1.5.0` in package.json (exact — these bytes ship into student-facing packages, so bumps should be deliberate). - build.mjs resolves the minified build from node_modules via import.meta.resolve and copies it into the package; the two PreTeXt files (locally modified) stay vendored. - Remove vendor/lz-string.min.js; update VENDORED.md and README. The packaged bytes are identical to the previously-vendored copy; runtime behavior is unchanged. README also corrected for the 4th-Edition + compressed-suspend_data persistence (was still describing the old localStorage-only prototype). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the state-blob / suspend_data diagnostic out of the always-shipped index.html template into debug/size-probe.html. build.mjs inlines it into index.html only when run with --debug; a normal package contains no trace of it (file count unchanged, since it is inlined rather than added). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend debug/size-probe.html to log each lti.frameResize: the height Doenet reported, the height the resizer applied to the activity iframe, and whether index.html overflows the box the LMS gave it. The overflow clause distinguishes an inner scrollbar (ours to fix) from the LMS player's outer frame (not controllable from the SCO). The vendored lti_iframe_resizer.js is left byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A new
packages/scorm-exportpackage that wraps a single DoenetML activity in an LMS-ready SCORM 2004 4th Edition zip — no PreTeXt toolchain, no book chrome. This is the groundwork for a "Download SCORM" button on doenet.org: an instructor exports one activity, uploads the zip to their LMS, and student scores and work persist in the LMS itself (no phone-home to doenet.org).How it works
A package is six static files in a flat zip:
imsmanifest.xml— minimal SCORM 2004 4th Ed. manifest (one item, one SCO)index.html— chrome-free shell hosting the activity iframeactivity.html— loads@doenet/standalonefrom CDN, embeds the DoenetML, speaks SPLICE to the parentptx_scorm_events.js— PreTeXt's SCORM bridge (vendored; LMS API discovery, scoring, state save/restore, submit)lti_iframe_resizer.js— PreTeXt's SPLICElti.frameResizehandler (vendored, verbatim)lz-string.min.js— pinned npm dep, copied in at build time; compresses state forsuspend_databuild.mjsis template-substitution +zip(Node built-ins + thezipCLI). The design is deliberately client-side-able: the same substitute-and-zip could run in the browser behind a button.node packages/scorm-export/build.mjs sample/sample.doenet --title "My Activity"Reusing the PreTeXt bridge
The SCORM runtime intelligence is reused from PreTeXt (
js/ptx_scorm_events.js,js/lti_iframe_resizer.js) rather than reimplemented, and kept as verbatim vendored copies (seevendor/VENDORED.md) so upstream fixes re-sync cleanly. The bridge is ~96% byte-identical to upstream; the local changes (all markedVENDOR-MOD) do one thing: persist the Doenet activity state through the SCORM data model instead of localStorage-only, so student work restores on a fresh LMS launch._doenetStatesis compressed (lz-string, base64) intocmi.suspend_data; the manifest declares 4th Edition for its 64,000-charsuspend_datacap. A size guard drops the blob (falling back to localStorage) rather than corruptingsuspend_dataif it would ever overflow.RunestoneBase.__ptxScormHooked); in a Runestone-free standalone package the state was never captured, so the SPLICEmessagehandler now forwardsstate(and the real subject) intorecordInteraction.These bridge changes are a candidate to contribute upstream to PreTeXt; if accepted there, the local mod drops and we re-copy verbatim.
Verified
End-to-end on Canvas: state save → compress → persist in
suspend_data→ restore on relaunch → deliver back to Doenet.cmi.entry = "resume", score restored, and the compressed state (dz) round-trips.Debugging
debug/size-probe.htmlis a passive diagnostic (state-blob size,suspend_dataround-trip,lti.frameResizetracking). It is not in a normal package — pass--debugto inline it.Notes / known limitations
@doenet/standalonefrom jsDelivr; pin--doenet-versionfor reproducible packages. A fully offline package would bundle the viewer into the zip.🤖 Generated with Claude Code