
HyperFrames: Editing Video with AI Through HTML Instead of Dragging a Timeline in Premiere
HyperFrames is a framework that uses HTML + GSAP + data-* attributes as the 'source of truth' for a video, editable in a normal editor, rendered out to a deterministic MP4 every time, with AI able to help write it fully. It has audio-synced captions, TTS, audio-reactive effects, transitions, and background removal, all complete in a single tool.
Everyone who has ever asked an AI to help make a video hits the same wall: ChatGPT/Claude can write beautiful code and generate accurate prompts, but they cannot write a Premiere/After Effects timeline for you. The .prproj and .aep files are opaque binaries that AI simply cannot touch.
On the dev side, people who have used Remotion since 2021 know the direct approach is "video as code", but Remotion is tied to React, with state, hooks, and side effects that make deterministic rendering messy.
HyperFrames is an idea that builds on this directly: HTML is the source of truth for the video, not a React component, not a Final Cut project, not some cryptic JSON schema. A composition is an index.html file with data-* attributes for timing, a GSAP timeline for animation, and CSS for the look. Open it in a browser to view it, open it in VS Code to edit it, and the git diff is readable.
This article is a primer for Thai developers who want to actually use AI to make videos, not just generate a prompt to hand off to Sora/Veo.
What is HyperFrames (in one sentence)
ref: hyperframes.dev
HyperFrames is a video editing framework that uses HTML as the source of truth. You write a composition as a normal HTML file, add data-start / data-duration on each element to specify timing, use a GSAP timeline for animation, and the CLI renders it out to an MP4 that is deterministic every time.
The basic unit is a composition, a single div that wraps every clip:
<div data-composition-id="root" data-width="1920" data-height="1080">
<video id="bg" data-start="0" data-duration="10"
data-track-index="0" src="hero.mp4" muted playsinline></video>
<h1 id="title" data-start="0.3" data-duration="4" data-track-index="1">
Sanoe POS
</h1>
<audio id="bgm" data-start="0" data-duration="10"
data-track-index="2" src="music.mp3"></audio>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
tl.from("#title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0.3);
window.__timelines["root"] = tl;
</script>
</div>That is really all there is. Render it with npx hyperframes render --output hero.mp4 and you get a usable MP4 right away.
How is it different from Premiere / After Effects / CapCut / Remotion
| Source format | Can AI write it? | Deterministic? | Diffs in git? | |
|---|---|---|---|---|
| Premiere Pro | .prproj (binary, zipped XML) | AI cannot touch it | sometimes (depends on plugin) | |
| After Effects | .aep (binary) | |||
| CapCut | proprietary JSON | closed | (binary-ish) | |
| Final Cut Pro | .fcpxml (XML) | writable, but very verbose | hard | |
| Remotion | React (.tsx) | watch out for useState/useEffect/Date.now | ||
| HyperFrames | HTML + CSS + GSAP | AI is good at it | (banning Math.random/Date.now is a rule) |
The key point: HyperFrames is not a Premiere replacement. It is not coming for the Color Grading or Audio Mastering work where you drag a fader. It solves the class of work that is reproducible, things like product launches, ad templates, social card animations, kinetic typography, captioned reels, work that a production team has to re-export every time marketing asks to change a headline.
Why it needs to exist, the design problem it solves
Three problems keep most teams' AI-powered video pipelines stuck at "generate a clip with Sora then manually cut it in CapCut":
- The source format is not readable. A
.prprojis a binary, no diff, no code review, and no AI agent can write it directly. The workflow you end up with is "Claude suggests, a person drags in Premiere," and the bottleneck is the person. - Non-deterministic rendering. Rendering in Premiere the first time and the second time can differ slightly (effect cache, GPU state, plugin version), which makes regression testing a video nearly impossible.
- AI can only generate a clip, not compose. ChatGPT/Sora can create a nice 5-second video, but "stitch it into a 30-second ad with captions synced to audio and a logo pinned to the corner" still has to be done by a person.
HyperFrames solves all three because:
- A composition is HTML, so it diffs, AI can write it, and it can be code reviewed through a PR.
- There is a hard rule against
Math.random()/Date.now()/setTimeoutin the timeline, so any render produces the same output, pixel-perfect. - An AI agent can write the entire composition file, not just "generate a prompt," from scene 1 through scene N.
Before / After, how it differs from the old way
Scenario A: caption sync to audio for a social reel
Before, the typical Thai content team workflow:
1. Director writes the script in a Google Doc
2. Voice-over talent records the mp3
3. The editor opens Premiere/CapCut, imports the mp3, listens, types captions word by word
4. Drags 800 timeline segments to match the speech rhythm, 30 min per minute of video
5. Marketing says "change the CTA at the end," go back to step 3
Human time cost: 30+ minutes per 1 minute of video, repeated every time the content changes.
After, the HyperFrames pipeline:
# 1. Create TTS narration from the script
npx hyperframes tts script.txt --voice af_heart --out narration.mp3
# 2. Transcribe to word-level timing (Whisper)
npx hyperframes transcribe narration.mp3 --out narration.json
# 3. Fill in the composition HTML that references narration.json
# The HyperFrames runtime syncs the captions to the audio per-word on its ownThe composition looks like this:
<audio id="vo" data-start="0" data-duration="30" data-track-index="2"
src="narration.mp3"></audio>
<div id="captions" class="hf-caption-track"
data-caption-src="narration.json"
data-start="0" data-duration="30" data-track-index="3">
</div>Edit the script, re-run TTS, transcribe, render, all within 5 minutes, with no timeline dragging at all. Thai works too because Whisper understands it.
Scenario B: a product launch that needs 5 language variants
Before, marketing needs 5 languages (TH/EN/JP/ID/VN):
1 Premiere project file, save as, edit text in 30 places, re-export, repeat 5 times
If the designer changes the logo color, redo everything
Time cost: 5 rounds x 20 min export = 100 minutes per single designer change
After, HyperFrames Variables:
<!doctype html>
<html data-composition-variables='[
{"id":"headline","type":"string","label":"Headline","default":"Welcome"},
{"id":"cta","type":"string","label":"CTA","default":"Try it"},
{"id":"locale","type":"enum","label":"Locale","default":"en",
"options":[
{"value":"th","label":"Thai"},{"value":"en","label":"English"},
{"value":"jp","label":"Japanese"},{"value":"id","label":"Indonesian"},
{"value":"vn","label":"Vietnamese"}
]}
]'># Render all 5 languages at once
for L in th en jp id vn; do
npx hyperframes render \
--variables "{\"headline\":\"...\", \"cta\":\"...\", \"locale\":\"$L\"}" \
--output "launch-$L.mp4"
doneChange the logo color in CSS once, render-all, done. No "save as" 5 times, no risk of forgetting to update a language version.
The difference in outcomes
| Before (timeline UI) | After (HyperFrames) | |
|---|---|---|
| How much AI can help | generate clip + prompt | write the whole composition file |
| Edit headline once, N languages | re-export N times | render-all via variables |
| Reproducibility | "close enough" | pixel-perfect deterministic |
| Code review | none (binary) | PR diff works |
| Caption sync to audio | drag manually | auto from Whisper JSON |
| Onboarding a new team member | teach Premiere | "read this HTML" |
The parts of a composition

The smallest possible HyperFrames file
<!doctype html>
<html>
<body>
<div data-composition-id="root" data-width="1920" data-height="1080">
<h1 id="hero" data-start="0" data-duration="3" data-track-index="1">
Hello HyperFrames
</h1>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = {};
const tl = gsap.timeline({ paused: true });
tl.from("#hero", { y: 60, opacity: 0, duration: 0.6 }, 0.1);
window.__timelines["root"] = tl;
</script>
</div>
</body>
</html>npx hyperframes preview starts a server, npx hyperframes render produces the MP4.
Data attributes, the commonly used ones
ref: HyperFrames docs
| attribute | required? | notes |
|---|---|---|
data-start | yes for every clip | seconds, or reference another id ("hero + 2") |
data-duration | yes for img/div/composition | video/audio uses the file's real length if not specified |
data-track-index | yes for every clip | integer; same-track clips must not overlap. Not related to z-index (use CSS) |
data-media-start | no | trim the head of the media file (seconds) |
data-volume | no | 0-1 for audio |
data-composition-variables | no | declare variables on <html>, drives the UI in Studio + defaults at render time |
The skills HyperFrames bundles, things that do the work on their own
These are the things an AI agent using HyperFrames can do directly without writing extra infrastructure:
| feature | command | real-world use case |
|---|---|---|
| TTS narration (Kokoro) | hyperframes tts script.txt --voice af_heart | produce broadcast-quality English voice-over in a single file |
| Transcribe (Whisper) | hyperframes transcribe vo.mp3 | create word-level JSON for caption sync, works for both Thai and English |
| Karaoke-style captions | <div class="hf-caption-track"> | sync to the audio, with marker sweep / sketchout / scribble emphasis |
| Audio-reactive | map FFT band to GSAP property | logo bouncing to the drum beat, background pulsing to EDM |
| Background removal (u2net) | hyperframes remove-background avatar.mp4 | cut a talking head out to place it on another scene |
| Transitions | crossfade / wipe / shader transition | scene changes that are not jump cuts |
| Lottie / Three.js / Anime.js / GSAP | adapter pattern bundled | embed motion graphics you already have right away |
Progressive Disclosure of the rendering pipeline
ref: HyperFrames overview
HyperFrames separates the dev-loop stages clearly, which lets an AI agent work accurately without wasting compute before it is needed:
| stage | command | use when | cost |
|---|---|---|---|
| Lint | npx hyperframes lint | after writing the HTML | < 1s, negligible |
| Validate | npx hyperframes validate | check WCAG contrast + structure | ~10s |
| Inspect | npx hyperframes inspect | check layout overflow visually | ~30s |
| Preview | npx hyperframes preview | view in the browser before rendering | live |
| Render | npx hyperframes render | produce the real MP4 | a minute to several minutes |
This means an AI agent writing a composition will:
- Write the HTML
lint+validate(a few seconds, catches syntax/structure errors immediately)inspect(check that text does not overflow the bubble)- Only then
renderat the end
Not "finish writing, render immediately, wait 3 minutes, find a bug, fix it, render again" the way the Premiere workflow goes.
Writing a good composition, 3 key rules
ref: Best practices in the hyperframes skill
1. Deterministic is a first-class constraint
The docs state it as a non-negotiable prohibition:
No
Math.random(),Date.now(), or time-based logic. Use a seeded PRNG if you need pseudo-random values.
If you want "random," use mulberry32 with a seed fixed into the HTML, so any render gives the same result. This rule is what makes regression testing a video possible.
2. Layout before Animation
The principle is to write the CSS layout of the "hero frame" (the moment when every element is on screen together) correctly first, then use gsap.from() to animate into that position.
Do not set a start state off-screen and guess where it will land. You cannot see the layout until you render, and it breaks at that point.
/* RIGHT, set the end state first */
.scene-content {
display: flex; flex-direction: column;
width: 100%; height: 100%;
padding: 120px 160px; gap: 24px;
box-sizing: border-box;
}// then animate INTO this position
tl.from(".title", { y: 60, opacity: 0, duration: 0.6 }, 0.1);3. Transitions are not optional
ALWAYS use transitions between scenes. No jump cuts. No exceptions.
A scene that cuts abruptly looks amateur immediately. HyperFrames bundles crossfade / wipe / reveal / shader transitions ready to use, no need to write them yourself.
HyperFrames vs Remotion, which one

This is the most direct comparison because both are "video as code."
| aspect | HyperFrames | Remotion |
|---|---|---|
| Source format | HTML + GSAP + data-* | React (TSX) + <Composition> |
| State / hook | banned (deterministic rule) | allowed, but be careful |
| AI writing | direct, HTML is what AI is best at | possible, but you must understand the React lifecycle |
| Bundled features | TTS, Whisper, background removal, captions, transitions | core engine, everything else is a separate package |
| Render | headless Chrome to MP4 | headless Chrome to MP4 |
| Adapter | GSAP / Anime.js / Lottie / Three.js / Web Animations API in the skill | useCurrentFrame() + props |
| Studio (visual editor) | yes (driven through data-composition-variables) | Remotion Studio |
| License / pricing | OSS | OSS + commercial license for large organizations |
Rule of thumb:
- If the team is a React shop and wants to reuse components, go Remotion.
- If the team is content/marketing-driven and wants the AI to write the video itself with built-in TTS/captions, go HyperFrames.
- If you want to port from Remotion to HyperFrames, there is a
remotion-to-hyperframesskill that can translate part of it for you.
The full pipeline, a real example
Making a 30-second social ad from a Thai script:
# 1. scaffold the project
npx hyperframes init my-ad
cd my-ad
# 2. make the voice-over from the script
npx hyperframes tts script.txt --voice af_heart --out vo.mp3
# 3. transcribe to word-level JSON
npx hyperframes transcribe vo.mp3 --out vo.json
# 4. write index.html (Claude/Cursor can write it for you)
# reference vo.mp3 + vo.json in the composition
# 5. dev loop
npx hyperframes lint && npx hyperframes validate
npx hyperframes inspect
npx hyperframes preview # view in the browser
# 6. render variants
for HEAD in "ลดราคา" "แจกฟรี" "ทดลองใช้"; do
npx hyperframes render --variables "{\"headline\":\"$HEAD\"}" \
--output "ad-${HEAD}.mp4"
doneAcross the whole process, the AI agent (Claude Code, Cursor) can write almost all of it on its own, with the person stepping in only to review through preview and to trigger the render.
Important gotchas for Thai developers
ref: hyperframes skill inside the repo
- Thai in HTML always needs a font-family that supports it. Premiere/CapCut have a font picker; HyperFrames uses plain CSS. If you set
font-family: "LINE Seed Sans TH"in CSS but do not place the.woff2infonts/, it falls back to Roboto, which renders Thai broken. Set up@font-facefully. - Whisper knows Thai but punctuation may be lost. After transcribing to JSON, check it before use; sometimes words run together (
สวัสดีครับวันนี้instead ofสวัสดี ครับ วันนี้) and you have to clean it manually. - Kokoro TTS still lacks a good Thai voice. For broadcast-quality Thai narration you have to use ElevenLabs/Azure, then transcribe it back into HyperFrames yourself.
- Do not use
repeat: -1. An infinite loop makes the render engine hang. Always compute the count from the duration:repeat: Math.ceil(duration / cycleDuration) - 1. videomust bemuted playsinlineon every one; the audio must live in a separate<audio>. Chrome's autoplay policy will not let a video play sound when it is being captured.- Paths with spaces must be quoted. A repo on
/Volumes/My SSD/...with a space in the name needs care when calling the CLI:npx hyperframes render --output "out/my video.mp4". - Do not animate
visibility/display. GSAP can only animate visual properties (opacity, transform, color). Useopacity: 0+pointer-events: noneinstead. gsap.set()on an element in a future scene does not work; the element is not in the DOM yet at page load. Usetl.set(selector, vars, timePosition)inside the timeline instead.
Summary
HyperFrames is the answer to "why can't AI edit video already," because until now the source format of video software was not something AI could write. Once the source becomes plain HTML, the whole pipeline changes:
- Stop dragging the timeline, write HTML, and AI can help fully.
- Stop exporting N times, use variables + render-all.
- Stop relying on the designer's memory, the composition is the spec, it diffs, and it reviews through a PR.
- Stop maintaining a separate caption pipeline, TTS / Whisper / caption sync live inside the framework.
If your team has repetitive video work (ad templates, product launches, social cards, captioned reels), try npx hyperframes init my-first-comp and write your first scene in 10 minutes. If you already use Claude Code / Cursor, install the hyperframes skill and Claude will write compositions for you from instructions in Thai (for example, "make a 5-second title card, blue, Sanoe, with a Thai subtitle").
See real examples and the component registry at hyperframes.dev, or if you want to port an existing Remotion project, there is a remotion-to-hyperframes skill that already helps translate it for you.
In 30 minutes you will have your first video that renders deterministically, that AI can help write, and that reviews through a git diff, unlocking your video pipeline from "human work" into real "code work."

