bridge-sandbox-utils.ts

Sandbox utility module exposing shape-vertex generators for blocker terrain pieces in the bridge sandbox. Returns unit-space polygon vertex arrays scaled by a caller-supplied factor; consumers feed these directly into collision and rendering pipelines.

Surface

ExportSignaturePurpose
makeBlockerVerts(shapeId: string, scale: number) => Array<{ x: number; y: number }>Produce polygon vertices for a named blocker shape, scaled by scale.

Shape catalog

shapeId switches over a fixed set of strings. s = scale is the unit radius/half-extent.

shapeIdVert countGeometry
blocker_rect4Rectangle 2s × 1.2s (half-extents ±s, ±0.6s).
blocker_square4Square 2s × 2s (half-extents ±s, ±s).
blocker_triangle3Equilateral-ish triangle, apex at (0, -s), base at ±0.87s, +0.5s.
blocker_circle1616-sided regular polygon inscribed in radius s, angles (i/16) * 2π.
blocker_L6L-shape, width 0.5s, height s. Vertices traced top-left → top-right → mid-right → far-right → bottom-right → bottom-left.
blocker_wall4Thin horizontal wall 4s × 0.3s (half-extents ±2s, ±0.15s).
(default)4Fallback unit square 2s × 2s, identical to blocker_square.

Implementation notes

  • Vertices are returned as plain { x, y } object literals (no shared Vec2 type).
  • All shapes are centered on the origin; the caller is responsible for translation/rotation to a world transform.
  • Circle approximation uses Math.cos/Math.sin with no caching — recomputed every call.
  • L-shape vertex { x: h, y: 0 } uses h = s while the rest of the width uses w = 0.5s; this is intentional (the inner corner sits at x = s, not x = 0.5s).
  • Triangle’s 0.87 is a hand-picked approximation of cos(30°) ≈ 0.866, not derived from a constant.
  • Unknown shapeId silently falls back to a unit square — no warning, no throw.

Callers

Used by the bridge-sandbox spawn path to build blocker terrain polygons; pair with the broader sandbox/level systems that consume vertex arrays for collision and draw.

EXTRACT-CANDIDATE

  • Magic constants. 0.6, 0.87, 0.5, 0.15, the 16 circle segments — all inline literals. Should move to a named-constant table (e.g., BLOCKER_SHAPE_CONSTANTS) per the “every number traces to a named constant” rule.
  • Shape ID strings. Seven 'blocker_*' literals scattered across case labels invite typos at the call site. Extract to a BlockerShapeId union or const BLOCKER_SHAPES = { rect: 'blocker_rect', ... } map.
  • Vec2 type duplication. { x: number; y: number } is re-declared in the return type rather than reusing an engine-wide Vec2. Consolidate with the canonical vector type if one exists.
  • Silent fallback. Default branch returns a unit square for any unknown shape. Project convention is “crash on bad data, no silent fallbacks” — should throw on unknown shapeId.
  • Circle precompute. 16-segment circle is rebuilt every call. If hot, cache the unit-radius vertex array once and multiply by s at call time.
  • L-shape definition. Mixing h = s and w = 0.5s inside the same vertex list is hard to read; extracting to a table of unit-space tuples scaled at the end would clarify intent.