mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-05 09:53:05 +00:00
## Problem Closes #555. Studio users could inspect the preview, but there was no first-class way to capture the current rendered frame as an image. ## What this fixes - Adds a `Capture` action to the Studio header toolbar so it does not cover the video preview. - Downloads the current composition frame as a PNG using the current player time. - Extends the existing thumbnail route and Studio/CLI thumbnail generators with an explicit PNG format path while preserving JPEG thumbnails for existing previews. - Adds URL/filename utility coverage plus thumbnail route coverage for PNG requests. ## Root cause Studio already had frame thumbnail generation, but the API path was JPEG-oriented and the editor UI only used it for previews. There was no current-frame capture affordance wired to the player state. ## Verification ### Local - `bun run --filter @hyperframes/core test src/studio-api/routes/thumbnail.test.ts` - `bun run --filter @hyperframes/studio test src/utils/frameCapture.test.ts src/player/components/PlayerControls.test.ts` - `bun run --filter @hyperframes/studio typecheck` - `bun run --filter @hyperframes/core typecheck` - `bun run --filter @hyperframes/cli typecheck` - `bunx oxlint packages/cli/src/server/studioServer.ts packages/core/src/studio-api/routes/thumbnail.test.ts packages/core/src/studio-api/routes/thumbnail.ts packages/core/src/studio-api/types.ts packages/studio/src/App.tsx packages/studio/src/icons/SystemIcons.tsx packages/studio/vite.config.ts packages/studio/src/utils/frameCapture.ts packages/studio/src/utils/frameCapture.test.ts` - `bunx oxfmt --check packages/cli/src/server/studioServer.ts packages/core/src/studio-api/routes/thumbnail.test.ts packages/core/src/studio-api/routes/thumbnail.ts packages/core/src/studio-api/types.ts packages/studio/src/App.tsx packages/studio/src/icons/SystemIcons.tsx packages/studio/vite.config.ts packages/studio/src/utils/frameCapture.ts packages/studio/src/utils/frameCapture.test.ts` - `git diff --check` ### Browser <img width="1027" height="910" alt="image" src="https://github.com/user-attachments/assets/71973af4-0279-4074-9 <img width="1026" height="902" alt="Screenshot 2026-04-29 at 16 17 22" src="https://github.com/user-attachments/assets/a32e1c19-b793-40b9-82f8-de8bbb11f123" /> 060-130839a2d419" />
27 lines
857 B
TypeScript
27 lines
857 B
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { buildFrameCaptureFilename, buildFrameCaptureUrl } from "./frameCapture";
|
|
|
|
describe("frame capture utilities", () => {
|
|
it("builds a PNG capture URL for the master composition", () => {
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2026-04-29T12:00:00Z"));
|
|
|
|
expect(
|
|
buildFrameCaptureUrl({
|
|
projectId: "demo project",
|
|
compositionPath: null,
|
|
currentTime: 1.23456,
|
|
origin: "http://localhost:5194",
|
|
}),
|
|
).toBe(
|
|
"http://localhost:5194/api/projects/demo%20project/thumbnail/index.html?t=1.235&format=png&v=1777464000000",
|
|
);
|
|
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it("builds a safe filename from a nested composition path", () => {
|
|
expect(buildFrameCaptureFilename("compositions/intro.html", 2.5)).toBe("intro-2-500s.png");
|
|
});
|
|
});
|