diff --git a/skills/hyperframes-animation/scripts/animation-map.mjs b/skills/hyperframes-animation/scripts/animation-map.mjs index f95bb09331..a9a3612df7 100644 --- a/skills/hyperframes-animation/scripts/animation-map.mjs +++ b/skills/hyperframes-animation/scripts/animation-map.mjs @@ -51,7 +51,7 @@ const server = await createFileServer({ projectDir: COMP_DIR, port: 0 }); const session = await createCaptureSession( server.url, OUT_DIR, - { width: WIDTH, height: HEIGHT, fps: FPS, format: "png" }, + { width: WIDTH, height: HEIGHT, fps: { num: FPS, den: 1 }, format: "png" }, null, ); await initializeSession(session); diff --git a/skills/hyperframes-animation/scripts/animation-map.test.mjs b/skills/hyperframes-animation/scripts/animation-map.test.mjs new file mode 100644 index 0000000000..5ffd62e1e3 --- /dev/null +++ b/skills/hyperframes-animation/scripts/animation-map.test.mjs @@ -0,0 +1,66 @@ +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, it } from "node:test"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); +const HELPERS = [ + join(REPO_ROOT, "skills", "hyperframes-animation", "scripts", "animation-map.mjs"), + join(REPO_ROOT, "skills", "hyperframes-creative", "scripts", "contrast-report.mjs"), +]; + +describe("HyperFrames skill helpers", () => { + for (const helper of HELPERS) + it(`${helper.split("/").at(-1)} passes a rational frame rate`, () => { + const root = mkdtempSync(join(tmpdir(), "hyperframes-skill-helper-test-")); + const packageDir = join(root, "node_modules", "@hyperframes", "producer"); + const sharpPackageDir = join(root, "node_modules", "sharp"); + const compositionDir = join(root, "composition"); + mkdirSync(packageDir, { recursive: true }); + mkdirSync(sharpPackageDir, { recursive: true }); + mkdirSync(compositionDir, { recursive: true }); + writeFileSync( + join(packageDir, "package.json"), + JSON.stringify({ name: "@hyperframes/producer", type: "module", exports: "./index.mjs" }), + ); + writeFileSync( + join(packageDir, "index.mjs"), + [ + 'export async function createFileServer() { return { url: "http://test", close() {} }; }', + "export async function createCaptureSession(_url, _out, options) {", + " throw new Error(`CAPTURE_OPTIONS=${JSON.stringify(options)}`);", + "}", + "export async function initializeSession() {}", + "export async function closeCaptureSession() {}", + "export async function getCompositionDuration() { return 0; }", + ].join("\n"), + ); + writeFileSync( + join(sharpPackageDir, "package.json"), + JSON.stringify({ name: "sharp", type: "module", exports: "./index.mjs" }), + ); + writeFileSync(join(sharpPackageDir, "index.mjs"), "export default function sharp() {}\n"); + + try { + const result = spawnSync( + process.execPath, + [helper, compositionDir, "--fps", "24", "--out", join(root, "output")], + { + encoding: "utf8", + env: { + ...process.env, + HYPERFRAMES_SKILL_NODE_MODULES: join(root, "node_modules"), + }, + }, + ); + const output = `${result.stdout}\n${result.stderr}`; + assert.notEqual(result.status, 0); + assert.match(output, /CAPTURE_OPTIONS=.*"fps":\{"num":24,"den":1\}/); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); +}); diff --git a/skills/hyperframes-creative/scripts/contrast-report.mjs b/skills/hyperframes-creative/scripts/contrast-report.mjs index 1f7db29355..17804325fc 100644 --- a/skills/hyperframes-creative/scripts/contrast-report.mjs +++ b/skills/hyperframes-creative/scripts/contrast-report.mjs @@ -82,7 +82,7 @@ const server = await createFileServer({ projectDir: COMP_DIR, port: 0 }); const session = await createCaptureSession( server.url, OUT_DIR, - { width: WIDTH, height: HEIGHT, fps: FPS, format: "png" }, + { width: WIDTH, height: HEIGHT, fps: { num: FPS, den: 1 }, format: "png" }, null, ); await initializeSession(session);