Files
healer-man/docs/content-packing.md
T
2026-09-12 11:07:25 -04:00

3.3 KiB

Lossless game content packaging

npm run web:prepare and npm run android:prepare include exactly five packs: core:ui, core:equipment, core:character-basic, core:runtime, and dungeon:wailing-caverns. The complete publication catalog retains all 54 regular dungeons. Internal manastorm:* environment packs remain dependency targets for the 53 regular dungeons that reuse those maps, but they and core:arenas are hidden from the Downloads screen.

The staging directories contain one object per original SHA-256 and extension under content/bundled. Gzip is used only when it saves space. The packager expands each compressed object and compares every byte with its source before writing the bootstrap catalog. Source GLBs, texture resolutions, animations, and audio are unchanged. No media is generated by this pipeline.

Compressed objects end in .gzip, not .gz: Android's asset packager expands and renames .gz inputs. The .gzip extension is explicitly stored without additional ZIP compression so the manifest and APK preserve identical bytes.

Each logical asset keeps its original byte count and SHA-256 in the manifest. An optional download record describes its gzip representation, including a separate compressed hash and byte count. The schema remains compatible with existing catalogs. Remote publishing retains original objects for older apps; new clients prefer the compressed representation and verify both hashes.

The Node server and Vite preview middleware resolve bundled logical URLs on first launch. The browser service worker does the same after activation and persists each immutable bootstrap object by hash after its first use. Android streams bundled gzip through its WebView asset handler, including the companion display, without writing an expanded copy to app storage. Deploy the browser build with the project's Node server so first-launch asset aliases work.

Browser optional installs store compressed objects once and keep small logical aliases. Legacy uncompressed cache entries remain readable. Removing a pack removes an object only after its last installed reference is gone. Android optional downloads resume the compressed transfer, verify it, expand and verify the original, and atomically activate the existing shared native object file.

content/storage-report.json inside each staging/build directory records actual unique object bytes and duplicate savings. These are packaged asset sizes, not GPU memory estimates. Optional Android downloads occupy their expanded size; bundled Android assets stay compressed inside the APK.

Normal release verification rejects unexpected bootstrap packs, more than 80 MiB of stored bootstrap objects, arena assets, and shelved client modules. Eligible JavaScript, CSS, and JSON responses are precompressed with Brotli and gzip; hashed Vite files and bundled content objects use immutable one-year caching, while HTML, service workers, and manifests revalidate.

Validation: npm run content:test, the content/avatar Vitest suites, the bundled-content server tests, npm run build, Android compilation, and a live roster plus dungeon screenshot check. Run npm run release:check before handoff. Android build commands also run scripts/content/verify-android-package.py against the resulting APK, checking every stored object and every original hash.