From 19b8a1f3c5a55c30b5aa367c9054ca1b31552536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Tue, 4 Aug 2026 16:27:41 -0700 Subject: [PATCH] refactor(studio): extract live timeline clock (#2711) --- packages/studio/src/player/store/liveTime.ts | 11 +++++++++++ packages/studio/src/player/store/playerStore.ts | 14 +------------- 2 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 packages/studio/src/player/store/liveTime.ts diff --git a/packages/studio/src/player/store/liveTime.ts b/packages/studio/src/player/store/liveTime.ts new file mode 100644 index 000000000..94bf6bf17 --- /dev/null +++ b/packages/studio/src/player/store/liveTime.ts @@ -0,0 +1,11 @@ +// ponytail: Playback RAF updates the playhead/time display without per-frame React renders. +type TimeListener = (time: number) => void; +const timeListeners = new Set(); + +export const liveTime = { + notify: (time: number) => timeListeners.forEach((listener) => listener(time)), + subscribe: (listener: TimeListener) => { + timeListeners.add(listener); + return () => timeListeners.delete(listener); + }, +}; diff --git a/packages/studio/src/player/store/playerStore.ts b/packages/studio/src/player/store/playerStore.ts index 26323e458..7686e7a87 100644 --- a/packages/studio/src/player/store/playerStore.ts +++ b/packages/studio/src/player/store/playerStore.ts @@ -12,6 +12,7 @@ import { clampTimelineZoomPercent, computePinnedZoomPercent } from "../component import { createKeyframeSlice, type KeyframeCacheEntry, type KeyframeSlice } from "./keyframeSlice"; export type { KeyframeCacheEntry } from "./keyframeSlice"; +export { liveTime } from "./liveTime"; export interface TimelineElement { id: string; @@ -279,19 +280,6 @@ interface BeatHistoryEntry { label: string; } -// Lightweight pub-sub for current time during playback. -// Bypasses React state so the RAF loop can update the playhead/time display -// without triggering re-renders on every frame. -type TimeListener = (time: number) => void; -const _timeListeners = new Set(); -export const liveTime = { - notify: (t: number) => _timeListeners.forEach((cb) => cb(t)), - subscribe: (cb: TimeListener) => { - _timeListeners.add(cb); - return () => _timeListeners.delete(cb); - }, -}; - export function createTimelineResetState() { return { isPlaying: false,