3.0 KiB
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.tsxis a thin wrapper that takesuserRole(from the shell) and callsuseClassroomTimer(userRole).- Timer state, fullscreen, custom-time parsing, progress/urgency, particles, and
Web Audio orchestration live in
frontend/src/business/classroom-timer/.shared/constants/classroomTimer.tskeeps 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_catalogrecords 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. theSoundRecipeshape). - Hooks:
useAudioFiles(list;retry: falseso a caller withoutREAD_AUDIO_FILESsilently falls back to the built-ins),useGenerateAudioFile,useDeleteAudioFile.canManageAudioFilesgates 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
reciperow 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 testpass.
Remaining Work
- Swap the local
generateSoundRecipestub for a real model call once an AI key exists. - Binary
fileupload UI — needs a typed upload client and the file-download ownership fix (seebackend/docs/audio-files.md);recipe/urlrows are unaffected.