Skip to main content

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.durationMinutes
  • modules[].lessons[].blocks[] (or refs into asset URLs)
  • navigation: linear | tree | branching
  • prerequisites[]: gates per lesson/module
  • assistant: 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 → active on PlaySession resume.
  • active → quiz_in_progress on quiz block enter.
  • quiz_in_progress → active|branch_decision|awaiting_grading based on outcome.
  • active → paused → active on 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.serveQuiz to 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.v1 with branchPath.
  • 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, scored
  • terminated, 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) and API_1484_11 (SCORM 2004) JS interfaces on window.
  • Translates LMSSetValue/SetValue calls 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-service event 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 manifest assistant.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 lang per 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​

FailureBehavior
Bundle hash mismatchUnmount; report; force online resume
Network drop mid-playKeep playing; queue statements
Quiz scoring service downUse bundled rules; mark pending_server_confirm
AI tutor refusalNeutral message; suggest rephrase
AI tutor offline + no local modelShow "Tutor unavailable offline; here's a cached summary" if any
License revoked while offlineOn 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.