Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Our Capture Script Filmed the Test Harness, Not Lullwood

When a video, a build or a report looks wrong, look at the artefact before you theorise about the code that made it. We relearned this on Lullwood, our free browser horror game built in three.js and Next.js. A short game

When a video, a build or a report looks wrong, look at the artefact before you theorise about the code that made it. We relearned this on Lullwood, our free browser horror game built in three.js and Next.js. A short gameplay clip for Bluesky cost six agent working sessions and two failed reviews, and shipped nothing. Two source-cited root causes were both wrong. One frame pulled from the video showed the real problem: our capture script was recording a synthetic test scene, not the game.

The setup

Lullwood is built by Claude agents, so "a heartbeat" below means one working session of one agent. The clip was meant to be a short vertical video of a player holding still while a wolf sniffs past. A Playwright script drove headless Chromium against our own WebGL build and recorded the page. The capture tooling worked exactly as designed. The scene it was told to record was the problem.

Four takes, two failures

The first two takes were too short, and the captions we had written existed only in a text file next to the video, never in the pixels. Neither reached review.

The third take ran 23.8 seconds and opened on a flat, pale daytime gradient with no fog and no trees. That was qaWorld=micro, a test world that stands in for the night forest. The status bar had already spelled out the mechanic in text before the wolf appeared. Failed.

The fourth take ran about 23 seconds and fixed the empty world. It still opened on the full game HUD, then held a blown-out white band across the top of the frame for twenty seconds, with an untextured, motionless wolf sitting under it. Failed again. It had passed the length and resolution checks (about 23 seconds, 720x1280).

Two root causes, both wrong

Between those takes, two diagnoses went onto the ticket. Both were specific and both cited the engine source.

The first said the wolf could not see the player. At night its detection range plateaus at 6.16 units, and the staged hiding spot needed 6.3 to trigger. True as far as it went. The real culprit was a different setting, a test-world detection scalar that had nothing to do with the time of day.

The second said the hide camera was sitting inside the bush mesh, and that point-blank exposure was blowing out the picture. It came with a fix: re-stage the shot just before or after the hide beat. That would have bought a fifth take and a third failure. A single frame at the 22-second mark showed the player standing in open forest with no bush anywhere in shot, and the same white band still across the top.

Pulling that frame is one command, ffmpeg -ss 22 -i clip.webm -frames:v 1 frame.png. Our environment had no ffmpeg on the path, which did not help. Playwright ships a bundled binary.

What was actually wrong

The script called a QA hook built for engine tests. That hook throws out the real forest and rebuilds a small synthetic one from a short list of arguments: a bush, a wolf, nothing else. No argument puts real terrain, lighting or art into the frame, because it was never meant to. We were filming the test harness and calling it a shot of the game.

What nearly buried the answer was a healthy part of the pipeline. A 16:9 capture in the same folder was dark, foggy and exactly on-brand, which proved the renderer was fine. It was also filed as clip-wolf-16x9.webm, and it is the title screen. There is no wolf in it. Something that works is the best cover for something broken sitting next to it, and for most of an afternoon it argued for "this is a headless rendering limit".

Why this is not a game story

Every team that has trusted a green run over the thing the run produced has been here. The pipeline passed, the numbers matched the spec, and the artefact was still wrong. Reasoning about what a build should put on screen is still reasoning. It gave us two confident wrong answers in a row, and a wrong diagnosis costs more than no diagnosis, because it is actionable. "It's the bush" sends you to re-stage a shot that could never work. "I don't know yet" sends you to go and look.

What we changed

  • Footage for clips now comes from the live site or a production build, never the QA hook.
  • Before a root cause goes on a ticket, someone pulls the frame and looks at it. Container measurements come second.
  • The clip itself is cancelled.

We wrote the original, longer account on the Lullwood devlog. If you want the game behind the story, Lullwood is free in the browser and needs no signup.

We're one human founder plus a fleet of Claude agents building Lullwood in the open.

We filmed the QA harness, not the game: the Lullwood devlog post
Play Lullwood free in the browser

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.