Skip to content

Accessible Video Quiz

A video-based memory quiz that is Born Accessible: a quiz cannot reach a senior unless it has both an audio description and captions, the audio description always plays before the video with no skip, captions are high-contrast and enlarged, and every answer is logged as a research record.

Where the code lives

  • src/features/video-quiz/types.ts — VideoQuizItem (authored content, including audioDescription and captions) and VideoQuizResponse, the research record whose field names mirror the approved schema.
  • src/features/video-quiz/validation.ts — validateVideoQuiz / canPublish: the Born Accessible gate that blocks publication when the audio description or captions are missing.
  • src/features/video-quiz/captions.ts — a resilient SRT parser and cueAt for time-based lookup.
  • src/features/video-quiz/export.ts — toCsv producing the research-ready video_quiz_response.csv columns.
  • src/features/video-quiz/logging.ts — buildVideoQuizResponse and the wrapped clock (keeps impure calls out of render for the React Compiler).
  • src/features/video-quiz/video-quiz-screen.tsx — the player.
  • app/(tabs)/video.tsx — the tab route.

Accessibility guarantees (WCAG 1.2.1, 1.2.2, 2.1.1)

  • Mandatory audio description. The description phase always precedes the video and is announced to assistive technology; there is no skip.
  • Mandatory captions. Captions render high-contrast (white on black) and enlarged (120% by default via defaultCaptionStyle).
  • Failsafe. A quiz that fails validateVideoQuiz renders a high-contrast error and no playback control, so inaccessible content never plays.
  • Large controls. The play/pause control is at least 48x48pt with a clear role and label, and advertises voice equivalents in its hint.
  • Nothing plays out of sight. Tapping Back or Home, or the app leaving the foreground, stops the clip; a delayed autoplay whose grace period elapses while the app is away never starts. Both screens share src/hooks/use-pause-when-hidden.ts for this, because the app has no transport control outside the player to silence it from.

Which video plays

Without an explicit item prop, the screen draws a shuffled order over seedVideoQuizzes and walks it, so the same clip does not open every visit. Because it shuffles the order rather than picking at random each time, every video is seen once before any repeats, and a reshuffle at the end of a pass never opens with the clip that just finished.

The draw happens once, in a lazy state initializer, so no randomness runs during a re-render. random is injectable for tests. This is the same pickPlayOrder helper the music quiz uses; see src/lib/play-order.ts.

Research data (Lisa Part)

Each answer produces a VideoQuizResponse capturing video_quiz_id, senior_id, timestamp, audio_description_used, captions_used, response, accuracy, context, senior_response_time_ms, and input_method. toCsv serializes a batch to the research-ready CSV.

Follow-ups (not in this branch)

  • Real video playback and time-synchronized caption rendering (expo-video).
  • Voice commands and voice answers (speech recognition), and caregiver audio recording for the description.
  • Caregiver upload flow: SRT upload, verified auto-captioning, and the publish-time enforcement of validateVideoQuiz.
  • Persist responses and add the CSV export action to the Stats Display.