Open
Conversation
Adds a new export option that generates a SCORM 1.2-compliant ZIP package uploadable to any LMS (Moodle, Blackboard, SCORM Cloud, etc.). What is exported: - Slide scenes → HTML SCO with absolutely-positioned CSS canvas, responsive scaling via transform:scale(), and auto-playing TTS narration audio - Quiz scenes (single/multiple choice only) → HTML SCO with SCORM scoring (cmi.core.score.*, cmi.interactions.*), visual feedback, and pass/fail tracking - Interactive scenes with embedded HTML → HTML SCO wrapping content in an isolated <iframe srcdoc> What is excluded: - PBL scenes (require live LLM) - Whiteboard animations and multi-agent chat - Short-answer quiz questions (require AI grading) - Interactive scenes without html content Video handling: a pre-export dialog lets the user choose between including video files in the package or replacing them with poster images (recommended to stay within LMS upload limits). New files: - lib/export/scorm/ (scorm-bridge.ts, manifest.ts, asset-collector.ts, slide-sco.ts, quiz-sco.ts, interactive-sco.ts, use-export-scorm.ts, index.ts) - components/scorm-export-dialog.tsx Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All scenes now rendered as <section> elements in a single index.html instead of separate scos/scene_XX.html files per scene (fixes broken navigation in LMS iframes that blocked window.parent.location.href) - Slide scaling uses .slide-scaler wrapper sized to visual dimensions so flex centering works correctly (fixes deformed slide layout) - TTS audio URLs are fetched as blobs and included in ZIP under assets/ - SCORM completion only fires on last scene (not on every scene load) - Nav bar with Prev/Next + narration Play/Pause/Restart controls embedded in single page; Next button gated on quiz submission - course-builder.ts assembles all section fragments into index.html - manifest.ts rewritten for single-SCO (one item → index.html) - data-title attributes added to all section types for nav bar display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shape rendering:
- Replace invalid CSS linear-gradient() in SVG fill attribute with proper
SVG <defs><linearGradient>/<radialGradient> elements
- Shapes with gradient fills now render correctly (previously appeared as
white/transparent boxes because browsers ignore CSS gradients in SVG fill)
TTS audio:
- TTS audio in normal flow is stored in IndexedDB only (audioUrl is not set)
- asset-collector now falls back to db.audioFiles.get(audioId) when audioUrl
is absent, storing the blob in the ZIP with key idb:{audioId}
- slide-sco narration lookup updated to resolve both audioUrl and idb: keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rendering fix — CSS class name conflicts with LMS stylesheets: - LMSes inject their own CSS (Bootstrap, Moodle themes) that overrides common names like .scene, .option-label, .submit-btn, .result-bar, .analysis - Renamed ALL CSS classes to om- prefix: om-scene, om-slide, om-quiz, om-scaler, om-canvas, om-opt, om-submit, om-result, om-pass/fail, etc. - Removed unnecessary .slide-stage wrapper div (was causing flex layout issues since position:absolute canvas made the wrapper collapse to zero height) - om-scaler is now the direct flex child of om-slide, centering works correctly Sidebar navigation: - Fixed 240px left panel with course title, progress bar, and scene list - Each scene shows a dot indicator: empty (not visited), green ✓ (visited), blue (current scene) - Progress label "X / N completades" updates as user navigates - Clicking any item in the sidebar navigates freely (no quiz gate) - Scene area and nav bar are offset by sidebar width (left: 240px) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SVG shapes use normalized 0-1 coordinates in the path. Without preserveAspectRatio="none", the browser letterboxes the square (1x1) viewBox to fit within the element bounds using xMidYMid meet — so a 1000x130 header shape only renders in a 130x130 area centered horizontally, leaving the rest empty. Adding preserveAspectRatio="none" stretches the viewBox to fill the element exactly, equivalent to PPTist's scale(W, H) transform approach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Saves lesson_location (scene index) and suspend_data (visited bitmask + quiz scores) on every navigation and quiz submit. On re-entry, restores visited state, quiz scores, and resumes at the last scene. Guards against overwriting completed/passed status with incomplete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Some LMS implementations (e.g. MiniLMSCat) load saved state asynchronously after LMSInitialize returns. Poll suspend_data/lesson_location up to 10 times (50ms apart) before applying resume state, so the course resumes correctly even when the LMS fetch takes a moment to complete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Sequential unlock: slide/interactive scenes unlock the next scene on visit; quiz scenes only unlock the next on passing (score >= 80). Locked scenes appear dimmed in the sidebar and cannot be clicked. unlockedUpTo persisted in suspend_data field 'u'. - Quiz retry: failed quiz shows "Torna-ho a intentar" button that fully resets inputs, styles and analysis so the student can retry. Infinite retries allowed; passing any attempt unlocks the next scene. - Submit validation: submit button requires at least one answer per question; unanswered blocks are highlighted in orange until resolved. - Init timing: reduce retry attempts from 10x50ms to 5x100ms now that MiniLMSCat bridge loads state synchronously before the iframe starts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n real time - Add null guard (if !block return) in submit validation and retry reset to prevent silent TypeError if getElementById finds no element. - Clear om-qblock--warn class immediately when user selects an answer, giving real-time feedback instead of requiring a second Submit click. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…deList - Add if(!block) guard in scoring forEach to prevent silent TypeError if any question block is unexpectedly missing from the DOM. - Replace NodeList.forEach() with Array.from().forEach() throughout to avoid compatibility issues in some browser/LMS environments. - Guard SCORM.logInteraction with typeof check before calling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… conflicts Multiple quizzes in the same course can have questions with identical IDs (e.g. q1, q2, q3). All quiz sections are in the same DOM, so getElementById was returning the first quiz's hidden blocks instead of the current quiz's. This caused submit validation to always fail silently on the second quiz. Fix: prefix all qblock_* and analysis_* element IDs with the sceneIndex (e.g. qblock_12_q1) to guarantee uniqueness across the entire page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Generates a notes.txt file at the ZIP root with all scene titles and their associated TTS speech text (SpeechAction.text), mirroring the notes panel visible in OpenMAIC's editor. Co-Authored-By: Claude Sonnet 4.6 <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.
Summary
Adds a complete SCORM 1.2 export pipeline to OpenMAIC. Instructors can export any course as a standards-compliant
.zippackage that can be uploaded to any SCORM 1.2 LMS (Moodle, SCORM Cloud, etc.). The package is a single-SCO design: all scenes live in oneindex.htmlwith internal JS navigation, which avoids the iframe navigation failures that multi-SCO approaches suffer in most LMSes.Related Issues
No related issues.
Changes
lib/export/scorm/with dedicated modules:course-builder.ts,slide-sco.ts,quiz-sco.ts,interactive-sco.ts,asset-collector.ts,manifest.ts,scorm-bridge.ts,use-export-scorm.ts<section>elements in oneindex.html; internal JS navigation replaces inter-SCO redirectstransform: scale()fit; SVG shapes usepreserveAspectRatio="none"and inline<linearGradient>/<radialGradient>defs to match editor appearancedb.audioFiles) when no server URL is available; included inassets/audio/inside the ZIP<iframe srcdoc>cmi.core.lesson_location+cmi.suspend_datasaved on every navigation and quiz submit; on re-entry the course resumes at the last scene with visited state and quiz scores restored;completed/passedstatus is never downgraded toincompleteom-prefix to prevent collisions with LMS stylesheets (Bootstrap, Moodle, etc.)notes.txt— plain-text file included in the ZIP with each scene's title and its TTS narration text, mirroring the notes panel in the OpenMAIC editorScormExportDialogcomponent with an "include videos" toggle, accessible from the headerType of Change
Verification
Steps to reproduce / test
imsmanifest.xml,index.html,scorm_bridge.js,notes.txt, and anassets/folder with audio files.index.htmllocally in a browser: verify sidebar navigation, slide scaling, audio playback, quiz submission with visual feedback, and retry on failure.What you personally verified
notes.txtcontains the correct narration text for each slide scene (not needed, but as a bonus)Evidence
pnpm check && pnpm lint && npx tsc --noEmit)Development
Development realized by Claude Code, under supervision of Author.