0.4.1 RELEASE NOTES
Fizlet 0.4.1
By Chris Cooley ↗ · · CHANGELOG.md ↗
Hardening from the engineering review (2026-10-29, §8: UI and tokens, collision and effects).
- pack smoke test: data subpaths (
.css,.json) resolve instead of importing. - ui:
mount()keys its shared constructed stylesheet by the CSS text. It cached the first sheet for the whole page, so a second game mounted with different CSS got the first game's styles. Stylesheet ownership is documented (BOARD-UI.md 2.1). No visual change. - ui:
tokens.jsonis the authoritative token source. Published asfizlet/ui/tokens.json; the build fails when aboard-ui.cssdefault orapplyPalette's variable map disagrees with it (scripts/tokens.mjs, tested).board-ui.cssis byte-identical. - collide:
Gridseparates entity capacity (cap), index capacity (new 5th argumentnodes, defaultcap * 4) and query-result capacity (out), and every saturation is counted:dropped(index full; now counts every refused cell entry),rejected(id outside0..cap-1or a non-finite circle; such ids used to alias the dedupe stamps),truncatedandmissed(query results that did not fit; they used to vanish silently). The constructor andresizethrow aRangeErroron non-finite sizes or non-integer capacities. - collide:
add,near,insertandquerypass numbers through a typed array, so the grid allocates nothing even when V8 does not inline it (the mixed collide + fx test went from ~24 young GCs per 200k frames to 0; its allowance drops from 100 to 1). - fx:
blast()stops at capacity instead of attempting every particle on a full pool (10 blasts of power 1e6 on a full pool: ~4.7 s before, ~0 ms now), and counts refused particles infx.dropped.effects()validatescap,scorch(0 now turns scorch marks off) and the colour and word tables;spawn,blastandkickrefuse non-finite input (a NaN life used to hold a pool slot forever). - fx: no allocation in a live scene.
blast()allocated on every call (Math.random returns a new heap number); the visual random is now a private generator seeded from Math.random (still never the simulation's seeded random) and blast writes the pool directly. Same recipe, same distributions. - tests: the allocation test runs a populated fx scene (blasts every frame window, the pool full, drops counted) and asserts no young-generation GC; new regression tests for every item above, and a browser test for two games mounting different CSS.
- README: the overload policy (decorative particles may drop, counted; collision results never drop silently).