The Tight Loop
A combat-log parser, a Godot test game, and a hosted multiplayer network walked into a bar. Forty-eight hours later they were a working 3D replay viewer. This is the field test for the Mech Suit Methodology, with the receipts.
The Mech Suit article ended on a claim. When the workflow is dialed in, the human-AI loop has enough throughput that you can research and prototype in real time. This is the receipts piece for one such loop, dated this week.
The work: a 3D replay viewer for World of Warcraft combat logs, rendered in Godot, fed by the same parsed JSON that drives an existing 2D web viewer. Twenty-one orbs, class-colored, glowing rings under the selected ones, profile card on the side, scrubbable timeline at the bottom. From idea to operator-ready in two slices over two days.
This is not normal. That is the whole point of writing it down.
Three Independent Things.
Three things existed before this slice. None of them knew about each other.
RaidUI is a combat log parser and 2D replay viewer that I built over the last several months. It chews through a multi-hundred-megabyte World of Warcraft combat log, segments it into pulls, normalizes positions to a unit-square arena bounding box, and emits one JSON file per pull. A web canvas renders dots gliding around. There is an LLM coach that runs locally through Ollama. It works.
There is a Godot 4.6 test game in a separate repo. Custom WebSocket client, signal-based entity lifecycle, server-authoritative thin client. The game itself is unfinished but the engine plumbing works. It has a follow-cam, an entity spawning system, smooth interpolation between server snapshots.
There is a multiplayer network stack hosted somewhere with my name on it. Nothing currently uses it for production load. It exists, it works, it is a sunk cost waiting for a use.
The premise was simple. Bridge them. Render the replay as 3D orbs in Godot, with the same data driving both views. Multiplayer co-presence on top eventually, but not yet.
This is the kind of project that traditionally produces a tech demo and stalls. The data is too thin. The renderers want different things. Schemas drift. The two-views-one-divergence-problem is its own genre. I have lived it before.
This is not the story of that.
Replay Is an Event Source, Not a Visualization.
Two sync problems hide inside “make it 3D.”
The first is replay data delivery: getting per-tick world state into the Godot scene. The second is multiplayer co-presence: peers seeing each other’s cameras, pings, scrubber position, highlights.
The instinct, especially when there is already a network stack, is to bundle them. Stream the replay over the network. Let the network be the spine. Multiplayer falls out for free.
That instinct is wrong, and recognizing it on day one was load-bearing for everything that followed.
The right move is to treat the replay as a deterministic event source. The same parsed JSON drives any renderer that subscribes to it. The contract between RaidUI and Godot is the JSON file, not the wire protocol. Multiplayer coordination (cameras, pings, scrubber DJ) is a separate problem that lives on top, optional, layerable.
Every design decision in the slices that followed traces back to this call. The Godot loader bypasses the existing live-game WebSocket client and writes directly into the game state’s signal layer. The coordinate mapper is replay-specific, not a generalization of the live game’s server-coord mapper. Parser-side interpolation lives in a single resampler function, not in the renderer. None of these are clever ideas. They are obvious moves once the architectural call is made.
Slice 0. Everything I Could Cut, I Cut.
Slice 0 was deliberately tight. Six items in scope, six items explicitly out.
In: schema version + replay identity validation, parser-side interpolation, a Godot loader as a fake game-state driver, class-colored orbs spawning through the existing scene path, the existing follow-cam, loud failure on schema mismatch.
Out: scrubber, free-cam, trails, AoE markers, multiplayer, every visualization beyond “orbs on a flat plane.”
Acceptance: load one known pull, watch all entities move continuously on flat ground for two minutes. Schema mutation produces a red panel and zero spawned orbs.
That was the entire slice. About 370 insertions on the parser side, 220 on the Godot side. One commit each.
Two design decisions inside slice 0 were specifically architectural.
First: the parser already emitted a contract-stable JSON file but did not include a schemaVersion field. Adding one was a one-line change in the build step plus a small addition to the JSON schema. Adding it before writing the validator means the validator can hard-fail on missing or mismatched version. No silent fallback. No pretending the file is valid when it is not. The mutation test (change schemaVersion: “v1” to schemaVersion: “v123231”) returned a red REPLAY FAILED panel and zero spawned orbs on the first attempt.
Second: the existing parser used carry-forward resampling at 200ms grid frames. That works fine for the 2D renderer because the canvas overlay paints fading trails that mask the freeze-then-snap pattern. In 3D with no trails, the snaps would be visually obvious. The fix was to add a sibling resampleLerp function that does grid-anchored linear interpolation between bracketing samples. The original resample stayed (preserving every existing test), the new function landed in twenty-five lines, and the build step swapped one call for the other. This kind of change exists in two-day form because the resampler was a pure function with one job.
By the end of slice 0 I had a Godot scene with twenty-one class-colored orbs gliding around on a flat green plane. The user response was “IT LIVES!!!” That was the unlock for slice 1.
Slice 1. Six Tracks. Two Batches.
Slice 1 was the merged build. Free-cam, scrubber HUD, hover tooltips, click-to-select with shift-click multi, profile card with a Highlight toggle, plus a small cleanup that descoped to slice 0.5 (hide the legacy world HUD that was bleeding through onto the replay scene). Six things, planned in five parallel tracks.
The architectural through-line is a SelectionManager autoload bus. It owns the set of selected entity IDs and a per-entity highlight-enabled flag. Visual consumers (the highlight ring) and UI consumers (the profile card) subscribe to a single SelectionChanged signal. Future visualization toggles (defensive timelines, trinkets, target-switching) slot into the same profile card section without rewiring selection.
Implementation ran in two parallel batches.
Batch one: the autoload registration in project.godot, two surgical edits to World.cs (a public Entities accessor and SetMeta calls so raycasts can resolve cursor to entity), eight new C# files (SelectionManager, ReplayRaycast helper, FreeCamController, HoverTooltip, SelectionInput, HighlightRing, ProfileCard, ScrubberHud). Independent files. Single tool call from the AI side. Single message.
Batch two: five sequential edits to the Godot loader (add fields, add properties, add HideLegacyHud call in _Ready, modify the timer’s wait time calculation, add the playback API methods at the bottom), plus one rewrite of the scene file to wire the new nodes.
dotnet build: zero warnings, zero errors. F6 in the editor. The user walked through the acceptance checklist: free-cam, scrubber, tooltips, single select, multi select, highlight toggle, slice 0.5 cleanup. Six checks. All passed first try.
Twelve files changed. About 770 lines of new code. Single commit on the master branch of the game repo.
“Everything Works. Great Job.”
That was the user’s response after the slice 1 walkthrough. Four words.
Game development has a reputation. Brute force, under-tested, “feel” criteria that resist test expression. The reputation is mostly earned. A single developer shipping a polished twenty-one-entity 3D viewer in two days, with click selection, profile cards, a scrubbable timeline, and class-colored highlight rings, on the first acceptance walk-through, is not the median experience.
This is the part of the article where it would be easy to overclaim. Skill matters. The architectural calls were not random. The codebases were not green-field. RaidUI’s parser had been hardened over months. The Godot project had a sane signal architecture from the start. The schema discipline that made everything cheap was not free. It was paid for in advance.
What is genuinely surprising is the pace. Twenty-plus years of writing software, and the loop closing this fast still felt like a different category of experience. Not “AI helped me code faster.” More like having a colleague who had read every line of the codebase, had infinite patience for design conversations, and could draft 600 lines of new code in the time it takes to make coffee.
Why The Loop Was Tight.
Three forces. Each one is a discipline, not a tool.
Schema discipline. RaidUI’s parser already emitted a contract-stable JSON file. Every renderer (existing 2D canvas, new 3D Godot scene, theoretical future WebXR) reads the same file. Adding schemaVersion and bossName to the contract on day one means consumers can hard-fail on mismatch and never see corrupt data. Adding this kind of discipline to a project that does not have it is its own multi-month project. It cannot be retrofitted in a slice. But where it exists, agents and renderers can be added without renegotiating the contract.
Slice scoping. Each slice had explicit in-scope and out-of-scope lists. The out-of-scope list was longer than the in-scope list. The Mech Suit principle of “one concern per worker” generalizes here: one concern per slice. Slice 0 was foundation. Slice 1 was the operator surface. Slice 2 (defensive timelines, trinkets, target-switching) waits for parser-side data work. Each slice ships, gets walked through, gets committed, and only then does the next slice get planned.
Architect-builder split. The architectural conversations (replay as event source, additive ingest methods on game state, OKLCH-to-sRGB at port time, SelectionManager as a bus, the camera framing math, the validation specifics) happened in dialogue. Once the calls were made, the implementation was 95% mechanical. Two parallel batches landed cleanly because the design conversation absorbed the failure modes ahead of time.
None of these forces are about the model getting smarter. The model has gotten better, but the loop tightening is mostly about the discipline.
What I Would Tell An Earlier Version Of Myself.
Build the data layer first. Renderers are subscribers. The contract is the architecture. If the data layer is sloppy, every downstream consumer pays for it forever.
Hold the line on slice scope. Three days of foundation that lets six features ship in one batch beats six features over six weeks. Saying no to the second feature is how the first one becomes solid enough to carry the rest.
Refine expensive, execute cheap. Architectural conversations pay for themselves immediately. Have them with the architect-mode AI. Do not have them while you are typing.
Watch for the moment your colleague says “everything works” on first try. That is the loop closing. Notice it. Write it down. The pace is the news, not the artifact.
This is still early. The tools keep getting better. The disciplines are still being figured out. What I know now that I did not know two days ago is that the throughput available to a single practitioner who has done the schema discipline work in advance is genuinely a different category of capability than what most teams I have worked with operate at.