06 DOCS · BUDGETS
Every kilobyte
is a choice.
Each module has a size budget, and CI fails when one is over. The kernel is 3,372 B gzip against a budget of 4,096 B. The table below is not typed: this page is built by the same code that checks the budgets, so the numbers are the ones measured on v0.21.3.
Measured on this build
| Entry | Gzip | Budget | Used |
|---|---|---|---|
@fzlt/core (kernel) | 3,372 B | 4,096 B | 82% |
@fzlt/core/debug | 486 B | 1,536 B | 32% |
@fzlt/core/perf | 2,019 B | 2,022 B | 100% |
@fzlt/core/input | 1,335 B | 1,536 B | 87% |
@fzlt/core/pad | 2,068 B | 2,120 B | 98% |
@fzlt/core/collide | 1,265 B | 1,536 B | 82% |
@fzlt/core/grid | 1,652 B | 1,664 B | 99% |
@fzlt/core/fx | 2,792 B | 3,072 B | 91% |
@fzlt/core/camera | 1,400 B | 1,536 B | 91% |
@fzlt/core/sprite | 1,437 B | 1,536 B | 94% |
@fzlt/core/sound | 1,062 B | 1,536 B | 69% |
@fzlt/core/embed | 2,040 B | 2,560 B | 80% |
@fzlt/core/slot | 1,849 B | 2,048 B | 90% |
@fzlt/core/presence | 2,197 B | 2,240 B | 98% |
@fzlt/core/presence/check | 4,870 B | 5,120 B | 95% |
@fzlt/core/hud | 1,306 B | 1,536 B | 85% |
@fzlt/core/match | 2,617 B | 2,816 B | 93% |
@fzlt/core/rules | 1,318 B | 1,536 B | 86% |
@fzlt/core/steer | 1,148 B | 1,280 B | 90% |
@fzlt/core/coach | 1,220 B | 1,536 B | 79% |
@fzlt/core/timeline | 2,137 B | 2,304 B | 93% |
@fzlt/core/touch | 310 B | 512 B | 61% |
@fzlt/core/css-clock | 5,368 B | 5,566 B | 96% |
@fzlt/core/layout | 1,747 B | 2,048 B | 85% |
@fzlt/core/view-canvas | 936 B | 1,229 B | 76% |
@fzlt/core/arcade | 24,147 B | 24,150 B | 100% |
@fzlt/core/arcade (hud omitted) | 18,200 B | 18,201 B | 100% |
@fzlt/core/board-page | 4,103 B | 4,160 B | 99% |
page build (kernel+slot+input+fx) | 7,094 B | 7,104 B | 100% |
@fzlt/core/ui (js) | 2,907 B | 3,072 B | 95% |
@fzlt/core/ui (css) | 5,139 B | 5,152 B | 100% |
Minified and gzipped with everything each entry pulls in (1 KB = 1024 bytes), the way npm run size checks it in CI. Over a budget, the build fails.
How we measure
- One measurement.
scripts/sizes.mjsbundles each entry with esbuild (ESM, ES2022, minified), gzips the output and compares it with the budget.npm run size(CI) and the website both call it, so a page can't show a number CI didn't check. - Everything it imports. A brick's size includes the kernel parts it pulls in. That is what a page pays for it alone.
- Live bytes for demos. Every live demo on this site wears a size badge: the gzip of the chunk it loads plus its static imports, measured at build. The site test measures it again and fails if they disagree.
- Budgets move only with a reason. When one goes up, the changelog says how much and why, and the release notes keep it.
The hero budget
A page hero's live chunk (kernel, bricks and the scene's own code) has a budget of 10 KB gzip. The page build (kernel, @fzlt/core/slot, @fzlt/core/input and @fzlt/core/fx) is 7,094 B against 7,104 B, which leaves about 3 KB for the scene. A test fails if sound, debug, the pad, the HUD, match or the Board UI get into it.
The two story heroes on the home page are inside it. Measured in 0.19.0: the layers scene's live chunk is 9,727 B and the fizz scene's 8,752 B, each loaded only once its slot nears the viewport. How small is small walks through the numbers.
Questions
Why gzip and not minified bytes?
Because gzip is what crosses the wire for a script on almost every host. The changelog gives minified bytes too where a change is about them.
Why is @fzlt/core/arcade so much bigger?
It is a shell, not a brick: it composes the kernel, board-page, input, the pad, sound, the HUD and the Board UI keys, so a page game is only its rules and art. Its budget counts all of them.