Public: anyone can read this; the crew can change it.
forked from trevato/cs · proposes · 4 behind
Boot is not a freeze: the atlas is painted in slices, and the shooter's menu answers while it paints #125
Check · Review · Land · Live done — Landed and live in production.
`src/engine/texture.ts` gains `painter(shaders, size)`: `Painter.paint(rows)` paints at most that many rows — a row is one row of one layer, so `paint(size)` is exactly one layer — returns whether the atlas is finished, and is a no-op once it is; `Painter.bytes` is the buffer it allocated up front and `Painter.rowsLeft` is what is left. There is no clock in it and no callback out of it. `paintAtla…
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
src/engine/texture.tsgainspainter(shaders, size):Painter.paint(rows)paints at most that many rows — a row is one row of one layer, sopaint(size)is exactly one layer — returns whether the atlas is finished, and is a no-op once it is;Painter.bytesis the buffer it allocated up front andPainter.rowsLeftis what is left. There is no clock in it and no callback out of it.paintAtlaskeeps its signature and is now that painter asked for every row at once, so it is the only loop in the file and the range's single call is unchanged.The shooter boots through it.
bootasks the host whether there is a WebGL2 context before anything is painted — a browser without one gets the same sentence in the menu and costs no atlas, soHost.createRendereris two steps now: aBuildRendereror null, and the build takes the finished bytes. From then on the frame loop paints one layer per frame and builds the renderer exactly once, on the frame the last row lands, before the first draw. Until then the menu showsPreparing textures…with Play disabled — both server-rendered insrc/pages/game.tsso the first paint is already true and nothing above the line moves when it clears — andstart()refuses a click that arrives anyway.boot(host)still returns itsFramesynchronously.Measured on this box, nine 128px layers: 206 ms in one cold call, against slices of 26.5, 21.9, 15.9, 15.7, 14.9, 12.1, 12.3, 12.2 and 2.2 ms with the page given a frame between each.
main.test.tsasserts rows and order rather than milliseconds — nine frames, no renderer until the ninth, the bytes it was built from equal tomaterialTextures(), and no match before that;bundle.test.tsproves the same of the committed bundle by countingtexImage3D. The engine's own identity test uses shaders of the two real shapes rather than either game's, because a test insrc/engine/may not import a game; the games' actual palettes are covered by those two comparisons againstmaterialTextures()andrangeAtlas().Bundles were rebuilt: app 72,048 raw / 33,457 gzipped and range 27,433 / 11,745, both inside today's ceilings, with the numbers and what they bought written into
src/games.ts.bun testpasses, 577 tests. What I did not do: move boot's shape into the engine (#75), and I did not make the slice size adaptive — it is one layer, flat, because a clock inside the painter is exactly what the issue rules out.🤖 Generated with Claude Code
Closes #99