Files
zooqueenandHanzo Dev 70b41673a3 frames: rebrand the fork to Hanzo Frames
Forked from HyperFrames (Apache-2.0), full history preserved.

Hosts are mapped explicitly and BEFORE the identifier rename, because
hyperframes.heygen.com is not decoration: 175 of its occurrences are $schema
identifiers that a validator dereferences. A blind rename would have left them
naming a host that never serves them. The schema files are in this repo under
docs/schema, so the mapped host is one we can actually serve -- that is the
condition that makes the rewrite safe, and serving them is a deploy task, not
an edit. docs/schema/hyperframes.json is renamed to frames.json to match the
identifier it is now published under.

api.heygen.com and the CLI auth against heygen.com are left UNRENAMED on
purpose. They are a dependency on HeyGen's SaaS, not a name of ours to take,
and the right move is to remove that integration rather than rebrand it.

LICENSE and CREDITS.md are untouched; NOTICE records the lineage.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 23:42:24 -07:00

67 lines
2.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import test from "node:test";
import { buildFramePackets } from "./frame-packets.mjs";
function write(path, contents) {
mkdirSync(dirname(path), { recursive: true });
writeFileSync(path, contents);
}
test("packets inline the blueprint body and the Scene-cited rule recipes", () => {
const project = mkdtempSync(join(tmpdir(), "fev-packets-"));
write(join(project, "frame.md"), "# tokens\n");
write(
join(project, "STORYBOARD.md"),
`---\nformat: 1920x1080\n---\n\n## Frame 1 — Hook\n\n- duration: 3s\n- src: compositions/frames/01-hook.html\n- blueprint: dataviz-countup\n- scene: hero stat punches in\n\nScene 1 (0.0–1.5s): the stat enters via spring-pop-entrance, then counting-dynamic-scale runs the tally.\n\n## Frame 2 — Freeform\n\n- duration: 4s\n- src: compositions/frames/02-freeform.html\n- blueprint: compose\n\nScene 1 (0.0–4.0s): a quiet hold, no named motion.\n`,
);
const result = buildFramePackets({ projectDir: project });
assert.equal(result.length, 2);
const hook = readFileSync(result[0].path, "utf8");
assert.match(hook, /## Selected blueprint: dataviz-countup/);
assert.match(hook, /## Selected motion rule: spring-pop-entrance/);
assert.match(hook, /## Selected motion rule: counting-dynamic-scale/);
assert.match(hook, /RULES_DIR: /);
const freeform = readFileSync(result[1].path, "utf8");
assert.doesNotMatch(freeform, /## Selected blueprint/);
assert.doesNotMatch(freeform, /## Selected motion rule/);
});
test("_role.md is the core contract + this workflow's delta, verbatim", () => {
const project = mkdtempSync(join(tmpdir(), "fev-role-"));
write(join(project, "frame.md"), "# tokens\n");
write(
join(project, "STORYBOARD.md"),
`---\nformat: 1920x1080\n---\n\n## Frame 1 — Hook\n\n- duration: 3s\n- src: compositions/frames/01-hook.html\n`,
);
buildFramePackets({ projectDir: project });
const rolePath = join(project, ".frames", "frame-packets", "_role.md");
assert.ok(existsSync(rolePath));
const role = readFileSync(rolePath, "utf8");
assert.match(role, /# Frame worker — core contract/);
assert.match(role, /# Frame worker — faceless-explainer delta/);
});
test("packet validation is atomic and leaves no partial output on overflow", () => {
const project = mkdtempSync(join(tmpdir(), "fev-atomic-"));
const outDir = join(project, ".frames", "frame-packets");
write(join(project, "frame.md"), "# tokens\n");
write(
join(project, "STORYBOARD.md"),
`---\nformat: 1920x1080\n---\n\n## Frame 1 — Big\n\n- duration: 3s\n- src: compositions/frames/01-big.html\n\n${"padding line\n".repeat(300)}`,
);
assert.throws(
() => buildFramePackets({ projectDir: project, outDir, maxPacketBytes: 2_000 }),
/limit 2000/,
);
assert.equal(existsSync(outDir), false);
});