Repository navigation
Description
Objective
Make Labelle WASM builds reproducible, faster and less memory-intensive, then adopt the released improvements in Flying Platform's GitLab CI. This ticket tracks the Docker builder image and all performance work below, as requested by the owner.
Coordinate implementation across labelle-cli, labelle-engine, labelle-assembler, labelle-web and labelle-bgfx. labelle-tools is archived and read-only. Audit existing Docker support before introducing another build path.
Measured baseline
Local Windows investigation on 2026-10-30, with one heavy job at a time and Zig builds limited to -j2:
| Experiment | Game compilation | Peak private compiler memory |
|---|---|---|
| Original ReleaseSafe code | 242 s | 10.41 GiB |
| Debug information stripped | 221 s | 9.66 GiB |
| Save serializer split into smaller functions, debug information and safety checks retained | 145 s | 5.34 GiB |
- The serializer prototype reduced compile time about 40% and peak private memory about 49%. Its main serializer function shrank from 523 KB to 73 KB of WASM code.
- LLVM control-flow restructuring fell from about 61 to 15 seconds; register stackification fell from 44 to 8 seconds.
- Linking the same original compiled libraries with Emscripten -O1 took about 2 seconds versus approximately 205 seconds for the original build/link invocation at -O3. WASM size increased from 35,954,722 to 37,033,628 bytes (about 3%).
- An unchanged compiled build took about 1 second; warm generation took about 4 seconds.
- Other large functions include startup (335 KB), the entity-detail inspector (165 KB), and deserialization (133 KB).
These are exploratory local measurements, not Linux/container guarantees. Compiler runs used timing instrumentation; private memory was sampled. The serializer prototype compiled and linked but has not undergone save/load or gameplay validation. The faster link setting needs browser correctness and runtime-performance comparisons. Prototype files and measurements are retained locally under D:/prj/labelle-toolkit/wasm-investigation-evidence; attach reproducible scripts/results and the patch to the implementation PRs so validation does not depend on that machine.
Work packages
1. Versioned Docker builder image
- Pin the base image and compatible Zig, Labelle CLI/assembler, Emscripten, Node and Python versions; record the toolchain inventory.
- Install required system libraries, including libatomic1, and Chromium WASM smoke-test dependencies.
- Run builds as a non-root user; include no credentials or game source.
- Respect project.labelle/labelle.lock pins and document image/toolkit compatibility.
- Keep toolchains in the image, persistent Zig local/global caches, Labelle package caches and Emscripten caches outside it, and game bundles/test reports as CI artifacts.
- Document cache mounts, ownership, keys and invalidation by toolchain/platform/build configuration.
- Publish versioned images to an agreed registry, pin consumers to immutable digests, and document upgrades and rollback.
- Confirm/configure a Docker-compatible GitLab executor; shell executors do not apply the CI image setting. Document CPU/memory/concurrency limits using measured requirements.
- Provide a GitLab CI example and adopt it in Flying Platform.
- Keep Android SDK/NDK support in a separate future image/variant.
2. Reduce oversized engine/compiler functions
- Implement and validate the serializer prototype in labelle-engine: move per-component entity collection and component writing into appropriately bounded functions so optimization does not expand everything into one oversized function.
- Preserve serialization format, error propagation, allocation cleanup, component policies and ReleaseSafe checks.
- Add targeted round-trip/regression coverage for representative FP components, marker components, prefab/built-in components and reference arrays; verify compatibility with existing saves.
- Profile remaining large functions, including deserialization, generated startup and inspector code. Reduce excessive inlining/unrolled code where measurements justify it.
- Update assembler templates/generation where needed; do not ship edits only to generated .labelle files.
- Re-measure compile time, peak memory, output size and runtime behavior. Debug stripping alone is not the primary fix.
3. Faster CI/preview linking
- Expose a documented WASM link-optimization setting independently of Zig's optimization/safety mode.
- Evaluate Emscripten -O1 for CI/preview builds while retaining ReleaseSafe checks, assertions, pthread settings and required browser features.
- Preserve an explicit optimized production/release path; do not silently change production defaults without runtime measurements.
- Compare -O1 and -O3 using identical compiled inputs, measuring link time, output size, startup, representative gameplay/frame performance and memory.
- Verify both threaded and single-threaded fallback bundles, browser smoke tests and assets/audio/settings/save-load behavior.
4. Independently compiled engine boundaries
- Audit which dependencies are already separate cached libraries (including BGFX/C++) and which Zig engine code is imported as source into the game compilation.
- Identify stable engine operations that can live behind explicit library/API boundaries, keeping FP-specific component/hook specialization in a smaller adapter.
- Prototype a viable boundary and measure whether game-only edits can reuse the engine artifact. Moving source into another imported module alone is insufficient.
- Validate target/ABI compatibility, debug-symbol behavior, threaded/fallback variants and cache invalidation.
- Implement boundaries with demonstrated benefit, or document measured blockers/tradeoffs and an explicit disposition for this work package; do not silently omit it.
5. Releases, consumer pins and end-to-end validation
- Release affected toolkit packages in dependency order and update Flying Platform's released dependency pins.
- Adopt the versioned builder image and selected CI link profile in FP's GitLab job.
- Publish reproducible cold, warm and changed-source benchmark results, separating image pull/startup, provisioning, generation, compilation, linking and smoke tests.
- Verify a fresh container/runner needs no manually installed host toolchains, and subsequent fresh containers reuse persistent caches.
- Compare peak compiler memory and safe job concurrency; containerization alone does not resolve oversized compiler workloads.
Acceptance criteria
- Dockerfile, image build/publish automation, immutable image version and GitLab usage documentation are available.
- Fresh-container builds and cache reuse work as a non-root user.
- Serializer changes are implemented in toolkit source and pass save/load compatibility and regression tests.
- Remaining oversized generated functions are profiled, with measured fixes and documented results.
- Independent WASM link optimization is exposed and validated; CI/preview and production behavior are documented.
- A separately compiled engine boundary is prototyped and evaluated, with implementation or explicit evidence-backed disposition.
- Threaded/fallback bundles and Chromium smoke tests pass; runtime correctness/performance tradeoffs are recorded.
- Affected toolkit releases are published and FP dependency/image pins are updated.
- FP GitLab CI passes using the image; bundles, reports and cold/warm/changed-source measurements are retained.
- Upgrade, rollback, cache invalidation and resource/concurrency guidance are documented.
Related prior work: labelle-cli#112 (Docker/Colima support), labelle-cli#206 and #210 (WASM scene materialization), and labelle-cli#331 (Android Docker limitations).
Updated by Codex, OpenAI LLM, at the owner's request to consolidate the image and all WASM build-performance improvements in this ticket.
Activity
[-]Publish a versioned Labelle WASM Docker builder image for GitLab CI[/-][+]Speed up Labelle WASM builds: Docker CI image, compiler memory, linking and engine boundaries[/+]apotema commentedon Oct 30, 2026
Status update (2026-10-30)
WP4 — independently compiled engine boundary: disposition: do not implement
Prototype and measurements: labelle-engine#923 (write-up, single-threaded follow-up), draft PR labelle-engine#924.
GameConfigWithYAxis(Renderer, …, Components, Hooks, Events)), so 94% of the 5.6 MB game-unit code is game-specialized. Only ~3% (~170 KB) is game-independent — the ceiling for any engine library boundary.Other work packages
perf/save-serializer-outline; full suite matchesmain(pre-existing Windows-only failures). A/B compile measurement in progress, PR to follow.LABELLE_WASM_LINK_OPT(unset = today's byte-identical command). FP, same compiled inputs:-O3194.8 s /-O221.7 s /-O17.8 s link; wasm +3% at-O1(+1% gzipped). Threaded and fallback Chromium smokes pass at-O1and-O3. Gameplay/frame-time, save/load and audio not yet validated. Found: labelle-web's best-effortwasm-opt -O3currently fails validation and is skipped in production exports (separate issue to file).https://claude.ai/code/session_01Hpt1haxcboZPznpG1KqDRS
apotema commentedon Oct 30, 2026
WP1 update: the WASM builder image moved out of labelle-cli into Flying Platform as a private image (moca-tecnologia/flying-platform-labelle#1101). #530 and #529 are closed as moved.
Toolkit-relevant findings from the image runs:
build.zig.zonpulls emsdk 4.0.9 as a Zig package and installs it inside each checkout (.labelle/bgfx_wasm/zig-pkg/, about 1.4 GB) instead of using the provider'sEMSDK. It is a toolkit issue and not filed yet.AccessDeniedon rename).https://claude.ai/code/session_01Hpt1haxcboZPznpG1KqDRS
apotema commentedon Oct 30, 2026
Toolkit bugs found during the GitLab CI trial (moca-tecnologia/flying-platform-labelle#1102) and the builder-image runs:
engine_versionis a commit SHAGitLab trial result: FP bundle at O1 with engine #926+#925 (on v4.2.0-rc.2), bgfx #209, web #28 and assembler #822: 251 s, 4.26 GB peak compiler memory (was 10.4 GiB), threaded and fallback smokes pass.
https://claude.ai/code/session_01Hpt1haxcboZPznpG1KqDRS
feat(wasm): link optimization setting independent of -Doptimize (#208) (
feat(export): wasm-opt level follows LABELLE_WASM_LINK_OPT (labelle-b…
feat(wasm): LABELLE_WASM_LINK_OPT in the in-tree emcc hooks (labelle-…
chore: release labelle-bgfx 0.38.0 for WASM link optimization setting (…
chore: release labelle-web 0.5.0 for WASM link optimization (#30)
chore: release labelle-assembler 0.125.0 for WASM link optimization (#…
release: labelle-imgui v0.14.8 — bridges honour EMSDK with EM_CACHE /…
chore: release labelle-assembler 0.126.0 for lazy root build deps and…
apotema commentedon Oct 31, 2026
Overnight release train — done (2026-10-31)
Everything below is released or merged, with CI green on the exact commits that were tagged/merged.
Toolkit releases
EMSDK; headers from$EM_CACHEwithsysroot_install.stampreadiness (#12)EMSDK; stamp-based sysroot readiness; needs audio 0.5.1 (#210)sokoldependency (#49)Earlier the same day: labelle-bgfx v0.38.0, labelle-web v0.5.0, labelle-assembler v0.125.0 (
LABELLE_WASM_LINK_OPT), labelle-registry web 0.5.0 entry.Flying Platform (moca-tecnologia/flying-platform-labelle)
O1(production stays-O3)sha256:4e20e902df8b9c2f50cdfeb4ab919fd1ede385ec53d6682f85671752620edf62sha256:e4277f4d65ab402dc3f508e5c15c3f32ac8bdadf39f8058079f2fec3239fdd3a)Measured effect (FP WASM, ReleaseSafe)
O1(bgfx Add WASM serve command (labelle wasm serve) #209 / web UX: Generator output shows misleading paths for generated files #28).Workarounds log
concurrent = 3). Retried with an empty commit (passed), then fixed at the source in labelle-cli v4.1.3 (fix(cache): concurrency-safe downloads into the shared labelle home #533).release/4.1.3E2E run finished; that run later passed on all platforms.mainE2E for the 4.1.3 version bump failed once on Windows inprovider_watch_e2e.py("the refused session rewrote the status file"); the same test passed on the fix commit and the release branch. Re-ran the failed job: green.build-and-deploycheck fails because GitHub Actions billing for the org is failing; it is not a required check and nothing was bypassed. Needs billing fixed..heavy-lockassuming it was that agent's; the image agent had just taken it. Its run continued unaffected.epic-528/fp-pin-4123andepic-528/fp-pin-4131worktrees (in use as session working directories; safe to delete),epic-528/emsdk-6.0.13+emsdk6-work, and the 30 GBepic-528/docker-cache-823/cache.ext4.No admin overrides, protection bypasses, force-pushes to others' branches, disabled tests, or republished versions.
Still open
-O3links).fp-docker-prrunner (PR coverage in the image) and movingfp-dockeroff theciuser — box work, see FPdocs/ci-docker-runners-nixos.md.https://claude.ai/code/session_01Hpt1haxcboZPznpG1KqDRS