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

66 lines
3.0 KiB
Markdown

# 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**: `builtin``playBuiltInSound(id)`, `recipe`
`playRecipe(recipe)` (`business/classroom-timer/audio-recipe.ts`, pure Web
Audio from JSON params), `file`/`url``new 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.