LMS Runtime Player
:::info Source
Sourced from docs/11-lms-runtime-player-spec.md in the documentation repo.
:::
Companion: 03 delivery-service · 03 progress-service · 10 Authoring
1. Goals
A single Player runtime that:
- Renders a PlayPackage identically online and offline.
- Implements SCORM 1.2/2004 API JS shim and xAPI/cmi5 statement emission.
- Hosts an AI tutor sidecar (cloud or local).
- Works on web (PWA), mobile (Capacitor), desktop (Electron).
- Supports LTR + RTL, full a11y, captions, keyboard-only navigation.
2. Player Architectural Layers
┌────────────── App Shell (PWA) ──────────────────┐
│ │
│ ┌────────────── Player Container ───────────┐ │
│ │ Topbar (title / progress / exit / a11y) │ │
│ │ ┌─────── Outline ───────┬──── Canvas ────┐│ │
│ │ │ Modules / Lessons │ Block renderers││ │
│ │ │ │ ││ │
│ │ └───────────────────────┴────────────────┘│ │
│ │ Bottom: Prev / Next, Quiz Submit, Tutor │ │
│ └────────────────┬──────────────────────────┘ │
│ │ │
│ ┌───────────────┼──────────────┐ │
│ │ State machine │ Runtime data │ Statement Q │
│ │ (Navigation, │ (PlayPackage)│ (xAPI) │
│ │ Attempt) │ │ │
│ └───────────────┴──────────────┘ │
│ │
│ ┌───────────── SCORM API JS ──────────────┐ │
│ │ Adapter for legacy SCORM bridges │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ┌───────────── AI Tutor Adapter ──────────┐ │
│ │ Cloud (SSE) or Local (WebGPU/WASM) │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ┌───────────── Sync Adapter ──────────────┐ │
│ │ Pull bundle revocations · Push outbox │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Key principle: the Player is content-driven and dumb. PlayPackage manifest tells it what to render, in what order, with what gating rules. No business logic in the Player.
3. PlayPackage Consumption
Player ingests PackageManifest (see content-service). Manifest fields used:
course.title,course.durationMinutesmodules[].lessons[].blocks[](or refs into asset URLs)navigation:linear|tree|branchingprerequisites[]: gates per lesson/moduleassistant: optional config (system prompt seed, tools allowed, RAG corpus refs)- Per-block content data (already validated against block schema)
4. Navigation State Machine
States: init, loading, active, paused, quiz_in_progress, branch_decision, awaiting_grading, completed, error.
Transitions:
init → loading → activeon PlaySession resume.active → quiz_in_progresson quiz block enter.quiz_in_progress → active|branch_decision|awaiting_gradingbased on outcome.active → paused → activeon user pause.- terminal verbs (
completed,failed,abandoned) →completed.
Implemented via XState; same machine on web/mobile/desktop.
5. Block Rendering
Each block rendered by the registry's runtime component (mirror of the editor's). Renderer contract:
interface RuntimeProps<TConfig, TData> {
block: Block<TConfig, TData>;
ctx: PlayerContext;
onEvent: (e: BlockEvent) => void; // emits domain events upward
i18n: I18nFn;
reducedMotion: boolean;
rtl: boolean;
offline: boolean;
}
Block events translated by Player to xAPI statements + delivery events.
6. Quiz Engine (delegated to assessment-service)
- Player calls
assessment.serveQuizto fetch presentation form. - Submits responses via
assessment.attempts/{aid}/score. - Offline path: bundled QuizBank + scoring rules used; statements queued; server re-scores on sync to confirm.
7. Branching Scenarios
- BranchingBlock referenced from manifest expands into a state machine over
ScenarioNodes. - Node decisions emit
delivery.navigation.cursor_moved.v1withbranchPath. - Outcome scoring computed by assessment-service (online) or bundled rules (offline).
8. Progress Tracking
Player emits xAPI statements per significant interaction:
experienced(block view)attempted,answered(quiz interactions)completed,passed,failed,scoredterminated,abandoned
Each statement carries cmi5 context (sessionId, registration). Statements written to local outbox first, then either sent online or queued for sync.
9. SCORM API Wrapper
For SCORM compatibility (esp. when this Player itself is launched inside another LMS via SCORM 1.2 or 2004 export):
- Implements
API(SCORM 1.2) andAPI_1484_11(SCORM 2004) JS interfaces onwindow. - Translates
LMSSetValue/SetValuecalls to internal events; persists to local store; round-trips on commit. - For our own Player when launched standalone: SCORM API present but mostly a no-op (we use xAPI internally).
10. xAPI / cmi5 Emitter
- Builds Statements per
delivery-serviceevent mapping. - Configurable LRS endpoint (defaults to
progress-service). - Offline: statements queued in IndexedDB; sync flush.
11. AI Tutor Sidecar
Panel mounts in Player chrome. Behavior:
- Online: SSE call to
/play-sessions/{id}/assistant/turns. System prompt assembled from manifestassistant.systemSeed+ current block context. - Offline: local AI client invoked; system prompt + retrieval over local lesson text. Provenance flagged
local: true. - Tools:
lookupBlock(id),summarizeLesson(id),quizMe(topic),translate(text, targetLocale),simplify(text, audience),cite(blockId). All tool implementations local on the client (operate against bundled PlayPackage). - Safety: refusals shown as neutral message + "Try a different question".
- Rate limits: per-tenant via gateway; offline limit by local CPU/GPU thermals.
- Telemetry: turns logged locally; pushed at sync.
12. Accessibility
- Keyboard map: Space = play/pause media; Right/Left = next/prev; Q = open quiz; T = open tutor; C = toggle captions; ? = help overlay.
- All controls have visible focus + ARIA labels.
- Captions on every video/audio (auto-generated then editable upstream).
- Transcript drawer; SR announces lesson + block role on enter.
- Reduced motion preference disables transitions.
- Color contrast meets WCAG 2.2 AA (also in the AI tutor panel).
- Player itself ≥ AA on automated + manual audits.
13. i18n & RTL
- All UI copy localized; manifest content rendered with the manifest's
langper block. - Logical CSS for layout; controls mirror in RTL.
- Mixed-direction handled with
dir="auto"on author content.
14. Offline Behavior
- Mount: verify bundle signature → decrypt with device key → mount via OPFS or IndexedDB.
- Persistence: PlaySession state in IndexedDB; statements queue; tutor turns log; offline-cert claim.
- License envelope: checked on mount + every navigation; expired → graceful exit.
- Tamper: hash mismatch → unmount + report-tamper + force online resume.
- Sync: periodic background sync via service worker; user-triggered sync from Sync Center.
15. Performance
- Idle FPS = 0 (no needless rendering).
- Block transitions < 100 ms.
- Video preloads only the next likely segment.
- AI tutor first token < 600 ms p95 online; < 1.5 s p95 local (small model).
- Memory budget: < 250 MB resident on mobile mid-tier.
16. Telemetry
- Player emits structured analytics events (start, navigate, quiz submit, tutor turn, offline mount).
- All AI tutor turns include provenance + cost.
17. Embedding
- Self-mountable into 3rd-party LMS via SCORM zip or LTI 1.3.
- LTI launch hits
/lti/launch(tenant-service); player runs in iframe with restricted CSP.
18. Failure Modes
| Failure | Behavior |
|---|---|
| Bundle hash mismatch | Unmount; report; force online resume |
| Network drop mid-play | Keep playing; queue statements |
| Quiz scoring service down | Use bundled rules; mark pending_server_confirm |
| AI tutor refusal | Neutral message; suggest rephrase |
| AI tutor offline + no local model | Show "Tutor unavailable offline; here's a cached summary" if any |
| License revoked while offline | On next sync, exit with explanation; preserve progress |
19. Testing
- Unit: state machine + statement mapper.
- Integration: PlayPackage fixtures for every block kind.
- Contract: progress-service + delivery-service consumers (Pact).
- E2E: J-11, J-12, J-13, J-14, J-20.
- A11y: axe + manual NVDA + VoiceOver per release.
- Perf: Lighthouse + Playwright traces; budget enforcement.
- AI: prompt regression for the tutor system prompt; safety eval; offline-vs-online parity sample.
20. Why
A single Player implementation across web, mobile, and desktop — driven by a normalized PlayPackage — is the only sustainable path to consistent UX and consistent SCORM/xAPI behavior. Building the Player to be dumb relative to the manifest keeps the heavy lifting in content-service (where it's testable and cacheable). Treating AI tutor and offline mount as adapters keeps the runtime stable as those underlying technologies evolve.