40227-vm/frontend/docs/classroom-timer-integration.md
2026-06-12 06:55:35 +02:00

3.0 KiB

Classroom Timer Integration

Purpose

A visual countdown timer with sensory backgrounds and a sound library. Sounds come from three places, unified in one picker: hardcoded built-in synthesized sounds, generated sounds (recipe rows), and uploaded audio (file/url rows) from the audio_files library.

Current Behavior

  • frontend/src/components/frameworks/ClassroomTimer.tsx is a thin wrapper that takes userRole (from the shell) and calls useClassroomTimer(userRole).
  • Timer state, fullscreen, custom-time parsing, progress/urgency, particles, and Web Audio orchestration live in frontend/src/business/classroom-timer/. shared/constants/classroomTimer.ts keeps timing/particle config plus the sound-group labels and the generated/uploaded fallback icons.
  • View pieces are under frontend/src/components/classroom-timer/. The sound picker (TimerSettingsPanel) groups sounds by origin — Built-in / Generated / Uploaded — for clear structure.
  • Backgrounds/presets/tips and the built-in sound metadata are backend-owned content_catalog records loaded via the shared content-catalog API. The built-in sounds themselves are synthesized in-browser (business/classroom-timer/audio.ts, playBuiltInSound).
  • Missing content-catalog data renders an explicit backend error (no frontend seed fallback).

Audio Library

The picker merges the built-ins with the audio_files library (business/audio-files/):

  • API/types: shared/api/audioFiles.ts, shared/types/audioFiles.ts (incl. the SoundRecipe shape).
  • Hooks: useAudioFiles (list; retry: false so a caller without READ_AUDIO_FILES silently falls back to the built-ins), useGenerateAudioFile, useDeleteAudioFile. canManageAudioFiles gates the manage affordances (director/office_manager/teacher).
  • Playback branches by kind: builtinplayBuiltInSound(id), recipeplayRecipe(recipe) (business/classroom-timer/audio-recipe.ts, pure Web Audio from JSON params), file/urlnew Audio(url).
  • Generate: managers type a name and click Generate; this creates a recipe row whose synthesis parameters come from a local stub (business/audio-files/generate.ts). When an AI key is wired, only that function changes — persistence, playback and the library list are unchanged. An empty name falls back to a generated name.
  • Delete: managers can remove their own (non-default) library rows.

Tests

  • business/classroom-timer/selectors.test.ts (timer math)
  • business/audio-files/selectors.test.ts (canManageAudioFiles), business/audio-files/generate.test.ts (local recipe stub shape)

Verification

  • npm run typecheck, npm run lint, npm run test pass.

Remaining Work

  • Swap the local generateSoundRecipe stub for a real model call once an AI key exists.
  • Binary file upload UI — needs a typed upload client and the file-download ownership fix (see backend/docs/audio-files.md); recipe/url rows are unaffected.