diff options
| author | cashmere <cashmere@autistici.org> | 2026-07-27 01:21:20 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-07-27 01:21:20 +0200 |
| commit | 783e9ac8462751adc14d78b070095fd63e45bda0 (patch) | |
| tree | 9e28a0937b9155c6b791af836c973f39ced9d541 /apps/web/src/voiceover/voiceover-store.ts | |
| parent | 30a36e45686db503fded68e4da5d4c465a06f978 (diff) | |
| download | opencut-783e9ac8462751adc14d78b070095fd63e45bda0.tar.gz | |
feat: voice-over recording into the timeline
MediaRecorder mic capture (defensive mimeType picking, permission/no-mic
toasts) with elapsed display in the timeline toolbar. Stop produces an
audio asset and inserts it at the playhead on an audio track as ONE
BatchCommand undo step, freeze-frame precedent. voice-over action
registered, no default keybinding. 20 tests; smoke-tested in Chromium
with a fake mic end to end.
Diffstat (limited to 'apps/web/src/voiceover/voiceover-store.ts')
| -rw-r--r-- | apps/web/src/voiceover/voiceover-store.ts | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/apps/web/src/voiceover/voiceover-store.ts b/apps/web/src/voiceover/voiceover-store.ts new file mode 100644 index 00000000..44ccae6c --- /dev/null +++ b/apps/web/src/voiceover/voiceover-store.ts @@ -0,0 +1,41 @@ +/** + * Voice-over recording UI state. + * Transient by nature — a recording never survives a reload, so unlike most + * stores here this one is intentionally NOT persisted (same pattern as + * editor-store / properties-store). + */ + +import { create } from "zustand"; +import type { MediaTime } from "@/wasm"; + +export type VoiceOverStatus = "idle" | "recording"; + +interface VoiceOverStore { + status: VoiceOverStatus; + startedAtMs: number | null; + playheadStartTime: MediaTime | null; + startRecording: ({ playheadTime }: { playheadTime: MediaTime }) => void; + stopRecording: () => void; +} + +export const useVoiceOverStore = create<VoiceOverStore>()((set) => ({ + status: "idle", + startedAtMs: null, + playheadStartTime: null, + + startRecording: ({ playheadTime }) => { + set({ + status: "recording", + startedAtMs: Date.now(), + playheadStartTime: playheadTime, + }); + }, + + stopRecording: () => { + set({ + status: "idle", + startedAtMs: null, + playheadStartTime: null, + }); + }, +})); |
