Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

45. Accessible Academy Media

Rullst’s LMS example (examples/lms) contains a bounded lesson-presentation foundation for video and audio. Authorization and progress remain server-owned, while the browser receives accessible media markup and an escaped transcript.

Start from the LMS example

Before 13.0.0-alpha.4, cargo rullst new --blueprint lms generated this application; it now lives in the Rullst repository as examples/lms. From a checkout of the repository:

cd examples/lms
cargo test -p rullst-lms-example

Copy the directory to start your own academy (its README shows how to run it and how to switch to the published crates). It includes the course catalog, modules, lessons, this accessible player, enrollment, progress, login and a Nexus admin. Earlier releases also generated a complete Academy (assessment, gamification, automation and notifications); v13 removed it in favor of this smaller application.

Lesson media contract

Lessons store these fields:

FieldContract
media_kindClosed renderer values: video or audio.
media_urlHTTPS URL or absolute same-origin path; control characters and backslashes are rejected.
captions_urlRequired valid source for video; normally a same-origin .vtt path.
transcriptRequired and bounded; the HTML renderer escapes it.
language_tagRequired bounded ASCII language tag such as en or pt-BR.

For production, prefer application-owned same-origin or signed media. Put a caption file at static/media/lesson.pt-BR.vtt and store the public source as /static/media/lesson.pt-BR.vtt; Server mounts the local static/ directory at /static.

WEBVTT

00:00.000 --> 00:04.000
Bem-vindo à primeira atividade.

The example intentionally ships no media binary. Its four seeded development lessons point at remote sample video/audio files, and its two video lessons use the static/media/memory-safety.en.vtt and static/media/first-project.en.vtt captions. The default CSP (default-src 'self') does not allow that remote media, so replace the seeded lessons in Nexus (/nexus) with your own content. Add your reviewed audio/video asset or application-specific object-storage delivery, then use a same-origin path such as /static/media/lesson.webm. If you choose a remote host, add only that reviewed origin to a media-src directive of the csp template under [security] in Rullst.toml; do not weaken the policy to arbitrary HTTPS. Core also defaults COEP to require-corp, so the remote media server must emit a compatible Cross-Origin-Resource-Policy response. When a reviewed server cannot do so, an application can explicitly set coep = "credentialless" under [security] in Rullst.toml; browsers then omit credentials for eligible cross-origin no-CORS requests. Prefer same-origin delivery, and test the exact CSP/COEP/media combination in the deployed browser rather than disabling isolation globally.

What the player enforces

  • no autoplay;
  • native video/audio controls;
  • a caption track for every video;
  • an always-available transcript for video and audio;
  • visible keyboard focus and nonce-bound styles;
  • escaped title and transcript values;
  • fail-closed rendering for unknown kinds, insecure sources or invalid accessibility metadata.

The protected lesson controller checks the authenticated learner’s active enrollment before rendering the player. Progress submissions use CSRF and idempotency data and remain authoritative in the database. Each rendered player carries a fresh random key, scoped to the requested percentage on submission: resubmitting the same click replays the stored event, while a later save, or another button, records new progress.

Evidence boundary

The example’s own tests, run in the repository’s workspace suite, cover catalog query bounds, progress keys, the production security baseline and the learning service’s owner boundary; no test renders the player or its rejected source/metadata cases. They do not prove codec support, buffering behavior, screen-reader quality, subtitle accuracy, microphone or speech recognition, physical mobile devices, CDN delivery or app store behavior. Run browser accessibility tests with your real content and deployment before making those claims.