bridge-sprite-baking.ts

Pure rendering helpers for sprite outline baking and fog stamp generation. No engine state dependency — every export is a deterministic-input pure function (modulo Math.random for fog noise).

Purpose

Pre-bake atmospheric and outline visuals to per-sprite HTMLCanvasElement textures so the hot render path only does drawImage calls. Two unrelated utilities live here:

  1. Fog stamp — a single 256×256 noise texture reused as parallax atmospheric overlay.
  2. Outlined sprite baking — wraps an arbitrary sprite with a crisp circular stroke and optional rarity glow.

Exports

SymbolKindReturns
getFogStamp()functionHTMLCanvasElement (memoized 256×256)
bakeOutlinedSprite(img, sz, strokeColor, glowColor, strokePx?)functionHTMLCanvasElement (sized sz×sz)

Fog stamp

getFogStamp() is memoized via module-scoped _fogStampCache; first call generates, subsequent calls return the cached canvas.

KnobValue
Sizesz = 256
Backgroundsolid #000000 fill
Blob count12 overlapping radial gradients
Blob radius40 + Math.random() * 60
Blob centeruniform random over [0, 256) for both axes
Gradient stops0 → rgba(255,255,255,0.4), 0.6 → rgba(255,255,255,0.15), 1 → rgba(255,255,255,0)

Intended use: drawn 1–3 times per frame as a parallax overlay. The randomness is unseeded — each page load produces a different noise pattern.

Outlined sprite baking

bakeOutlinedSprite(img, sz, strokeColor, glowColor, strokePx = 2) returns a fresh canvas with three composited layers (back → front):

LayerContentImplementation
0aOuter glow ringdilate(strokePx + 5, 32, glowColor, 0.22) — only if glowColor non-null
0bInner glow ringdilate(strokePx + 3, 32, glowColor, 0.38) — only if glowColor non-null
1Crisp strokedilate(strokePx, 32, strokeColor, 1.0)
2Original spritedrawImage(img, pad, pad, drawSz, drawSz)

Geometry constants

ConstantValuePurpose
pad14Reserved border for stroke + glow spread; covers strokePx up to ~7
drawSzsz - pad * 2Inner draw region for original + dilated copies
Default strokePx2Crisp 2-pixel outline
Dilation samples32Copies stamped on circle — eliminates octagonal artifact of cardinal-only stamping

Dilation algorithm

dilate(radius, samples, color, alpha) is a local closure that:

  1. Creates an offscreen layerCvs of size sz×sz.
  2. Draws samples copies of img around a circle of given radius, each at angle (i / samples) * 2π, offset from (pad, pad).
  3. Sets globalCompositeOperation = 'source-in' and floods color — recolors the silhouette to a single solid color.
  4. Composites the result onto the output ctx at alpha.

Net effect: produces a solid-color dilated silhouette of the source sprite without ever computing actual paths. Equivalent to a circular morphological dilation by radius pixels.

Caller contracts

  • Pass glowColor = null to skip the glow layers (common enemies).
  • Pass the same color for strokeColor and glowColor to get a unified rarity tint.
  • img may be either HTMLImageElement or HTMLCanvasElement.
  • strokePx higher than ~7 will overflow the 14-pixel pad and clip the outline.

Performance notes

  • Both functions allocate canvases — call once at bake time, never per frame.
  • Outlined-sprite bake cost scales as O((1 + 2·glow) · 32) drawImage calls = 32 calls without glow, 96 with glow.
  • Fog stamp generation is one-shot; the memoization makes repeated getFogStamp() calls O(1).

Dependencies

None. Imports nothing — uses only DOM canvas APIs.

EXTRACT-CANDIDATE

  • The pad = 14 magic number ties to strokePx ≤ 7. Could derive pad = strokePx + 6 to remove the implicit cap and the comment-only invariant.
  • dilate samples count 32 is duplicated across all three call sites — could be a named constant DILATION_SAMPLES = 32.
  • Glow alpha pair (0.22, 0.38) and radius offsets (+5, +3) are magic numbers; could move to a GLOW_LAYERS table for tunability.
  • Fog stamp constants (sz=256, blobCount=12, radius range, gradient stops) could move to a FOG_STAMP_CONFIG data object — currently the only knob is editing the function body.
  • Math.random() in fog stamp is unseeded — if deterministic builds become a requirement, accept an optional RNG parameter.