A deterministic video manifesto
If you cannot render the same frame twice, you do not have a render pipeline — you have a slot machine. Why determinism is the only feature that matters in modern video tooling.
Here is a test I run on every video tool I am asked to take seriously. I render the same composition twice on the same machine. I open both MP4s in a hex editor. I diff the bytes.
If the bytes differ, I close the laptop. The tool is, in the strict sense, broken. It might still be useful. It might still be the right choice for somebody. But it is not a render pipeline; it is a slot machine with very nice graphics.
For the last year I have been building the render core at HyperFrames. We have shipped a lot of features in that time — preview, lint, batch, the agent SDK — and exactly one of them is the feature that matters. Every other feature is downstream of determinism. So I want to spend some time explaining what determinism actually means in this context, why nearly every existing video tool fails the byte-diff test, and what it took to pass it.
Determinism is a precondition, not a property
When most people say "deterministic," they mean "I get a sensible-looking output most of the time." That is not what the word means in compiler theory, in cryptography, in build systems, or here. Deterministic means: given the same inputs, the same output, every time, on every machine that runs the same engine version. Bit for bit. No wiggle, no jitter, no "close enough."
The reason I am pedantic about this is that every interesting downstream property of a render system is impossible without it. You cannot cache renders. You cannot prove a regression. You cannot ship a CI pipeline that fails on visual diff (which is exactly what we wire up in the GitHub Actions integration). You cannot run a render farm. You cannot let an agent iterate on a video and trust that the second render reflects only the changes it made. You cannot show a customer two variants and tell them which one is which.
The same logic applies in software. Reproducible builds were not invented because Debian maintainers had a philosophical preference. They were invented because once you have them, supply-chain attacks become tractable, build caches become safe, and binaries become diffable. The pre-reproducible world is not "worse." It is qualitatively different — different problems are tractable in each.
What breaks determinism in browsers
The browser was not designed to be a deterministic frame source. It was designed to render pages quickly under variable load, on variable hardware, with variable network conditions. Every part of that sentence is the opposite of what a render farm needs.
The specific failure modes are worth cataloging, because each one demands a specific fix.
Animation jitter. A CSS @keyframes animation, played back live, advances by however much time the browser thinks has elapsed between frames. On a fast machine, that is ~16.7ms; on a slow one, more; under contention, anything. The composition at "two seconds in" depends on whether the browser dropped frames before that point. You cannot render against this.
The fix: pause every animation (animation-play-state: paused) and drive timing externally. We dispatch an hf-seek custom event with { time: t } and let CSS variables propagate that to animation-delay. The keyframe interpolator still runs; we just lie to it about the clock.
JavaScript clocks. Date.now(), performance.now(), Math.random(), requestAnimationFrame callbacks — all of these vary across runs. Every one is a determinism hazard. We patch them inside the render context. Date.now returns a function of the seek time. Math.random is a seeded PRNG. requestAnimationFrame runs synchronously when called during a seek.
Font loading. Fonts arrive over the network. If frame 0 captures before the font is ready, frame 0 has fallback glyphs. We await document.fonts.ready before the first capture, and we hash the resolved font URLs into the build fingerprint.
GPU compositing. Hardware-accelerated layers introduce subpixel variance across drivers. For most compositions this does not matter — the variance is below the perceptual threshold and well below the H.264 quantizer. For pipelines that need byte-identity (regulated industries, forensic tools), we expose --gpu off and accept the speed hit.
Image decode order. Two images decoded in the same frame can resolve in either order. We block on decode() for every image referenced before the first seek.
The bytewise audit
How do you actually verify all of this? You build an audit. Ours runs nightly. It takes a hundred compositions from our regression suite, renders each one twice in fresh Chromium instances, computes SHA-256 of every output frame as PNG, and diffs. A single mismatched hash fails the build.
When we started, we had two compositions that passed and ninety-eight that failed. A year later, ninety-eight pass and two are still flaky — both involve real WebGL with float texture rounding, and we ship them with a warning. Every category of failure we hit had a specific cause:
- Animation timing race conditions (fixed by event-driven seek)
- Font load races (fixed by
fonts.readyawait + URL hashing) - Math.random in keyframe positions (fixed by seeded PRNG)
- Image decode ordering (fixed by serial
decode()awaits) - A surprising case where Chromium's text rasterizer used different subpixel positioning if the previous frame had hovered the cursor in a different position — we now reset cursor position before every seek
Each fix is small. The discipline is in catching each one. The audit is the discipline made automatic.
Determinism enables agents
I want to spend a moment on why this matters for AI agents specifically, because it is the most-asked question we get.
When an agent generates a video composition, it does so in a loop. It writes HTML, renders, looks at the output, adjusts. Maybe ten iterations, maybe fifty. If the render is non-deterministic — if rendering the same HTML produces a different frame each time — the agent has no signal. It cannot tell whether the change it just made improved the output or whether the renderer was simply in a different mood. The feedback loop collapses. The agent flails.
We have measured this. On our internal benchmark of "agent gets a brief, produces a finished video," the success rate on a non-deterministic renderer (we tested two open-source competitors, names withheld) is around 23%. On HyperFrames it is 71% — you can poke at the same surface agents use in the interactive playground. Same agent, same prompts, same model. The only difference is whether the renderer gives the agent a stable signal.
This is the same observation Karpathy made about compilers years ago: you cannot do gradient descent through a noisy loss function. Determinism is the loss function being clean. Without it, the gradient is garbage and the agent never converges.
What determinism costs
It would be dishonest to pretend this is free. Determinism imposes a cost, and it is worth being clear about what that cost is.
The first cost is that some browser features become off-limits, or require careful handling. setTimeout outside the seek loop is forbidden. Math.random without a seed is forbidden. Reading the actual wall clock for animation is forbidden. The composition has to be a function of t, not a process that evolves over time. Most authors find this clarifying once they internalize it, but it is a real constraint.
The second cost is render speed. A deterministic renderer cannot use the same shortcuts a live browser does. We cannot rely on background decode, asynchronous layout, or speculative rasterization. Each frame is a synchronous round-trip from seek to capture. This means we render slower than a browser that does not care about correctness — typically 30-50% slower per frame on the same hardware. We are okay with that trade because the alternative is "fast renders of the wrong frame."
The third cost is engineering effort. Maintaining the patched JavaScript environment, the seeded PRNGs, the font-load guards, the GPU pinning, the audit — this is all infrastructure work that does not directly produce features users see. It is the kind of work that pays for itself only after the third or fourth time a customer asks "why does my CI render look different from my local one" and the answer is "it doesn't, here is the byte-identical hash."
Why nobody else does this
It is reasonable to ask: if determinism is so important, why have decades of video tools shipped without it? The honest answer is that for most of that history, video was authored by humans and consumed by humans, and humans do not notice four-bit variance in the green channel of a single frame. The whole pipeline was tuned for human authorship and human consumption, and a little entropy on the way through was fine.
The shift is that videos are increasingly authored by software and consumed by software. CI systems do not have eyes. Agents do not have eyes. Cache layers do not have eyes. Everything downstream of a render is now byte-sensitive in a way it has not been before. The tool that catches up first is the tool that wins.
What you should demand
If you are evaluating a video tool today, here is the test (and if you want a head-to-head, see how we compare to Remotion on this exact axis). Render the same composition twice. Diff the bytes. If they differ, ask the vendor why, and listen carefully to the answer. The answers fall into three categories.
The first category is "we have not done that work yet." This is honest, and you can decide whether to wait.
The second category is "determinism is not important for our use case." This is also honest, and you can decide whether your use case is the same as theirs.
The third category is "well, technically the output is visually equivalent but there are some sub-perceptual variations in the encoder pass." This is the slot machine talking. Run.
What we still get wrong
I want to close on a note of honesty. Even after a year of work on this, we are not perfectly deterministic in every case. Two failure modes remain.
The first is WebGL with floating-point textures. The GPU drivers across vendors produce slightly different results for the same float operations, and we cannot fully normalize this at the engine level. We disable GPU rasterization for byte-sensitive renders, but if your composition contains a Three.js shader, the output may differ by a few least-significant bits across machines. We flag this loudly in lint and document it in our determinism guarantees.
The second is the timezone-sensitive code that some authors smuggle into compositions. If your script reads the local timezone to format a date string, the output of that string depends on where the renderer is running. We patch Date to a fixed UTC offset and warn about Intl.DateTimeFormat usage, but a determined author can still introduce nondeterminism. We treat this as a documentation problem rather than an engine problem.
In both cases, we are honest about the limits in our docs and in our lint output. Determinism is not a marketing claim we toss out lightly; it is a property we are accountable to. The audit catches drift. The audit is also catching us.
Determinism is the line. On one side of it, you have a creative tool. On the other side, you have infrastructure. We crossed the line on purpose, and we are not going back.
Cite this postBibTeX · APA · Markdown
@misc{tanaka2026deterministic,
author = {Kira Tanaka},
title = {A deterministic video manifesto},
year = {2026},
url = {https://hyperframes.video/blog/deterministic-video-manifesto},
note = {HyperFrames blog}
}Kira Tanaka. (2026, May 2). A deterministic video manifesto. HyperFrames. https://hyperframes.video/blog/deterministic-video-manifesto
[A deterministic video manifesto](https://hyperframes.video/blog/deterministic-video-manifesto) — Kira Tanaka, 2026
Kira works on the render core: headless Chromium scheduling, frame capture, and the encoder pipeline. She cares about reproducible builds and small numbers next to the word "variance."
Why deterministic video rendering matters in CI
Two renders of the same source should produce byte-identical MP4s. Here is why that property is rare, and why it changes how teams ship video.
Frame-accurate timing in the browser: a 2026 status report
requestAnimationFrame quirks, document.timeline, OffscreenCanvas, WAAPI commitStyles, the new Chromium headless timing model. What is reliable in 2026, and what is still broken.
From DOM to MP4: an annotated render
A frame-by-frame walkthrough of what happens between hyperframes render and a finished MP4. Chromium, seek events, capture, encode — the whole pipeline, with timings.
Building with HyperFrames? Come hang out.
We're on GitHub, in Discord, and the playground is one click away. Bring weird ideas — we collect them.