Skip to content

Commit eb2ccb5

Browse files
AmirMohammad CheraghaliAmirMohammad Cheraghali
authored andcommitted
fix(timeline): Add horizontal margins to timeline and fix session recorder crash
- StudioLayout: Added px-6 padding to timeline container to prevent handles from touching screen edges - useSessionRecorder: Fixed ReferenceError/hoisting issue with applyFrameAt - useSessionRecorder: Restored missing refs and logic lost in previous edits
1 parent 5971488 commit eb2ccb5

3 files changed

Lines changed: 44 additions & 33 deletions

File tree

src/components/StudioLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ export const StudioLayout: React.FC<StudioLayoutProps> = ({ recorder, onExit, ex
931931

932932
{/* BOTTOM TIMELINE */}
933933
<div className={`h-48 bg-neutral-900/95 backdrop-blur border-t border-white/10 flex flex-col pointer-events-auto relative transition-all duration-300 ${isTrimMode ? 'ring-1 ring-blue-500/50' : ''}`}>
934-
<div className="flex-1 relative mt-2">
934+
<div className="flex-1 relative mt-2 px-6">
935935
<VideoTimeline
936936
session={session}
937937
segments={segments}

src/components/VideoTimeline.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ export const VideoTimeline = ({
3333
onSegmentSelect,
3434
playbackTime,
3535
onSeek,
36-
trimMode,
3736
trimStart: externalTrimStart,
3837
trimEnd: externalTrimEnd,
3938
onTrimChange,
@@ -311,7 +310,7 @@ export const VideoTimeline = ({
311310
{/* Timeline Track Container */}
312311
<div
313312
ref={containerRef}
314-
className="relative h-auto min-h-[6rem] bg-black/40 rounded-lg border border-white/10 overflow-x-auto overflow-y-hidden cursor-pointer select-none py-2 px-4 space-y-2"
313+
className="relative h-auto min-h-[6rem] bg-black/40 rounded-lg border border-white/10 overflow-x-auto overflow-y-hidden cursor-pointer select-none py-2 space-y-2"
315314
onMouseDown={handleTimelineMouseDown}
316315
onMouseMove={handleMouseMove}
317316
onMouseUp={handleMouseUp}

src/hooks/useSessionRecorder.ts

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ export const useSessionRecorder = ({ onPlaybackStateChange, onPlaybackCameraChan
1515
const [playbackSpeed, setPlaybackSpeed] = useState(1);
1616
const [masterVolume, setMasterVolume] = useState(1.0);
1717

18+
// --- State & Refs (Restored) ---
19+
const eventsRef = useRef<RecordedEvent[]>([]);
20+
const initialStateRef = useRef<any>(null);
21+
const startTimeRef = useRef<number>(0);
22+
const animationFrameRef = useRef<number | null>(null);
23+
24+
// Playback Optimization Refs
25+
const playbackCursorRef = useRef<number>(0);
26+
const accumulatedStateRef = useRef<any>(null);
27+
const lastAppliedTimeRef = useRef<number>(-1);
28+
const lastPlaybackUpdateRef = useRef<number>(0);
29+
30+
// Timeline Segments
31+
const [segments, setSegments] = useState<TimelineSegment[]>([]);
1832
// Audio Playback
1933
// We need a pool of players or a single smart player?
2034
// For MVP: Single Music Track => Single Audio Element.
@@ -156,45 +170,17 @@ export const useSessionRecorder = ({ onPlaybackStateChange, onPlaybackCameraChan
156170
});
157171
}, [isRecording]);
158172

159-
// --- Playback ---
160-
161-
const play = useCallback(() => {
162-
if (!session) return;
163-
setIsPlaying(true);
164-
lastPlaybackUpdateRef.current = Date.now();
165-
166-
// Sync Audio
167-
syncAudio(playbackTime, true);
168-
}, [session, playbackTime, syncAudio]);
169-
170-
const pause = useCallback(() => {
171-
setIsPlaying(false);
172-
// Sync Audio
173-
if (audioRef.current) {
174-
audioRef.current.pause();
175-
}
176-
}, []);
177-
178-
const seek = useCallback((time: number) => {
179-
if (!session) return;
180-
setPlaybackTime(time);
181-
applyFrameAt(time);
182-
syncAudio(time, isPlaying);
183-
}, [session, isPlaying, applyFrameAt, syncAudio]);
173+
// --- Playback Helper ---
184174

185175
const applyFrameAt = useCallback((globalTime: number) => {
186176
if (!session || !onPlaybackStateChange || !onPlaybackCameraChange) return;
187177

188178
// Find which segment covers this global time
189-
// Note: 'segments' state from upper scope
190-
// We need to use state setter callback or refs if state is stale,
191-
// but here we depend on 'segments' in hook dependency array.
192179
const activeSegment = segments.find(
193180
s => globalTime >= s.startTime && globalTime < s.startTime + s.duration
194181
);
195182

196183
if (!activeSegment) {
197-
// Gap in timeline? Or end of playback?
198184
return;
199185
}
200186

@@ -203,7 +189,6 @@ export const useSessionRecorder = ({ onPlaybackStateChange, onPlaybackCameraChan
203189
const sourceTime = activeSegment.sourceStartTime + timeInSegment;
204190

205191
// Rebuild state from scratch for now to ensure correctness across jumps
206-
// Performance TODO: Optimization cursor needs to be segment-aware
207192
let currentState = JSON.parse(JSON.stringify(session.initialState));
208193
let currentCamera = null;
209194

@@ -228,6 +213,32 @@ export const useSessionRecorder = ({ onPlaybackStateChange, onPlaybackCameraChan
228213
lastAppliedTimeRef.current = globalTime;
229214
}, [session, segments, onPlaybackStateChange, onPlaybackCameraChange]);
230215

216+
// --- Playback Controls ---
217+
218+
const play = useCallback(() => {
219+
if (!session) return;
220+
setIsPlaying(true);
221+
lastPlaybackUpdateRef.current = Date.now();
222+
223+
// Sync Audio
224+
syncAudio(playbackTime, true);
225+
}, [session, playbackTime, syncAudio]);
226+
227+
const pause = useCallback(() => {
228+
setIsPlaying(false);
229+
// Sync Audio
230+
if (audioRef.current) {
231+
audioRef.current.pause();
232+
}
233+
}, []);
234+
235+
const seek = useCallback((time: number) => {
236+
if (!session) return;
237+
setPlaybackTime(time);
238+
applyFrameAt(time);
239+
syncAudio(time, isPlaying);
240+
}, [session, isPlaying, applyFrameAt, syncAudio]);
241+
231242

232243
// Playback Loop
233244
useEffect(() => {
@@ -640,6 +651,7 @@ export const useSessionRecorder = ({ onPlaybackStateChange, onPlaybackCameraChan
640651
setSegments,
641652

642653
// Selection
654+
selectedSegmentIds, // Fix: Expose selection state
643655
toggleSegmentSelection,
644656
deleteSelectedSegments,
645657
updateSegment,

0 commit comments

Comments
 (0)