PURPOSE
Defines the flat-shape stamp families used by the parallax backdrop. Every family produces a single flat-colored silhouette with an optional thin outline and a pre-baked blur — no gradients, no internal detail (craters, windows, rim lights, dots). The backdrop’s job is mood, not reading; detail belongs to gameplay. Each family has N variants; first use of every (variant, tint, blurPx) combo bakes to a small offscreen canvas and caches. Draw time is one drawImage per placed stamp.
OWNS
- The
StampFamilyIdunion of family ids:asteroids_far,asteroids_mid,asteroids_near,planets_far,ships_distant,buildings,plants_jungle,crystals,debris,spires,obsidian_shards,oil_platforms,rig_beams. VariantFninterface (draw(ctx, size, seed)+bakeSize) andFamilyinterface (variants,baseDensity,minWorldSize,maxWorldSize).- The drawing primitives
drawJaggedPolygon,drawSmoothAsteroid,drawLeaf. - The per-family
VariantFnimplementations:asteroidSmall,asteroidMedium,asteroidLarge,planetFar,shipDistant,buildingVariant,plantJungle,crystalShard,debrisChunk,spireRock,oilPlatform,rigBeam,obsidianShard. - The
FAMILIEStable mapping eachStampFamilyIdto its variant list, base density, and world-size range. - The
_bakeCache(Map<string, HTMLCanvasElement>) keyed byfamily:variantIndex:tintHex:blurPx. - The bake pipeline (
bakeVariant): flat-black shape draw →source-intint → blit throughfilter: blur(...)onto a padded outer canvas so the halo never clips.
READS FROM
./layer-types— importshash3ifor all per-vertex / per-pipe / per-greeble / per-arm seeded random rolls.document— guardedtypeof document === 'undefined'check so non-browser environments returnnullfrombakeVariantrather than crashing.
PUSHES TO
- Returns
HTMLCanvasElementinstances to callers viagetStampCanvasfor blit at draw time. - Exposes read-only family metadata via
getFamilyInfo(variantCount,baseDensity,minSize,maxSize). - Returns deterministic variant indices via
pickVariantIndexfor tile-local(tx, ty, i)placements. - Provides
disposeStampCachefor palette swaps and hot-reload/test teardown.
DOES NOT
- Does not place stamps in the world or choose tile positions — callers (the stamp layer renderer) decide where and how many.
- Does not blit baked canvases to the screen — only returns the cached
HTMLCanvasElement. - Does not maintain per-layer density multipliers — only exposes the base density.
- Does not use
createRadialGradientorcreateLinearGradientfor fills (the single exception isrigBeam, which uses a vertical alpha gradient to fade into the water line — still flat-colored, just feathered alpha). - Does not draw internal detail: no craters, no windows, no dots, no specks, no rim lights, no second-color highlights.
- Does not allow more than one simple outline per shape.
- Does not bake without padding — output canvas size is always
bakeSize + 2 * padwherepad = ceil(blurPx * 2). - Does not key the bake cache on function identity — variant index drives the shape seed so duplicate
VariantFnentries inFAMILIES[*].variantsstill produce distinct silhouettes.
Signals
None — this module is a pure shape/bake library. No event emission, no observers, no subscribers.
Entry points
getFamilyInfo(family)— returns{ variantCount, baseDensity, minSize, maxSize }for a family.getStampCanvas(family, variantIndex, tintHex, blurPx)— returns (and caches on first call) the baked tinted+blurred canvas for one variant; returnsnullifdocumentis absent or a 2D context cannot be obtained.pickVariantIndex(family, tx, ty, i)— deterministic per-stamp variant pick usinghash3i(tx * 31 + 7, ty * 37 + 11, i * 13 + 3)modulo variant count.disposeStampCache()— clears_bakeCache; called on palette swap or in tests / hot-reload paths.
Pattern notes
- Flat-fill-only contract. Every primitive and variant uses
ctx.fillStyle = '#000'then a singlefill()(orfillRect). The black shape is later tinted bysource-inin the bake step. The only gradient in the file isrigBeam’s vertical alpha fade, which preserves the flat-color rule while letting the beam sink into the waterline. - Asteroid silhouette anti-symmetry.
drawSmoothAsteroiddefeats brain shape-matching with three independent variation sources: ellipsoidal stretch in[0.55, 1.55], baked rotation, and two wobble bands (low-freq sinusoids at odd cycle counts 3 and 5 with random phase + amplitude, plus per-vertex high-freq hash noise at ±6%). Side count itself rolls in[22, 30]so silhouette resolution varies. - Variant index drives the shape seed.
bakeVariantpasses(variantIndex + 1) * 0.1234as the seed tovariant.draw. Listing the sameVariantFnN times in a family’svariantsarray produces N visually distinct bakes because every random roll inside the variant is keyed off that seed. Thebuildingsfamily uses this with 16 entries ofbuildingVariant;asteroids_*families use it with 9 entries each. Comments inFAMILIESflag this explicitly so future edits don’t “deduplicate” the array. - Procedural buildings.
buildingVariantrolls main body dimensions, then 0..3 thick pipes (each with independent length, thickness, side, height, end-cap dimensions), then 0..2 side/roof greebles, then an independent roll for a tall antenna mast and a stepped roof cap. Pipe shafts terminate at the cap’s inner edge to avoid double-overdraw artifacts after blur. - Bake cache key.
${family}:${variantIndex}:${tintHex}:${blurPx}— palette swaps changetintHexand create new entries; the old ones stay untildisposeStampCacheis called. - Bake padding.
pad = ceil(blurPx * 2); output canvas is(bakeSize + 2 * pad)². Two-pixel safety clamps insidebuildingVariantkeep greebles, masts, and caps from rendering against the canvas edge where the blur halo could clip. bakeSizeis per-variant. Asteroid bake sizes scale from 48 (small) to 192 (large); planets 256; ships 64; buildings 192; plants 128; crystals 96; debris 64; spires 128; obsidian 128; oil platforms 192; rig beams 128. Larger bake sizes give crisper silhouettes on near-camera stamps at the cost of memory.drawJaggedPolygonis legacy. It is kept only fordebrisChunk— asteroid families switched todrawSmoothAsteroidfor the soft oblong silhouette that matches the top-down projection ofgenerateAsteroidMeshindraw-3d-terrain.ts.- Special-case families.
oil_platformsandrig_beamsexist for the Delphi lake surface view: oil platforms are top-down ringed platforms with pipe-arm stubs and deck structures; rig beams are vertical alpha-feathered beams with a top platform head and optional mast. - No DOM in non-browser paths.
bakeVariantearly-returnsnullwhendocumentis undefined, so server-side or worker-side imports of this module are safe.