PURPOSE
Asset preload entry point. Loads every image, font, and sprite-bundle the game needs before the menu is shown, so first-frame rendering and first planet switch never block on a network fetch. Reports progress as a fraction 0.0 → 1.0 via a caller-supplied callback. Designed to be called exactly once at app boot.
OWNS
preloadAllAssets(onProgress?)— the single public entry point that orchestrates all six preload steps and ticks progress.PreloadProgresstype — callback signature(fraction: number) => void._loadImg(src)— internal helper that wraps anImageelement in aPromise<void>and resolves on bothonloadandonerror(never rejects)._preloadFonts()— internal helper that uses thedocument.fontsFontFace API to warm Cal Sans, Space Grotesk, and Bungee at 16px / weight 400.PLANET_SPRITE_PATHS— hard-coded list of 11 planet PNG paths (Landing Site, Sunrise City, Voidstar, Solaris, Speedway, Eden-5, Old Earth, Network Station, Delphi, Obelisk, Desolation).TERRAIN_SPRITE_PATHS— hard-coded list of terrain PNGs (currently just/terrain/building1.pngfor Sunrise City).
READS FROM
../rendering/ships-v4-loader—preloadAllShipV4()for ship diffuse + normal + points bundles across every hull in the ship manifest.../rendering/enemy-sprites—preloadEnemySprites()for the four enemy archetypes.../rendering/weapon-icons—preloadWeaponIcons()for weapon UI icons.../rendering/ui-icons—preloadUiIcons()for generic UI icons.- DOM globals —
Image,document.fonts(guarded bytypeof documentand'fonts' in documentchecks for SSR safety). - Static asset paths under
/planets/and/terrain/— served from the Vitepublic/folder at runtime.
PUSHES TO
- The browser’s HTTP image cache and decoded-image cache (via
Image.src = ...triggering fetch + decode). - The browser’s font cache and the
document.fontsFontFaceSet (Cal Sans, Space Grotesk, Bungee at 16px / 400 weight). - The
onProgresscallback supplied by the caller — invoked six times, once per completed step. - Indirect: ship-v4 loader, enemy-sprite loader, weapon-icon loader, and UI-icon loader all populate their own module-level caches.
DOES NOT
- Does not render anything. No canvas, no DOM mutation other than transient
Imageand FontFace warm-up. - Does not reject. Image errors resolve silently (
onerror → resolve()); font errors are swallowed in a try/catch. Missing assets never block boot. - Does not gate steps in parallel — steps 1–6 run strictly sequentially via
await. Within steps 5 and 6, paths within that step do load in parallel viaPromise.all. - Does not retry, timeout, or cancel. A hung asset fetch will stall boot indefinitely.
- Does not check the asset list at runtime —
PLANET_SPRITE_PATHSis hard-coded and is not derived fromPLANET_ORDER(the comment claims it must match but there is no programmatic link). - Does not preload audio, particle textures, or background art.
- Does not de-duplicate calls — calling
preloadAllAssetstwice will trigger the full pipeline twice.
Signals
None. This module does not emit, subscribe to, or use the engine signal bus. Progress is communicated solely through the onProgress callback parameter; completion is communicated through resolution of the returned Promise<void>.
Entry points
preloadAllAssets(onProgress?: PreloadProgress): Promise<void>— only public export besides thePreloadProgresstype. Called once at app boot by the boot screen / loader UI.
The boot pipeline through this module is fixed at six steps:
preloadAllShipV4()— ship bundles (diffuse + normal + points per hull).preloadEnemySprites()— four enemy archetypes._preloadFonts()— Cal Sans, Space Grotesk, Bungee.preloadWeaponIcons()thenpreloadUiIcons()— both awaited inside the same step before the singletick().- Planet sprites —
Promise.alloverPLANET_SPRITE_PATHS. - Terrain sprites —
Promise.alloverTERRAIN_SPRITE_PATHS.
The progress denominator steps = 6 is hard-coded; adding or removing a step requires updating that constant in the same edit.
Pattern notes
- Never-reject contract. Every async helper resolves even on failure. The design choice is to keep boot resilient against missing or corrupt assets — the game continues with whatever loaded, and downstream renderers handle missing textures themselves.
- Step granularity vs. fan-out. Steps are sequential to make progress monotonic and the progress UI smooth, but each step internally fans out (
Promise.all) where it can. Steps 1, 2, 3, and 4 are sequential at the inter-step level because each is itself a fan-out inside its own loader module. - Hard-coded path lists.
PLANET_SPRITE_PATHSandTERRAIN_SPRITE_PATHSare literal arrays in this file rather than being imported from the planet or terrain data tables. The planet list comment explicitly notes it “must match all planets inPLANET_ORDER” — drift here is a known maintenance hazard. - Font selection. The FontFace API call uses
400 16px "Family"strings. This warms only the 400-weight 16px variant; other weights/sizes used at runtime rely onfont-display: swapto fill in lazily. The comments mention Roboto Slab and Saira but the code preloads Space Grotesk and Bungee — the source-of-truth for fonts actually warmed is the_preloadFontsbody, not the file-header comment. - SSR guard. The font helper bails early if
documentis undefined or lacks afontsproperty. The image helper does not guardImage— it assumes a browser environment. - Building bake dependency. Terrain sprites are preloaded so the building-bake step (used by Sunrise City) can synchronously read pixel data from a fully decoded image without races.
- One-shot semantics. No idempotency guard. Caller is responsible for ensuring
preloadAllAssetsis invoked exactly once.