Debugging Implemented
Reproduce a bug by replaying the exact take that caused it, instead of trying to perform the same motion by hand.
Early-access beta · part of XRForge
Record XR movement in Unity Play Mode, save it as a take, and replay or loop it through the XR Device Simulator without putting the headset back on.
A take recorded once, looping in the Device Simulator.
You have put the headset on forty times to test the same grab. Every iteration on a VR interaction costs the same tax: headset on, find the object, perform the motion, headset off, read the console. Change one line, pay it again. The motion is never quite identical, so neither is the bug.
Start recording, enter Play Mode, perform the interaction once. Head and controller motion is captured frame by frame.
Takes are saved into the project, so they can be committed next to the scenes they exercise.
Replay the take through the XR Interaction Simulator — identically, every time, with the headset on the desk.
Reproduce a bug by replaying the exact take that caused it, instead of trying to perform the same motion by hand.
Run yesterday's take against today's build and see what changed.
Leave the headset on the desk. Develop and test XR interactions from your keyboard, anywhere — plane, cafe, couch.
Takes become fixtures. Replay them in play-mode tests and in CI, and fail the build when a scene edit changes what a take does.
Repeatable camera and hand motion, so you can retake the lighting without retaking the performance.
Let AI agents drive the simulator through MCP — automate testing and exploration without human input.
Implemented
A take replayed against the wall clock is a demo. Replayed against a virtual clock it is a fixture: the same events on the same frames, on your desk and on a loaded build runner. That is what makes a recording assertable. Replay records what the scene did as a signal trace, compares it against an approved golden, and exits non-zero when a scene edit changes the answer.
SixShots.golden.json approved
SixShots.actual.json this run
FAIL SixShots — 3 mismatches: 1 drifted past tolerance, 1 missing, 1 extra. Exit code 1.
Select, hover and activate are read off the XR Interaction Toolkit's own event stream, including objects spawned mid-take. Nothing to instrument, nothing added to your build.
A golden is plain JSON beside the take. It reads in a pull request, and re-baselining is always an explicit act — never a silent rewrite on failure.
Every run can be copied as a markdown report: the versions to reproduce it, each take's first divergence, rig drift, and the errors the game logged. Paste it into a ticket as it is.
A 60-second take does not cost 60 seconds of CI. Playback steps a fixed delta per frame, so physics and timers advance identically and the take runs as fast as the runner allows.
// One test covers every take that has a golden.
[UnityTest]
public IEnumerator EveryTake_MatchesItsGolden(
[ValueSource(typeof(XRReplayTest), nameof(XRReplayTest.TakesWithGoldens))] string take) {
yield return new EnterPlayMode();
var run = XRReplayTest.Run(take); // opens the capture scene
yield return run;
run.AssertMatchesGolden();
yield return new ExitPlayMode();
}
Before that job runs, a batchmode preflight checks in seconds that every take still has its golden, its recording and its capture scene — so a take committed without its trace fails fast instead of after a full play-mode run.
A take is an .asset profile and its .inputtrace
recording, plus a .golden.json once it has a baseline —
written into a project-relative folder. They commit to version control
next to the scenes they exercise,
which turns a bug report into something a teammate can replay rather than
re-enact. A reviewer runs the take instead of reading repro steps and
hoping they perform the same motion.
XRForge Replay is an Editor-only Unity package. It needs Unity 6.3 (6000.3) or newer and XR Interaction Toolkit 3.4.1 or newer. The XR Interaction Simulator it drives ships with XRI as an importable sample.
The documentation is open to early-access users now. If you have the access password, it is behind this link.
Read the docs