Frame Perfect

Deterministic replay for game studios

Every crash,
reproducible frame for frame.

Capture your game's inputs, RNG, and state so any reported bug replays frame for frame, on demand.

replay.tower seed 0x9F2CTowerStanding OK
f0000 hash 0x00000000
frame timeline... frames at 60 fps
Capture
SIG-1041
OUT_OF_BOUNDS
player.z = -1.04e3
capturedreplay ✓
SIG-1058
NAN_VELOCITY
vel.x = NaN
capturedreplay ✓
Diverge
SIG-1092
DESYNC
hash split @ f1042
capturedreplay ✓
SIG-1109
SOFT_LOCK
state frozen 9.6s
capturedreplay ✓
Cluster
SIG-1143
HEALTH_NEG
hp = -14
capturedreplay ✓
SIG-1160
INVARIANT
Upright violated
capturedreplay ✓
SIG-1177
ASSERT_FAIL
qpos NaN @ contact
capturedreplay ✓
Reproduce
SIG-1211
MIN_REPRO
44 -> 5 steps
capturedreplay ✓
SIG-1228
PATCH_PASS
family fixed · exit 0
capturedreplay ✓

The raw stream

Thousands of failures, in flight.

Every captured session lands as a signature in the stream. Scroll to fly through it, on the way to the pipeline that turns it into order.

capture stream·frame 0000

The raw stream

Thousands of failures, in flight.

Every captured session lands as a signature in the stream, on the way to the pipeline that turns it into order.

OUT_OF_BOUNDS
player.z = -1.04e3
NAN_VELOCITY
vel.x = NaN
DESYNC
hash split @ f1042
SOFT_LOCK
state frozen 9.6s
HEALTH_NEG
hp = -14
INVARIANT
Upright violated
ASSERT_FAIL
qpos NaN @ contact
MIN_REPRO
44 -> 5 steps
PATCH_PASS
family fixed · exit 0

What turns a bug from a guess into a fact

Deterministic replay

One seeded PRNG, a fixed timestep, and float-quantized state hashing capture a run so it replays bit for bit. If it happened once, it happens again, on demand.

Invariant clustering

Anomalies group by the rule they broke and the state they broke it in. Different stack traces, one root cause, one ticket.

Repro tickets

Every ticket is severity-ranked and re-triggers inline from its trace. Triage stops being archaeology.

deprecated

Everything it makes obsolete

  • manual repro steps
  • "cannot reproduce"
  • screenshot debugging
  • works on my machine
  • flaky bug reports
  • duplicate tickets
  • guesswork triage
  • regression spreadsheets
  • print-line debugging
  • video scrubbing by hand
  • stale QA checklists
  • ad-hoc repro scripts

One captured trace replaces the whole pile. Move the cursor through the wreckage.

triage

From a wall of errors to one root cause

crash-channel.log12 reports
WARNinput desync suspected on client 2
ERRNaN in Rigidbody.velocity.x
ERRNullReference: PlayerController.Update()
WARNframe time spike 84ms (budget 16.6)
ERRsoft-lock: FSM stuck in 'stagger'
ERRcheckpoint hash split @ f1042
WARNGC alloc 2.1MB in hot path
ERRout-of-bounds: player.z = -1.04e3
WARNanimation event missed
ERRhealth < 0 after parry
WARNaudio voice limit reached
ERRphysics tunneling through floor
root cause found
Desync, not twelve bugs.
family
FAM-03
reports merged
7 to 1 stack hash
first divergence
checkpoint @ f1042
minimal repro
5 inputs
P(repro)
100%

The analysis engine

From one reproduced bug to the whole story.

Deterministic replay catches a bug once. The analysis layer turns it into the full picture: what diverged and when, every other bug that shares its root cause, how flaky it is, the shortest way to trigger it, whether a patch actually fixed the family, and whether it ever comes back.

Engine-state diffing

Align a buggy run against a passing reference and pinpoint the first frame they diverge, over structured state, never screenshots. That first-divergence frame is the highest-signal root-cause cue.

first-divergence frame

Root-cause families

A trace encoder (signature + divergence pattern + trigger) feeds a FAISS index and HDBSCAN. Superficially different traces that share one root cause land in one family; new traces route online or flag as novel.

cluster purity 1.000

Reproducibility profiles

Replay K times under identical seed and inputs for P(repro), then vary one axis at a time to classify the bug: deterministic, seed-sensitive, frame-timing race, or desync.

P(repro) + sensitivity

Minimal repro (ddmin)

Delta-debug the input down to the few steps that still reproduce the same failure signature, confirmed by the diff and repeated for flaky bugs so a needed step is never dropped.

shortest reproducing steps

Patch verification

On a new build, re-run the original, its minimal repro, and a sample of the whole family. Reports fixed / still-failing / partially-fixed / new-regression as a CI-gateable check.

CI exit code

Natural-language search

An LLM turns a plain-language report into a structured state-pattern query; matching runs over the real indexed state, so results are grounded, with no hallucinated matches. The LLM is budget-capped.

grounded, cost-controlled

One canonical trace, any engine.

Every engine implements one adapter that emits the same structural `BugTrace`. The core never imports an engine, so the whole analysis stack runs identically on Unity, Unreal, Godot, or a real MuJoCo sim.

Game enginesinstrumented build, or run in-process
UnityUnrealGodotMuJoCo
EngineStateAdapterthe core imports no engine
one canonical interface
Canonical BugTracestructural only, never pixels
inputs · per-frame state · signature
Analysis coreoffline, observable, cost-controlled LLM
FAISS · HDBSCAN · ddmin · deterministic replay
Monitorread-only, with live ETAs
the website, behind login

Connects to your engine

One adapter emits the same canonical trace, so the whole analysis stack runs identically on the engine you already ship in.

Unity
Unreal
Godot
Roblox
Bevy
CryEngine
GameMaker
Construct
PlayCanvas
Cocos
MonoGame
Source
Stencyl
Unity
Unreal
Godot
Roblox
Bevy
CryEngine
GameMaker
Construct
PlayCanvas
Cocos
MonoGame
Source
Stencyl

Unity, Unreal, and Godot today. Anything that can emit a BugTrace next.

One ticket, reproduced on click.

A real ticket from the live dashboard: three reports merged into one, with the invariant it broke and a trace that reproduces it bit for bit. Hit re-trigger.

Open the monitor
ticket · tk-arm 3 reports merged

JointInBounds violated in RobotArm

high

A scripted overdrive commands the elbow joint past its safe range, slamming it into the hard limit. Validated on MuJoCo: the same trace replays bit-for-bit, and the joint reaches the limit on every run.

JointInBoundsscene · RobotArmMuJoCo · overdrive
JointLimitException: j2 exceeded safe range at Arm.Step()
AssertionFailed: |jointAngle| <= 2.4 rad at SafetyMonitor.Check()
the arm slams into its limit and judders when you overdrive the elbow
16 checkpoints on file

One platform, every part of QA

Reports that share a root cause collapse into one severity-ranked ticket. Your morning starts with a list that is already deduplicated, not a channel full of the same crash filed five times.

100%of replays land bit-for-bit
320steps re-executed per trace
3physics environments validated
1e-4hash grid: drift below it is ignored

Questions, answered

Every source of randomness flows through one seeded PCG32 generator, gameplay advances on a fixed timestep, and state is quantized to a 1e-4 grid before hashing. Given the same seed and inputs, the run is a pure function of (state, input, rng), so it reproduces bit-for-bit.

Reports are clustered by the invariants they violated and the state region they fired in, weighted over stack-trace and game-state similarity. Different stack traces with the same root cause collapse into one severity-ranked ticket.

PhysX is not reproducible across runs, so we do not promise bit-for-bit replay of a Rigidbody pile. Two honest paths: drive a deterministic simulation you own (guaranteed replay), or capture inputs and checkpoint hashes over PhysX and let the harness flag nondeterminism as a desync canary. The Unity package ships both.

Yes. We validated the same guarantee on MuJoCo across three environments (a box tower, a robot arm, and a humanoid), each with a planted bug. Every run replays bit-for-bit; perturb one input by two percent and it diverges at the contact moment. The clips on this page are those real runs.

Drop in the Frame Perfect Unity package, implement IDeterministicSimulation over your gameplay, and it records the seed, PRNG state, input log, and checkpoint hashes. The moment an invariant fires it writes a re-triggerable trace and ships the anomaly to ingestion.

Reproduce the irreproducible.

Capture the run once, reproduce it on command, and ship the fix with confidence. Free to start, no card required.