Skip to content
6 changes: 4 additions & 2 deletions apps/ui/src/components/editor/export-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function ExportDialog({ open, onOpenChange }: ExportDialogProps) {
const options: ExportOptions = {
width: settings.width,
height: settings.height,
frameRate: settings.fps,
frameRate: settings.fps.numerator / settings.fps.denominator,
videoBitrate: qualityPreset?.bitrate,
};

Expand Down Expand Up @@ -167,7 +167,9 @@ export function ExportDialog({ open, onOpenChange }: ExportDialogProps) {
</div>
<div>
<span className="font-medium">Frame rate: </span>
{settings.fps} fps
{Math.round((settings.fps.numerator / settings.fps.denominator) * 100) /
100}{" "}
fps
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/src/components/editor/keyframe-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function KeyframeButton({
onReset,
clipStartTime,
}: KeyframeButtonProps) {
const currentTime = useVideoEditorStore((s) => s.currentTime);
const currentTime = useVideoEditorStore((s) => s.currentFrame);
const clips = useVideoEditorStore((s) => s.clips);
const addKeyframe = useVideoEditorStore((s) => s.addKeyframe);
const deleteKeyframe = useVideoEditorStore((s) => s.deleteKeyframe);
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/src/components/editor/keyframe-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function KeyframeInput({
displayMultiplier = 1,
className,
}: KeyframeInputProps) {
const currentTime = useVideoEditorStore((s) => s.currentTime);
const currentTime = useVideoEditorStore((s) => s.currentFrame);
const clips = useVideoEditorStore((s) => s.clips);
const addKeyframe = useVideoEditorStore((s) => s.addKeyframe);
const updateKeyframe = useVideoEditorStore((s) => s.updateKeyframe);
Expand Down
33 changes: 18 additions & 15 deletions apps/ui/src/components/editor/playback-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,35 @@ import { Button } from "../ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
import { useVideoEditorStore } from "../../state/video-editor-store";
import { Play, Pause, SkipBack, SkipForward, ChevronsLeft, ChevronsRight } from "lucide-react";
import { type FrameRate } from "@tooscut/render-engine";

/**
* Format time as HH:MM:SS.ms
* Format a frame number as timecode HH:MM:SS:FF
*/
function formatTimecode(seconds: number): string {
const hrs = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
const ms = Math.floor((seconds % 1) * 100);
function formatTimecode(frame: number, fps: FrameRate): string {
const fpsFloat = fps.numerator / fps.denominator;
const totalSeconds = frame / fpsFloat;
const hrs = Math.floor(totalSeconds / 3600);
const mins = Math.floor((totalSeconds % 3600) / 60);
const secs = Math.floor(totalSeconds % 60);
const ff = Math.floor(frame % fpsFloat);

return `${hrs.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}.${ms.toString().padStart(2, "0")}`;
return `${hrs.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}:${ff.toString().padStart(2, "0")}`;
}

export function PlaybackControls() {
const currentTime = useVideoEditorStore((s) => s.currentTime);
const duration = useVideoEditorStore((s) => s.duration);
const currentFrame = useVideoEditorStore((s) => s.currentFrame);
const durationFrames = useVideoEditorStore((s) => s.durationFrames);
const isPlaying = useVideoEditorStore((s) => s.isPlaying);
const seekTo = useVideoEditorStore((s) => s.seekTo);
const setIsPlaying = useVideoEditorStore((s) => s.setIsPlaying);

const frameTime = 1 / 30;
const settings = useVideoEditorStore((s) => s.settings);

const handleJumpToStart = () => seekTo(0);
const handleStepBackward = () => seekTo(Math.max(0, currentTime - frameTime));
const handleStepBackward = () => seekTo(Math.max(0, currentFrame - 1));
const handlePlayPause = () => setIsPlaying(!isPlaying);
const handleStepForward = () => seekTo(Math.min(duration, currentTime + frameTime));
const handleJumpToEnd = () => seekTo(duration);
const handleStepForward = () => seekTo(Math.min(durationFrames, currentFrame + 1));
const handleJumpToEnd = () => seekTo(durationFrames);

return (
<TooltipProvider delayDuration={300}>
Expand Down Expand Up @@ -100,7 +102,8 @@ export function PlaybackControls() {

{/* Time display */}
<div className="ml-4 font-mono text-sm text-muted-foreground">
{formatTimecode(currentTime)} / {formatTimecode(duration)}
{formatTimecode(currentFrame, settings.fps)} /{" "}
{formatTimecode(durationFrames, settings.fps)}
</div>
</div>
</TooltipProvider>
Expand Down
Loading
Loading