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.