feat: add Studio NLE playback controls

This commit is contained in:
Miguel Ángel
2026-04-28 17:51:38 -04:00
parent a18f66db18
commit a45f900af7
8 changed files with 435 additions and 33 deletions
+19 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { formatTime } from "./time";
import { formatFrameTime, frameToSeconds, secondsToFrame, formatTime } from "./time";
describe("formatTime", () => {
it("formats zero seconds", () => {
@@ -55,3 +55,21 @@ describe("formatTime", () => {
expect(formatTime(Infinity)).toBe("0:00");
});
});
describe("frame helpers", () => {
it("converts seconds to frames at the Studio preview rate", () => {
expect(secondsToFrame(0)).toBe(0);
expect(secondsToFrame(1)).toBe(30);
expect(secondsToFrame(1.5)).toBe(45);
});
it("converts frames to seconds at the Studio preview rate", () => {
expect(frameToSeconds(0)).toBe(0);
expect(frameToSeconds(30)).toBe(1);
expect(frameToSeconds(45)).toBe(1.5);
});
it("formats current and total frame display", () => {
expect(formatFrameTime(1, 5)).toBe("30f / 150f");
});
});
+20
View File
@@ -1,6 +1,26 @@
export const STUDIO_PREVIEW_FPS = 30;
export function formatTime(time: number): string {
if (!Number.isFinite(time) || time < 0) return "0:00";
const mins = Math.floor(time / 60);
const secs = Math.floor(time % 60);
return `${mins}:${secs.toString().padStart(2, "0")}`;
}
export function secondsToFrame(time: number, fps = STUDIO_PREVIEW_FPS): number {
if (!Number.isFinite(time) || time <= 0) return 0;
if (!Number.isFinite(fps) || fps <= 0) return 0;
return Math.round(time * fps);
}
export function frameToSeconds(frame: number, fps = STUDIO_PREVIEW_FPS): number {
if (!Number.isFinite(frame) || frame <= 0) return 0;
if (!Number.isFinite(fps) || fps <= 0) return 0;
return frame / fps;
}
export function formatFrameTime(time: number, duration: number, fps = STUDIO_PREVIEW_FPS): string {
const currentFrame = secondsToFrame(time, fps);
const totalFrames = secondsToFrame(duration, fps);
return `${currentFrame}f / ${totalFrames}f`;
}