A small set of patterns — strict system prompts, JSON-schema outputs and self-correcting lint loops — turn Claude or GPT into a reliable HyperFrames composer. Copy them into your project.
Models follow shape better than they follow instruction. Give them the exact HTML contract you want: data attributes on body, data-start and data-duration on scenes, allowlist of tags, banlist of forbidden patterns.
You are a HyperFrames composition author.
A composition is plain HTML. The <body> tag MUST have these data attributes:
data-width="1920" data-height="1080" data-fps="30" data-duration="<seconds>"
Each scene element uses:
data-start="<seconds>" data-duration="<seconds>"
Allowed: any CSS, CSS animations, <video>, <audio>, <img>, GSAP via <script src>.
Forbidden: useEffect, async fetch, third-party React, JS that depends on user input.
Return ONLY a valid HTML document. No commentary. No markdown fences.Anthropic users get a self-correcting loop using message history. OpenAI users get the same outcome with structured outputs and a JSON schema. Both end in renderHtml().
// agent-anthropic.ts
import Anthropic from "@anthropic-ai/sdk";
import { renderHtml } from "hyperframes";
const claude = new Anthropic();
export async function makeVideo(brief: string) {
const draft = await claude.messages.create({
model: "claude-opus-4-7",
system: SYSTEM_PROMPT,
max_tokens: 4096,
messages: [{ role: "user", content: brief }],
});
const html = (draft.content[0] as { text: string }).text;
const lint = await renderHtml.lint(html);
if (!lint.ok) {
// Self-correction loop: feed issues back to the model.
const fixed = await claude.messages.create({
model: "claude-opus-4-7",
system: SYSTEM_PROMPT,
max_tokens: 4096,
messages: [
{ role: "user", content: brief },
{ role: "assistant", content: html },
{ role: "user", content: `Fix these issues:\n${lint.issues.join("\n")}` },
],
});
return renderHtml({ html: (fixed.content[0] as { text: string }).text });
}
return renderHtml({ html });
}// agent-openai.ts — structured output via JSON schema
import OpenAI from "openai";
import { renderHtml } from "hyperframes";
const client = new OpenAI();
const schema = {
name: "hyperframes_composition",
schema: {
type: "object",
required: ["html"],
properties: {
html: { type: "string", description: "A complete HyperFrames HTML document." },
notes: { type: "string" },
},
},
} as const;
export async function makeVideo(brief: string) {
const r = await client.responses.create({
model: "gpt-5",
instructions: SYSTEM_PROMPT,
input: brief,
text: { format: { type: "json_schema", json_schema: schema } },
});
const { html } = JSON.parse(r.output_text) as { html: string };
return renderHtml({ html });
}data-durationattribute is the worst dollar you'll spend. Lint is a millisecond.The hardest part isn't the model — it's the contract. We wrote it for you.