Kirino 的游戏宝藏
← Back to issue 022
Game observation

1.4 Seconds and Eight Million Pixels in Replay, How Alex van Rossum Used Digests to Nail Wreckwing Stutters into Reproducible Labor

If the default craft for destruction-flight games is often "make the collapse look loud first, then kill hitching by feel—turn effects down, cut fragments, guess which frame is…

Saved articles ↗

If the default craft for destruction-flight games is often "make the collapse look loud first, then kill hitching by feel—turn effects down, cut fragments, guess which frame is expensive," then in early October 2026 the numbers Alex van Rossum of Dutch indie studio Trilithon Games laid out in his engine devlogs rewrote that default bill into a replayable work order. The game is *Wreckwing*, on Mac Apple silicon, on the in-house Trilithon Engine: Swift, Metal, and Jolt Physics. There is no store page yet; the title is still in development. This essay did not play a finished build. Scenes and figures below come from the author's public posts and the studio site.

I lined up the engine notes I could find. The hard facts are plain. On October 6, large-city play hit many slowdowns, once almost a crawl. Telemetry put them in simulation, 0.7 to 1.4 s after charges that broke 140 to 500 structure pieces. Stalls reported in play ran from 0.2 to 1.4 s. Around the same week they also wrote about determinism digests, headless replay, and how lighting can skip pixels in a 4K frame. Drafts were written with Claude Code in the repo; Alex van Rossum reviewed every figure.

The through-line of this piece is replay, and the digest. They sound like tool names. On the craft side they are a checkable promise. Make the world repeat under the same fingerprint first, then talk about which cut saved time. Savings must leave evidence. Timing changed. The world fingerprint still matches.

Wreckwing tower collapse

1. Industry default, guess the hitch, cut effects to "optimize"

Everyone knows destruction is expensive. An explosion fractures structure, debris keeps each other awake, and the renderer still has to strip parts that already broke. The default workflow is fixed too. First say by feel that "it must be physics," then try fewer fragments, freeze rubble sooner, or drop light and shadow tiers. Players learn the same vocabulary. They say the game hitch after a blast, or skip High in big cities. That mutual understanding makes guessing a forgivable production grammar.

*Wreckwing* raises the cost of guessing. It is destruction flight across large cities. One missile can carve a crater tens of meters wide. A rocket barrage can wake tens of thousands of freshly broken bodies. The expensive second often stacks removal hooks, terrain dedupe, blast presentation, mesh compaction, and support checks, each able to add tens to hundreds of milliseconds. If you only feel which frame hitchs, you can fix the wrong cause, or fix the right one and change the world.

The fork is here. The default asks what effect to turn off so the frame rate looks better. They asked whether that 1.4 s could be pinned as a replayable session first, then measured and fixed item by item, with a world fingerprint proving the collapse players meet is still the same collapse.

Stalls-by-replay devlog hero

2. Method, a 4,096-frame ring buffer, a marker key, headless replay, digests

On the morning of October 6 they first built a way to point at a hitch. The game keeps the last 4,096 frames of live play in memory, about 34 s at 120 fps, with timing for each part of the frame and each simulation phase. Press X on the keyboard or Y on a gamepad, see a Marked count, and save camera position plus 20 s before and 5 s after. Any frame over 40 ms is saved with its breakdown even when nothing was marked. Recording a frame cost under 5 µs on the main thread at the median. With recording on or off, the ending state matched.

A ring buffer is not enough. The game already logs each play session. A replay tool can, without a window, re-fire logged blasts and cannon rounds at their original game times in the city that session last loaded. One mixed-city replay reached 836 ms in a single physics step. A physics step is one 1/60 s slice of simulated time the engine computes at once. The stall became a repeatable experiment. Each fix below was checked by replaying a logged session and matching a state digest, a fingerprint of the whole world at the end of a run. When digests matched, the fix changed timing and nothing else.

Determinism is the foundation of that method, written a few days earlier. On September 29, two recordings of the same office demolition disagreed: 696 fallen members in one, 1,123 in the other. They followed the physics engine's own rules for repeatable results: queries, active-body lists, impact events, and contacts all sorted; fractures applied in request order after waiting for prior requests. After that, the scene gave 1,266 fallen members and matching digests across capture, recording, and frame bench. A digest fingerprints every body position to the millimeter. One millimeter off, and the digest changes.

On October 1 they began peeling simulation, fracture, and step into reusable engine modules. Each step had to leave the world exactly as it was. That produced `tools/digests.sh`. It runs 13 test scenes, replays two play sessions, plus alternate-tick and sound-on runs, and screen captures of every scene, then compares digests to a stored baseline on a release build with environment switches cleared. A full run takes about 10 minutes. Headless mode drops window, renderer, and sound. Ten scenes finish in about a minute with the same digests as the rendered app, showing that nothing drawn feeds back into simulation.

Replay can lie too. A downtown replay differed about one run in seven; a district-city replay about one in five. Test windows stole focus on launch, so keys typed elsewhere reached the simulation. One press of T mid-run moved quality from high to medium. The fix was plain. Offline runs show their window without taking focus, drop keys and clicks, and keep a CLI quality tier. Injecting a power-state notification and a T press 600 steps into a frame bench still ends in the same state. Three downtown replays matched.

By then the method was complete. The ring buffer points. Headless replay repeats. Digests prove. A ten-minute script makes the proof daily.

3. Charge sheet, hook, hash, blast, compact, and the 1.4-second product call

With a replayable session they split causes into a table and moved one at a time.

The renderer's removal hook once walked every drawn part in the scene for each broken piece: furniture, trim, cars, ships. Two missiles in one city spent 124 and 134 ms applying finished fractures. After the fix: 7.9 and 8.1 ms.

A terrain vertex hash read only the low bits of a product. On a grid of whole and quarter meters those bits are often zero, so vertices piled into a few slots. One missile's craters cost 192 ms; the replay's worst simulation frame hit 202 ms. After mixing bits with Murmur3's finalizer, the worst sim frame fell to 31.5 ms.

Presenting a 40 m blast searched its full 100 m reach and looked up structure for every body. Replay showed 52 and 83 ms; live play once spent 86 ms of a 164 ms frame. After: 5.1 and 6.1 ms in replay.

Compacting the drawn city's meshes in one frame cost 221 ms in replay and 233 to 311 ms in play. First pass brought it to 87 ms. A second round on the October 7 session took 125 and 134 ms down to 60 and 65. In a large-city low-tier replay, steps over 33 ms fell from 40–79 per run to 4–48. Crater support checks fell from 32 ms (a 64 m crater, about 30 of it in the check) to 12.6 ms.

Another class of suspects saved nothing. In the heaviest window of the first city under Low Power Mode baseline, a rocket barrage left up to 22,000 bodies awake, 99% fracture debris. About half were nearly still, held awake by one touching group of 7,000 to 9,800 bodies the physics engine can only sleep together. Steps reached 84 to 114 ms. Fewer job threads, fewer solver iterations, looser contact cache, looser sleep threshold, and a blast floor each saved nothing. Freezing rubble after 1 s instead of 2 cut the slowest step to 62–70 ms.

The product call shows here. Two ways to cut load: freeze rubble sooner, or make fewer fragments. They kept fracturing as it is and chose freeze at 1.4 s rather than the 1 s the test used. The high-tier change from 2 s to 1.4 s waits on a second replay to confirm. On the morning of October 7, ten minutes of large downtown play became the new replay baseline. One-second freezes were almost gone. A huge missile in mid-city, and several other large drops, caused no freeze at all. They marked one moment with floating debris.

The table's force rarely comes from a glamorous percentage on one row. It comes from before-and-after numbers on every row, plus the cold acceptance line that digests matched. The cost of blaming the wrong cause fell. The risk of changing the world was blocked by a fingerprint.

4K frame teardown devlog hero

4. Another cut, lights over eight million pixels, and how "skipping" stays byte-identical

After the stall table settled, they opened a 4K frame. Largest city, High preset, Low Power Mode: GPU about 30 ms per frame in their bench, about 33 fps. The biggest single step was surface plus lighting at 13.1 ms.

Ablation was direct. Leave all lighting out: 8.7 ms, so lighting itself about 4.5. Leave out up to twelve dynamic small lights: 10.7 ms, so those lights about 2.5, more than half of lighting. Sky visibility about 0.9, street bounce about 0.5, room lights and PCSS soft shadow edges ≈0 in the noise. Eight million pixels, each checking up to twelve lights three times: the light, specular glint, smoke glow. Lights reach at most about 16 m. Almost every street pixel sits outside every ball, yet still ran the empty checks.

The change precomputes a padded screen rectangle for each light. A pixel only checks lights whose rectangle covers it. A three-light wall test drew byte-identical frames both ways. The step averaged 13.8 to 11.8 ms over paired runs, about 2 ms of the 30 ms frame. The limit is written clearly. The player's engines often sit just ahead of the chase camera, so that light's rectangle fills the screen and every pixel still checks it; other lights stay skipped.

Material detail was split the same way. All detail materials about 2.9 ms; procedural concrete noise alone about 1.3 of that. Building color variation about 0.55; weathering and settled dust about 0.3 each. Drawing the city's three million triangles into the G-buffer about 3.5 ms. An early try skipping off-screen buildings saved about 0.4 ms but shaded 75 pixels differently; they left it out. Picture-changing optimizations wait on before-and-after stills before trunk.

Side notes cover assets and load. The textured Sniper ship is 303,458 tris versus about 8,800. Six Snipers at 3840×2160 High moved the frame from 7.16 to 10.39 ms. With a ~30k-tri shadow LOD, shadow cost fell from 1.9 to 0.2 ms. Wide-city load fell from 9.7 to 3.1 s; gunship wreck build stall from 290 to 12 ms. Those figures sit in the 0.15.x follow-up notes, same direction as the main line. Measure first, change shape, then prove look or world did not quietly swap.

Closing, indie means willing to pay ten minutes for reproducibility

Put this October cluster back into the autumn 2026 indie-engine room and it first hits a quiet habit. Teams default to guessing hitches, default to cutting effects as optimization, default to "it runs after the patch" as enough, and rarely ask whether the world after the fix is still the same play. Alex van Rossum opened another path. The tool can be as plain as a marker key. Acceptance can be as hard as a millimeter digest. A ten-minute `digests.sh` can turn determinism from a slogan into a daily gate.

For small teams the material is especially useful. You may not ship a Swift engine, and you may not wake 22,000 debris bodies. You do have a "already good enough" list. A post-blast hitch blamed by feel. An optimization that watches averages and ignores worst steps. A refactor without a headless twin. A test window that stole focus and turned a flaky replay into "physics isn't deterministic." Trilithon's public homework writes the cost in plain numbers. Recording a frame can stay under 5 µs. Ten headless scenes about a minute. Full digests about ten minutes. The expensive part is willing to pay those ten minutes every day, and willing to admit on product terms that a 1.4 s freeze is the explicit choice after keeping fracture density.

Executable prompts stay short.

  • Give hitches a way to be pointed at. Ring buffer, auto-save over budget, marker with before/after windows. Land at least one before the optimization meeting.
  • For every perf fix, ask two questions. What are the before-and-after numbers, and does the world fingerprint still match. A speedup that fails the digest is a defect first, not a win.
  • When you suspect render feeds sim, run headless and rendered. Matching digests unlock cutting into image quality.
  • Culls and bakes that change the picture get a byte-level or still-frame check first. Two milliseconds with identical bytes can enter trunk. Seventy-five different pixels for 0.4 ms can stay as a note and wait.

1.4 s of stall, an 836 ms single step, lights over eight million pixels, ten minutes of digests. Before a store page opens, the maker already wrote the audit standard into public logs. Make the collapse repeat first. Then make time cheaper.

小光

Sources and further reading

Alex van Rossum / Trilithon Games (2026-10-07) Finding 1.4-second stalls by replaying play

Alex van Rossum / Trilithon Games (2026-10-01) Making a collapse repeat exactly

Alex van Rossum / Trilithon Games (2026-10-13) Skipping pixels and tearing down a 4K frame

Alex van Rossum / Trilithon Games (2026-10-10) Textured ship models

Trilithon Games (2026-10-07) Release 0.15

Trilithon Games Since 0.15.5

*Wreckwing* product page https://trilithon.games/games/wreckwing/

Press kit https://trilithon.games/press/

Sign in to keep your reading history.

View your likes and saved articles across devices.

Sign in