<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>cat/marbles</title>
<subtitle>an endless marble-race generator in the browser; the url is the seed, so every track can be shared</subtitle>
<id>https://src.rest/cat/marbles/</id>
<link href="https://src.rest/cat/marbles/"/>
<updated>2026-09-30T20:46:48-06:00</updated><entry>
<id>2178fd3d2b5ca8ab549e2609f0eadc5153710bb9</id>
<title>fix: use supported Cloudflare Pages configuration</title>
<link href="https://src.rest/cat/marbles/commit/2178fd3d2b5ca8ab549e2609f0eadc5153710bb9/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:46:48-06:00</updated>
<content type="text">Remove the unsupported account_id field so Wrangler can deploy the complete site to the existing authenticated Pages project.</content>
</entry>
<entry>
<id>b20b16518311f9eb4d573b3653af0c904aba2647</id>
<title>build: package the complete Cloudflare Pages site</title>
<link href="https://src.rest/cat/marbles/commit/b20b16518311f9eb4d573b3653af0c904aba2647/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:42:01-06:00</updated>
<content type="text">Build browser JS and native physics together, then package static files and
asset packs into ignored output/site. Save the existing Pages target in
Wrangler configuration and document the deployment workflow and controls.

Record completed UX, collision and camera verification: 230 tests passed,
full type checks and build passed, and browser checks reported no errors.</content>
</entry>
<entry>
<id>cfae4700bcf09cb8c7fd5928ce2cf8a37b5a5611</id>
<title>fix: preserve zoom and smooth wide follow-camera views</title>
<link href="https://src.rest/cat/marbles/commit/cfae4700bcf09cb8c7fd5928ce2cf8a37b5a5611/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:41:32-06:00</updated>
<content type="text">Keep chosen wheel zoom through idle time, respawns and retargeting. Pair
obstruction hits on the same mesh/instance and distinguish open foreground
shells from volumes containing the lens. Wide shots tolerate foreground
occlusion and ease through bends while retaining lens clearance.

Detect teleports from consecutive subject positions rather than camera lag.
Add eight geometry regressions; verify continuous motion at 30/60/120 fps.
On e0b75o4y7s, an 80-second wide-camera comparison reduced moves over two
units per frame from 21 to zero.</content>
</entry>
<entry>
<id>bb28b82cc536eda960692c8eef76c9c6943f34e8</id>
<title>feat: simplify the launch menu and expose playback controls</title>
<link href="https://src.rest/cat/marbles/commit/bb28b82cc536eda960692c8eef76c9c6943f34e8/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:41:24-06:00</updated>
<content type="text">Use a dedicated illustrated title screen with racer count and optional seed.
Keep Classic loop, steering and diagnostics in Simulation options; name the
Modern and Legacy steering choices explicitly. Remove redundant subtitles
and the duplicate top-bar wordmark.

Add visible camera, pause, fullscreen, share and settings controls with native
keyboard behavior, responsive layouts and clear loading failure recovery.
Hide hero/leader selection and its shortcut in solo or decorative-peer runs.</content>
</entry>
<entry>
<id>9784c75b23512b64a832ae2b4ec9e7d92619dbd3</id>
<title>fix: clear disconnected lanes and overlapping track collisions</title>
<link href="https://src.rest/cat/marbles/commit/9784c75b23512b64a832ae2b4ec9e7d92619dbd3/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:41:06-06:00</updated>
<content type="text">Split discontinuous braid ribbons and pack independent collision strips
without joining triangles. Restrict static contacts to each racer checkpoint
and adjacent checkpoints so rotated older segments cannot block the track.
Preserve peer contacts and ghost behavior; export the rebuilt shim API.

Regression checks cover disconnected topology, ramp/helix overlaps and both
icy-braid lanes. Native browser soaks cleared the recorded failures; two
drop-cup recoveries remain documented.</content>
</entry>
<entry>
<id>6e38293cbab70130b367cac05a0adce902505bd1</id>
<title>feat: trace rail recoveries to authored track pieces</title>
<link href="https://src.rest/cat/marbles/commit/6e38293cbab70130b367cac05a0adce902505bd1/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:40:33-06:00</updated>
<content type="text">Attach source window, family, zone and lane metadata to dense rail stations.
Remap placement indices after filtered jump/reorientation meshes and carry
provenance through concatenation. Record bounded recovery and LOD telemetry
with generated-window exposure counts for diagnosing stalled pieces.

Add provenance regressions and preserve the earlier recovery sample notes.</content>
</entry>
<entry>
<id>a8237c65e1c2260f12cdc98937f338c2f53a6756</id>
<title>fix: accumulate trail samples during slow marble motion</title>
<link href="https://src.rest/cat/marbles/commit/a8237c65e1c2260f12cdc98937f338c2f53a6756/"/>
<author><name>Dami</name></author>
<updated>2026-09-30T20:40:16-06:00</updated>
<content type="text">Keep a separate committed sampling anchor so a moving ribbon head does not
prevent slow motion from adding trail points. Reset the anchor on warps,
fades and explicit clears. Covered by a slow-motion regression.</content>
</entry>
<entry>
<id>7e7a85f65097b1cb7e73fc3b5b18448127938bd1</id>
<title>BUG HUNT: harden cameras, menus, trails, and teardown</title>
<link href="https://src.rest/cat/marbles/commit/7e7a85f65097b1cb7e73fc3b5b18448127938bd1/"/>
<author><name>Dami</name></author>
<updated>2026-08-26T15:57:14-06:00</updated>
<content type="text">Keep endless orbit attached to the streamed subject, fade tunnel shells around the lens, and scope camera occlusion to authored track pieces.

Make the title menu and gallery usable on small screens, preserve exact seeds and native input behavior, and hide inactive HUD chrome.

Add constant-cost boost trails, dispose marble/WASM resources across regeneration, and cover trail and physics teardown regressions. Verified with lint, type-check, build, and 214 passing tests.</content>
</entry>
<entry>
<id>62919dbc41c478b3801086a082584cd42b8503a4</id>
<title>MARBLES KEEP THEIR COLOURS (glow round): boost stops painting the pack blue</title>
<link href="https://src.rest/cat/marbles/commit/62919dbc41c478b3801086a082584cd42b8503a4/"/>
<author><name>Dami</name></author>
<updated>2026-08-10T04:10:51-06:00</updated>
<content type="text">The reported bug (&quot;the outer shell of marbles sometimes gets a blue tint
at some locations or angles&quot;) was the BOOST GLOW, not the glass.

On ignition the racer wrote emissive 0x2255ff @0.9 to every material it
owned — including the transmission SHELL. A transmission material adds
emissive on top of the refracted core rather than blending with it, so
that flooded the whole sphere with one flat colour; the same saturated
blue on the CORE at 0.9 then swamped each racer&#39;s identity. Result: every
boosting marble rendered the same periwinkle, which is why the tint came
and went with location (boost corridors) and took the whole pack at once.

Now: the shell never emits, and the glow is the racer&#39;s OWN colour pushed
30% toward white at 0.55 — the marble lights up from inside its glass and
stays itself. Same law at pack scale (instance colour brightens instead of
lerping 3/4 to a shared blue).

Also, found while measuring: the shell carried two stacked reflection
layers (RoomEnvironment PMREM at 1.2 plus clearcoat 1), spraying ~8% of an
environment brighter than this world over every marble pixel, which the
zone&#39;s mood lighting tinted. Measured on a red-cored marble, the wash
lifted G/B from ~4 to ~47. One layer at 0.5 now; core saturation at race
distance is up ~40% and the refractive rim and highlights are unchanged.

210 tests pass.</content>
</entry>
<entry>
<id>fbf553171d5e53703fc34093e7c2c8485ec2955a</id>
<title>progress.md: current-state line for the emergence round (M21-M25 + mass families + contact events, 210 tests)</title>
<link href="https://src.rest/cat/marbles/commit/fbf553171d5e53703fc34093e7c2c8485ec2955a/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:51:09-06:00</updated>
<content type="text"></content>
</entry>
<entry>
<id>bedb2e352b57bcfa78ab89fab4243c18275117a6</id>
<title>THE WORLD REMEMBERS (M25): the race leaves marks</title>
<link href="https://src.rest/cat/marbles/commit/bedb2e352b57bcfa78ab89fab4243c18275117a6/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:49:44-06:00</updated>
<content type="text">Client-side accumulating history — generation never knows (streaming
law untouched; every mark parents to a segment group and sinks out with
its ExitAnim):
- SCARS: hard marble-static knocks (contact events ≥ 4.5 u/s) leave
  dark scuff marks at the hit point, sized by impact speed, capped 30
  per segment, shared geometry/material, excluded from the fit box.
- ICE SCUFFS: hard braking on icy stations drops pale translucent
  streak marks (rate-limited 0.5s per racer, deterministic — sim state
  only).
- TIP-OVERS: a hard knock within 0.8u of trackside furniture (fans,
  banners, bumper mushrooms) tips it ~74 degrees away from the shove,
  eased over ~0.5s — and it STAYS fallen until the segment sinks. A
  fallen fan keeps spinning: the wreck is alive.
- Telemetry: race JSON gains standing-mark count; scar bookkeeping
  cleans with segment disposal. NO audio (user rule).
  210 green, check clean, goldens untouched (pure presentation).</content>
</entry>
<entry>
<id>11ae0ef5c39a001d0a8f858fc6050b1687f6b006</id>
<title>CONTACT EVENTS (shim round): the pack&#39;s knocks are real now</title>
<link href="https://src.rest/cat/marbles/commit/11ae0ef5c39a001d0a8f858fc6050b1687f6b006/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:46:49-06:00</updated>
<content type="text">New wasm surface, no audio (user rule — audio stays parked):
- shim.c: hit events enabled on every marble shape (userData = idx+1;
  statics stay silent and resolve as −1), world hitEventThreshold 1.5
  u/s (real knocks, not rolling contact); ph_hits flattens the step&#39;s
  b3ContactHitEvents to [idxA, idxB, approachSpeed, px, py, pz] × 6
  floats — pull-based and deterministic. Rebuilt via build_physics.sh.
- engine.ts hits(): reusable heap-view readback (HITS_CAP 256).
- endless.ts consumes per step INSIDE the step callback (events clear
  next step): marble-marble hits arm the TEMPER trigger (real contacts
  now; the 2.5-radii proximity proxy stays as the sub-threshold
  fallback), and hard marble-static knocks (≥4.5 u/s) queue pendingScars
  — the M25 world-memory feed.
- Headless test: head-on pair reports exactly the expected pair above
  threshold; hard drop reports a static knock. 210 green, check clean,
  goldens untouched (client+shim only).</content>
</entry>
<entry>
<id>6c1fa38aedfe3b3ef1a0cfb861598040fcd2aa9c</id>
<title>SEED PERSONALITY (M24): worlds develop temperaments</title>
<link href="https://src.rest/cat/marbles/commit/6c1fa38aedfe3b3ef1a0cfb861598040fcd2aa9c/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:41:32-06:00</updated>
<content type="text">StyleField v2 — the under-exploited seam gets its identity draw:
- style.ts TEMPERAMENTS (appended draw — finite streams byte-identical,
  genVersion untouched): balanced (common), treacherous (icy/gravity/
  spur + spooky/barren/winter islands), soaring (jump/sprint/helix +
  tropical/meadow), tangled (braids/spurs/reorients + abstract/grove),
  rolling (slopes/corner-drops + rocky/autumn), serene (hazards damped +
  meadow/forest/grove).
- The endless planner&#39;s clause draw now composes climate × temperament
  (world.ts composeClauseBias; path.ts takes one merged record); the
  island biome draw leans with the temperament too — a seed&#39;s sky,
  hazards and islands cohere into one character.
- Corpus law test: treacherous seeds run measurably icier/heavier than
  serene ones; ≥4 temperaments emerge over 60 seeds.
- Pin cycle #3 of the round: jump→grav-scan-2, propeller→grav-scan-0,
  spur@1→grav-scan-22, 180 reorient back to grav-scan-33, 3-chain →
  grav-scan-32@0-2 (one seed now pins open fork AND full chain), gust
  bank→wind-scan-9@4 (bank run-gap relaxed ≤4: climate biases spread
  gusts thinner than the M19a adjacency law assumed — an island&#39;s ledge
  row is the bank unit). 209 green, check clean, goldens re-pinned.</content>
</entry>
<entry>
<id>39a9911f5fa1c5a6d58fb7425b8d2d76c10d420f</id>
<title>BRAID NETWORKS (M23): the line stops being a line</title>
<link href="https://src.rest/cat/marbles/commit/39a9911f5fa1c5a6d58fb7425b8d2d76c10d420f/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:34:08-06:00</updated>
<content type="text">Two braids per segment + 3-segment open chains — sub-packs now live on
separate lanes for up to 60 cells:
- path.ts: braid gate braids.length &lt; 2 (an open fork is necessarily
  last); continuations may STAY OPEN (0.35) when the cap affords the
  full middle segment + a minimal merge — the alt lane rides an ENTIRE
  segment boundary-to-boundary (L2 = SEGMENT_TARGET, no merge, open
  state re-emitted with accumulated cells). OPEN_BRAID_CAP 34 → 60:
  fork segment + one full open middle + merge segment is the longest
  legal chain, still comfortably co-live under KEEP_SEGMENTS.
- world.ts: altPath concatenates EVERY lane&#39;s loop (was last-wins —
  a two-braid segment lost its first lane&#39;s channel proxies).
- proxies.ts: chains and merge windows pair IN PATH ORDER (find-first
  broke the moment a cont chain and a fresh fork shared a segment — the
  closed braid lost both junction composites; caught by the contract
  suite on braid-scan-0).
- Client lane carry is transitive through braidContOf (0→1→2), so a
  rider&#39;s fork-drawn lane survives BOTH boundaries.
- Tests: chain-walking V3 contract (transitive resolution, ≤3 segments,
  cap law, port continuity at every hop, stay-open middles emerge);
  altPath containment law (concatenated lanes); pinned 3-segment chain
  grav-scan-15 with both-lane drive soak through the whole network.
  208 green, check clean, endless goldens re-pinned.</content>
</entry>
<entry>
<id>291336ca2fd71bcafcaa71b5e65417321aa5dc8c</id>
<title>SLIPSTREAM ECONOMY (M22): trains form because they pay</title>
<link href="https://src.rest/cat/marbles/commit/291336ca2fd71bcafcaa71b5e65417321aa5dc8c/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:25:22-06:00</updated>
<content type="text">One rule, five systems couple: riding a wake REFILLS the boost tank
(DRAFT_REFILL 1/14 at full depth on top of base regen 1/12 — a committed
wake rider roughly doubles its recharge; burns never sip the tow).
- boostStep gains draftDepth (appended param, decision-table rows);
  decide() feeds (draft−1)/DRAFT_GAIN; riders keep their kinematic fake
  (no fuel at LOD distance).
- Emergence: pilots with wake appetite line up for the economy, hoard,
  and detonate at attack range — cascading overtakes nobody scripted.
- Telemetry: race JSON gains maxTrain + trains (s-consecutive drafting
  chains ≥3) so the trains are measurable in soaks.
- All client-side: goldens byte-identical, scenario pins untouched.
  206 green, check clean.</content>
</entry>
<entry>
<id>7e734b734e74ea8d5796e68ad0c2f71e5c42ac5f</id>
<title>WEATHER BECOMES PHYSICAL (M21): the sky is a generation input now</title>
<link href="https://src.rest/cat/marbles/commit/7e734b734e74ea8d5796e68ad0c2f71e5c42ac5f/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:22:14-06:00</updated>
<content type="text">drawZone was always seed-pure — so the generator legally reads the SAME
climate the sky presents. Systems that never felt each other now couple:
weather → surface → pilot brake styles → boost economy.

- src/gen/climate.ts: MOODS + BIOME_MOOD_BIAS + drawZone moved verbatim
  from client atmosphere.ts (draw SHAPE unchanged — skies are part of
  every shared seed); segmentClimate(seed, i) = the BASE zone draw (the
  biome lean stays presentation-only: islands are planned inside the
  zone, so the base draw is the only self-consistent generation input).
  ZONE_SEGMENTS lives here now; atmosphere.ts re-exports for the client.
- path.ts MOOD_CLAUSE_BIAS: snowdrift grows icy patches (x2.5) and damps
  sprints; goldhour soars (jump x1.6, sprint x1.4, icy x0.5); ember
  sprints + corner-drops; abyss pulls gravity x1.8; midnight forks
  (braid x1.5, spur x1.4); violet spirals (helix x1.7, reorient x1.3).
  One weighted draw either way — stream shape identical, outcomes lean.
- furniture.ts: ember storms gust harder and rise (gust x1.4, updraft
  x1.4); snow muffles gusts (x0.7). Threshold multipliers only.
- Corpus law test: snowdrift icy-rate &gt; 1.5x goldhour; goldhour outjumps
  snowdrift — the coupling is measurable, not cosmetic.
- THE pin cycle: the climate bias moved nearly every endless pin.
  Re-scanned + re-pinned: reorients grav-scan-20(+90)/grav-scan-13(180),
  helix jump-scan-14@0, spurs grav-scan-3@0/grav-scan-36@1 (grav-scan-18
  rejected: a 180 twist upstream of its spur made a hostile scenario),
  gust bank wide-scan-30@8, tagged OPEN braid grav-scan-17@1 (boost-alt
  vs icy-main across a segment boundary), bump/vortex corpora widened.
  206 green, check clean, endless goldens re-pinned, genVersion
  unchanged (finite untouched).</content>
</entry>
<entry>
<id>416d6ab4e8c96bec8d9705859ff7da66797301dd</id>
<title>ISLAND MASS FAMILIES (user directive): islands stop being one body in different paint</title>
<link href="https://src.rest/cat/marbles/commit/416d6ab4e8c96bec8d9705859ff7da66797301dd/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T21:07:18-06:00</updated>
<content type="text">&#39;Islands are mostly just one type with a color phenotype plus decor&#39; —
now the island BODY itself is a vocabulary:
- MASS_FAMILIES in islands.ts: &#39;cliff&#39; (nature voxels, full shaping
  vocabulary — untouched code path) vs &#39;block&#39; families (Platformer Kit
  voxels, measured: clean 1.0 full / 0.5 low courses, bottom-center,
  cosmetic 0.082 lip overhang, INTEGRATED tops — no cap tile).
- BiomeSpec.massFamily: winter is BUILT OF SNOW now (block-snow body,
  tinted-cliff phenotype retired); new &#39;grove&#39; biome (block-grass body,
  forest decor). Ten biomes total.
- proxies blockHeight knows platformer courses (1x1 boxes per course,
  lip is cosmetic); islandRender treats block masses as occluders with
  value-jitter-only coloring (pre-textured tops must not be hue-tinted).
- Platformer Kit imported + joined DECOR_PACKS / GOLDEN_PACKS / test
  manifests.
- MEASURED RULINGS on the record: Space Kit terrain_* is a SURFACE kit
  (flat top + 0.5 skirts, hollow underside, off-origin authoring) —
  wrong for void islands seen from below, deferred again; block corner
  rim-rounding awaits a mesh-orientation measure.
- Corpus: grove+winter block islands emerge across biome scan; 21.9k
  block voxels / 30 seeds. 205 green, endless goldens re-pinned,
  genVersion unchanged.</content>
</entry>
<entry>
<id>3b979a648b28c0ad022a69e44977f0d0fb89898e</id>
<title>progress.md: current-state line for the M18-M20 + V3 round (205 tests)</title>
<link href="https://src.rest/cat/marbles/commit/3b979a648b28c0ad022a69e44977f0d0fb89898e/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T20:41:43-06:00</updated>
<content type="text"></content>
</entry>
<entry>
<id>1abfbcfa2ee94e3884c5b119d2560237cdb8e1a3</id>
<title>OPEN FORKS (V3, user directive): the line forks now and answers later</title>
<link href="https://src.rest/cat/marbles/commit/1abfbcfa2ee94e3884c5b119d2560237cdb8e1a3/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T20:41:17-06:00</updated>
<content type="text">&#39;Forking currently exists as a singular generative pass only. It should
allow for unresolved forks to resolve in later generation up to a
point.&#39; — the braid clause may now leave its fork OPEN at the segment
boundary; the successor segment MUST open with the continuation and
merge within OPEN_BRAID_CAP total cells (bounded irresolution).

- path.ts: HeadState.openBraid carries {side, offset, cells, laneMods,
  wanderer} across the boundary; tryBraidSide draws an open coin (new
  child stream — zero draw perturbation; the pinned braids simply drew
  closed) and runs the braid flush to the boundary (its straight tail IS
  the seam margin; profile keeps no return budget); planSegment resolves
  an inherited fork FIRST via tryBraidContinuation (longest-fits-first,
  profile walks the carried offset home, V1 merge at a pinned straight).
  The alt lane&#39;s own boundary corridor is checked with the
  hasFlatContinuation CONTRACT pose (the next cell past the seam — the
  bug that silently killed every open attempt in the first cut), and the
  successor-probe gate is what makes leaving a fork open safe: it only
  commits when the continuation actually plans.
- world.ts: fork mutation only on non-cont braids, merge only on
  non-open; alt chains build headless/tailless per case and hang
  contBraid/openBraid flags; EndlessSegment.braidContOf names the fork
  segment; lane-tag lip margins apply only at ends that ARE junctions.
- proxies.ts: a continuation chain&#39;s carrier window keeps its plain
  channel RIBBON (no fork mouth cut into an ordinary wall) and no fork
  composite; the merge composite emits as ever.
- Client: railFor + braidLaneFor + the rider hook carry the FORK
  segment&#39;s per-racer lane draw across the boundary (one draw per BRAID
  — no re-draw, no teleport-flip mid-braid); rival mirroring keys on the
  same label.
- Tests: V3 contract (open resolves next segment exactly once,
  braidContOf, side/laneMods carry, cap law, alt-lane PORT CONTINUITY
  across the seam &lt;1e-6); closed contract scoped to closed braids; lip
  law knows boundary ends; drive() soak on grav-scan-32 crosses the
  boundary on BOTH lanes and merges home. Corpus: 136 braids / 14 open /
  0 planner failures over 160 seeds x 8 segments.
  205 green, check clean, endless goldens re-pinned.</content>
</entry>
<entry>
<id>b82e133b3c8b151f300cbb23c2ff29c4de94422d</id>
<title>VOID SHARDS (user correction): the void stops growing bushes</title>
<link href="https://src.rest/cat/marbles/commit/b82e133b3c8b151f300cbb23c2ff29c4de94422d/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T20:22:25-06:00</updated>
<content type="text">Floating ground props read as set-dressing that forgot gravity. The
void vocabulary is now things that plausibly float:
- GENERIC: floating island SHARDS — torn-off islets (cliff course(s) +
  grass cap + ragged quarter underside), every piece sharing ONE float
  so the islet bobs and drifts as a body; plus space debris (meteors,
  crystals).
- Biome tables purged of ground props (pirate sand rocks, holiday rock
  piles, autumn sand rocks OUT); ships, the ghost, the crypt and the
  snowflakes stay.
- Shard clearance covers the whole islet (cap and underside), not just
  its base.
- Test: floating-ground-prop ban (nature ids in the void must be shard
  components), capless-grass ban, shared-float/scale shard coherence.
  203 green; endless goldens re-pinned.</content>
</entry>
<entry>
<id>2657265edb30939aae7e5cfd81bc7205072f4dbf</id>
<title>LOOP BREADTH (M19c): twin diamonds, stub gardens, rotundas, richer pillars</title>
<link href="https://src.rest/cat/marbles/commit/2657265edb30939aae7e5cfd81bc7205072f4dbf/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T20:18:56-06:00</updated>
<content type="text">Finite-mode set-piece breadth, one batched genVersion shift
(g491fc4c7a685 → g555803244402), endless goldens&#39; segment hashes
byte-identical (only the embedded __version moved — the supports gate
held):

- features.ts: a SECOND split-merge diamond on another run (own child
  stream, 0.5) — two lane-choice events per lap. The chicane pair from
  the design was ruled out by MEASUREMENT (mutated rings top out at
  ~9-cell straight runs; the pair needs 11) and adapted honestly.
- stubs.ts: STUB GARDEN — 2-3 clustered sidings sharing one cap style
  plus a trackside fan facing the ring beyond the middle cap; with the
  M19a loop wind backport the garden literally breathes on passing
  marbles. Appended child stream.
- scenery.ts: TWO-TIER ROTUNDA — measured: open and solid curve-wide
  forms are both exactly 0.5 tall with identical footprints, so a solid
  ring is a plinth the open ring stacks on flush. Appended child draw.
- supports.ts: planStack gains an extended pattern pool (three-band
  taper four→two→single, pedestal) GATED to loop-mode call sites
  (assemble !open, takeable falsework) — the endless viaduct hash space
  is untouched and the endless golden test is the tripwire. Both new
  patterns obey the containment law (narrower always on wider).
- Tests: scenery-ring law extended to rotunda tiers; pinned scenarios
  loop-scan-981 / loop-scan-20 / loop-scan-33. golden_tracks.json
  regenerated once. 202 green, check clean.</content>
</entry>
<entry>
<id>eb4271346ab5c2112dfc25c36041e7611c8fb6b9</id>
<title>LANE IDENTITY (M19b): braids where the lane you draw matters</title>
<link href="https://src.rest/cat/marbles/commit/eb4271346ab5c2112dfc25c36041e7611c8fb6b9/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T20:07:46-06:00</updated>
<content type="text">Lane mods + wanderer character — one intentional reshuffle, tag-only law:

- path.ts: Braid.laneMods drawn from a new child stream (0.5 none /
  0.25 icy-alt+boost-main / 0.25 inverse); wanderer character (own
  child, 0.35) leans the SAME profile range outward via weighted picks
  (pick and weighted both consume one draw — non-wanderer braids stay
  byte-identical; the wanderer bias IS the reshuffle) and always carries
  the alt-boost compensation, so the long way around is never a strict
  loser. Breadth stays capped at B (no new twist-window veto pressure).
- TAG-ONLY LAW: lane mods never join plan.mods (realize&#39;s exclude rules
  must not see them — geometry is sacred), never pin windows. world.ts
  stamps main-lane windowMods over the braid INTERIOR only (&gt;=2 cells
  from fork and merge — the junction-lip law in friction form) and hangs
  per-part zone tags on the alt chain (LoopSegment.alt.zones, chain ends
  untagged); tagged windows&#39; placements carry zone for the recolor.
- world.ts realize generalized over plan.braids (bare braid-wfc label
  for braid 0 — existing seeds byte-identical; &gt;1 braid is now a
  one-line planner change away, with its own pin cycle).
- rail.ts: alt-chain stations OVERLAY the tag on the fork&#39;s centering
  ({center, icy}/{center, speed}) — untagged chains (diamonds, spurs,
  V1 braids) byte-identical.
- Presentation: BOOST_PIPE amber joins ICE_PIPE/GRAVITY_PIPE — boost
  zones (sprints AND boost lanes) now recolor: zones must read.
- Tests: corpus lip-law scan (plan.mods zones exempt — a jump&#39;s boost
  approach may brush the merge), wanderer-compensation law, alt-zones
  alignment, rail overlay signature on the pinned grav-scan-6@4 braid;
  drive() soak clears the tagged braid on BOTH lanes. New pins:
  grav-scan-6@4 icy/wanderer, grav-scan-10@3 boost lane; braid pins
  grav-scan-17/38 held. 199 green, check clean, endless goldens
  re-pinned, genVersion g491fc4c7a685 unchanged.</content>
</entry>
<entry>
<id>fb13e4f3dbbd8f5858a573c0801eae576979a7ff</id>
<title>RIVALRIES (M20b): seeded grudges and allies, temper, brake style</title>
<link href="https://src.rest/cat/marbles/commit/fb13e4f3dbbd8f5858a573c0801eae576979a7ff/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T19:55:40-06:00</updated>
<content type="text">Directed seed-pure relationships expressed ONLY through existing
actuators — no new physics surface, zero gen-side movement (goldens and
scenario pins untouched; the A0 lock proves the trait appends clean).

- peersCore rivalFor(seed, i, n): own label rival/${i}, fixed draw order
  (has 0.5 → offset 1-16 → valence 70/30 grudge → intensity 0.5-1).
  DIRECTED — i hunts its target, the target is oblivious (a symmetric
  pair would need a shared hash, banned by the rng law). Resolved once
  at pack build.
- Traits appended AFTER M20a&#39;s (milestone order IS the draw order):
  brakeStyle 0.8-1.35 scales the PLANNING decel in the brake sweep
  (6·1.35 &lt; A_BRAKE_MAX 10 — a late-braker can always shed what it
  planned; the band inequality is test-pinned), temper 0-1 opens a ~3s
  hot window on contact (temperStep mirrors boostStep; the contact proxy
  is a neighbor inside 2.5 radii — the shim has no contact events).
- decide() expression, levers only: grudge target ahead reads closer
  (gap/(1+intensity) into an unchanged boostStep) and ally never
  triggers an attack; separation asymmetry via the REPORTED neighbor
  bravery (−0.1·intensity, autopilot compare untouched); defensive
  blocking stands in the chasing rival&#39;s line (offset ≤0.25 &lt;
  CORRIDOR_DEAD, engage/release hysteresis + slew, strict priority
  overtake &gt; block &gt; wander on the one offset actuator); braid lane
  mirroring adopts the rival&#39;s own label-pure draw (grudge follows,
  ally opposes) behind a 10u proximity gate. All transient state resets
  on demote/promote/respawn; rivalry expresses in the live band only.
- HUD: PlaceHud gains one quiet token `#3/128 · R#7`, flag-gated
  (?rival=1), Kenney-frame styling inherited — default decided at
  review. Telemetry: hero rival + grudge-ignition counter, spread/burst
  from M20a.
- Tests: temper decision table, brakeStyle envelope behavior + band
  pins, rivalFor determinism/independence/coverage laws. 196 green,
  check clean, goldens byte-identical.</content>
</entry>
<entry>
<id>5c4fd0d74aee4e3302f11d16fd601f1e4cfda09d</id>
<title>PACK DYNAMICS (M20a): drafting, lane personality, overtake commitment</title>
<link href="https://src.rest/cat/marbles/commit/5c4fd0d74aee4e3302f11d16fd601f1e4cfda09d/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T19:49:38-06:00</updated>
<content type="text">The pack interacts through the air and the line, not just contact/fuel —
all inside the existing envelope law, zero gen-side movement (both golden
files byte-identical; scenario pins untouched).

- A0 FIRST: tests/personality_snapshot.json + the appended-draw lock —
  pilotFor/racerIdentity/braidLaneAlt fixture captured PRE-change; the
  test walks only fixture keys, so appends stay green and any in-stream
  insert goes red. The fixture regenerates only from a known-good commit.
- Traits appended after efficiency: wake 0.6-1.4 (draft appetite),
  lanePref 0.35-0.65 (braid threshold), chir ±1 (passing side).
- draftFactor(gap, wake): wake window 1.2-5.0u behind the same-lane
  leader, ≤ +10%, threaded into autopilotForce as targetMult exactly like
  boostMult — wishspeed stays min(target, vSafe): drafting into a corner
  brakes identically (envelope test proves the cap).
- decide(): captures the gap-ahead racer; same-lane gate on braids;
  r.draft at decision cadence (1-step-lag contract); overtake commitment
  holds pilotEff.offset = chir·0.27 (&lt; CORRIDOR_DEAD 0.3 — the corridor
  spring never fights it) while a burn is an attack, engage &lt;3.5u /
  release &gt;5u hysteresis + 0.4s slew on the single offset actuator.
  State resets on demote/promote/respawn.
- Riders: rank stamped in the sort pass; riderUpdate applies the same
  draft law CAPPED at +8% (chained riders must never outrun the
  hero-anchored stream) and draws the same per-racer braid lane at
  segment entry, so the fork split ratio holds at LOD distance.
- braidLaneAlt(seed,idx,seg,pref): SAME label, SAME single draw, moving
  threshold only — historical coin == pref 0.5 (test-pinned).
- Telemetry: race JSON gains respawnBurst (2s window), spreadP10P90 (the
  liveliness tripwire), per-racer draft.
- Tests: draft window/falloff/cap tables, envelope safety, lane
  monotonicity + per-racer independence, trait bands, fuzz harness runs
  the draft law with client parity + asserts a wake window opened;
  determinism run-twice still byte-equal. 193 green, check clean.</content>
</entry>
<entry>
<id>74731b242648c8051e0cd701703bffcc99804114</id>
<title>VOID DECOR (M18b): the empty air gets furniture — drifting shoals, ships, ghosts, meteors</title>
<link href="https://src.rest/cat/marbles/commit/74731b242648c8051e0cd701703bffcc99804114/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T19:40:37-06:00</updated>
<content type="text">New generative system, zero perturbation of existing streams (new labeled
family &quot;void-decor&quot;):
- gen/endless/voidDecor.ts: per-segment clusters (0-2, expected ~1) of
  1-5 pieces hung off the segment&#39;s own path samples — mid band 8-16u
  (slightly below the line), far band 18-40u scaled into fog silhouettes;
  biome-flavored tables (ships off tropical coasts, a ghost + crypt in
  spooky air, snowflakes in winter, sand shoals in autumn) + generic
  rock/crystal shoals; rare far-band EVENTS ~0.08 (meteor trains, a
  passing craft/satellite) with pure-in-index quiet-after suppression.
  Sites keep &gt;=6u of every path sample (main+alt), island cells, and any
  occupancy claim at their column. Space Kit imported (153 pieces).
- EndlessSegment.voidDecor is a SEPARATE field: the proxy path
  structurally cannot see it — non-collision by construction (contract
  test: proxies byte-count-identical with the field stripped).
- Placement.float {amp, period, phase, drift} — the wind model: canon
  hashes it; genVersion untouched (finite never emits it).
- client/voidRender.ts: instanced flat in the frame-correct segment
  group (spawn/exit waves see direct children; twist halves split per
  anchor), castShadow off, no occluder flag; float pass in finishFrame
  gated on the spawn wave (writer-overlap-free) with a 2s bob envelope +
  capped segment-local drift; fit box skips voidDecor-flagged meshes
  (far shoals must not inflate shadow/focus).
- Tests: same-seed determinism, 30x8 structural scan (budget, clearance,
  resolution, float-on-every-piece, multi-pack emergence), proxy
  blindness contract, event rarity + never-consecutive law.
  188 green, check clean. Endless goldens re-pinned (canon + content);
  genVersion g491fc4c7a685 unchanged.</content>
</entry>
<entry>
<id>ad5a11148863dca8b4d2d345465fe3982e7cbdd9</id>
<title>THEME PACKS (M18a): winter, spooky, tropical, autumn islands on four new kits</title>
<link href="https://src.rest/cat/marbles/commit/ad5a11148863dca8b4d2d345465fe3982e7cbdd9/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T19:31:55-06:00</updated>
<content type="text">- Import pipeline: Holiday/Graveyard/Pirate/Survival kits packed (one
  colormap each); DEFAULT_PACKS grows to six.
- decor.ts: SETTINGS rows carry pack + finite flags; pickSetting draws
  ONLY the historical nature trio (the genVersion guard — finite stream
  byte-identical, golden_tracks untouched); settingByName reaches the four
  new regex tables (patterns + scale ranges measured per pack: pirate is
  ~2.5-3x nature scale, survival props tiny).
- islands.ts: BiomeSpec capId fully-qualified, per-biome landmark lists +
  landmarkScale (default = the historical nature statue list, draws
  byte-identical); four appended rows (w 1.2/0.8/1.2/1.0 — nature keeps
  ~70%, a themed island is an event). Caps reuse the 1x1 nature ground
  tile; measured: no themed pack ships a clean 1x1 cap.
- Client: assets.ts loads a DECOR_PACKS list + manifests map; catalogs
  (client + goldenCatalog + all gen-side tests) carry all five packs —
  settings resolve against the catalog, so pack presence shapes output.
- Presentation: islandRender biome tints (snow-creep courses, graveyard
  gloom, sandstone strata, ochre mottling; snow/sand cap repaints; pinned
  foliage leans); atmosphere drawZone takes a biome bias (zone&#39;s dominant
  island biome multiplies mood weights — winter leans snowdrift etc.,
  same rng draw shape, presentation-only).
- Tests: finite-trio lock, per-row manifest resolution, 40-seed themed
  scan (placement resolution + cap 1x1 law). 184 green, check clean.
- Endless goldens re-pinned (biome reshuffle, island-local); scenario
  pins all held; genVersion g491fc4c7a685 unchanged.</content>
</entry>
<entry>
<id>1c0d8ec2b0e44a5bf85de6f00ef329b835a5f442</id>
<title>GUST WALLS (M19a): the wind gets a clock — pulsed blockades, vortex eddies, loop backport</title>
<link href="https://src.rest/cat/marbles/commit/1c0d8ec2b0e44a5bf85de6f00ef329b835a5f442/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T19:20:26-06:00</updated>
<content type="text">Wind &amp; hazard vocabulary, all appended draws (zero rng-stream reshuffle):
- Placement.wind gains pulse {period,duty,phase} + swirl; canon hashes both.
- fanField: pulseGain (cosine-eased duty windows on SIM time), swirl volumes
  (tangential force around a vertical column), FanField.setTime.
- furniture: gust walls upgrade cross fans in place (strength 14, duty .45,
  period 2.4-3.6s); vortex = table fan at the lip, eddy over the channel;
  coordinateGusts post-pass (rng-free) phase-locks banks into travelling
  waves and sets same-host L/R pairs anti-phase.
- endless Session: windT sim clock drives the field (advanceTime-pure).
- Loop backport: FanField over loop fan placements; kinematic marble takes
  tangential wind into speed and lateral wind into a clamped channel sway.
- Tests: pulse/swirl/coordination laws, corpus emergence (16x10), gust
  scenario rules + pinned bank (wide-scan-13), windy drive() soak through
  the bank with bit-identical replay. 181 green, check clean.
- Endless goldens re-pinned (content adds); genVersion unchanged.</content>
</entry>
<entry>
<id>38d562aafc37964742db8c997283d7e10eff4e7d</id>
<title>MEASURED COLLISION (audit round): the proxies now match the kit, and CI proves it</title>
<link href="https://src.rest/cat/marbles/commit/38d562aafc37964742db8c997283d7e10eff4e7d/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T18:40:55-06:00</updated>
<content type="text">Full remediation of docs/collision-mesh-audit.md (119/119 pieces,
re-audited clean same day — docs/collision-mesh-reaudit.md), built on
headless GLB measurement (gltf-transform over marble-kit.glb, pattern
tools/measure_ports.ts). Measured truths, grid units: wall inner face
0.287, rim floor+0.25, floor bore ROUND r 0.25 in straight-hole and
BOTH end-hole flavors, wide inner wall 0.575, split-double walls at
branch ±0.287.

- PARITY (T7): segmentProxies() is the ONE channel builder for
  production, the ?gallery=1 bench, and the sims (the bench had been
  omitting wide scales — a diagnostic-only wiring defect that falsified
  five audit rows). gapSegmentsOf lives with it; rail.ts re-exports.
  Bench asserts finite mesh bounds, frames empty plots safely, and
  ghosts cross-over&#39;s host mesh (a deliberate noMesh phantom).
- APERTURES (T2/T5): PieceDef.holes → LoopSegment.holes opens a real
  bore in the ribbon (lip decks, side slivers, walls, under-deck guide
  ring). Drop-stacks get an authored measured compound: annulus deck,
  octagonal cup (r 1.0 world) with the entry arch open, octagonal
  shaft, receiver cup opened toward the true exit yaw, pan law kept.
- WIDTH (T1): widening is an additive wall SHIFT (0.576 world/side),
  not the old x2.43 section scale that put wide walls outside the
  visible +-1.7 mesh; the bench passes def-authored port widths so an
  isolated funnel tapers honestly.
- RIM (T6): CHANNEL_PROFILE tops at 0.62 over floor (measured rim 0.5
  + 0.12 solver cap), wall face 0.62 lateral; junction composite walls
  follow the same law (diamond/spur/braid tightened ~0.4/side to the
  measured split-double faces).
- TURNS (T3): arc stations bounded by outer-boundary chord sagitta
  (0.008 world) instead of a fixed angle; crease rounding stays as the
  documented kicker-prevention law.
- JUNCTIONS (T2): the cross cell emits ONE authored 4-way composite
  (deck + solid corner posts, all four port arches open) from the mesh
  visit; the phantom is silent — two same-height route ribbons used to
  wall each other&#39;s route off.

QUANTITATIVE CI (tests/collision_metrics_test.ts + collision_width_test):
ring floor/lateral/rim budgets (3009 rings, worst floor err 0.041 at
slant-d&#39;s intentional crest rounding), RENDER-derived directed distance
(40k GLB channel verts within 0.2 of the collision surface; corridor
excludes port-face bands — shared boundaries the neighbor&#39;s ring
covers — and drop shells&#39; cosmetic corners), bore-openness probes (13),
drop compound probes (12), diamond compound probes (3), cross probes,
and per-variant coverage accounting (rings 113 / render-dist 101 /
probes 17 / paired-by-design 1; bench-build failures fail loudly).
The CI caught three real defects during bring-up: approach ribbons
overhanging drop bores (lip-trimmed), missing bore side slivers, and
thin cross corner Ls (now solid posts).

174 tests green, deno task check clean.</content>
</entry>
<entry>
<id>d32bc7844122c0aa1810d61f2f1524fe6c9ba911</id>
<title>progress.md: test count 162</title>
<link href="https://src.rest/cat/marbles/commit/d32bc7844122c0aa1810d61f2f1524fe6c9ba911/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T17:09:43-06:00</updated>
<content type="text"></content>
</entry>
<entry>
<id>60c3c011a4f108bec9312e652ab76388af5b0c9f</id>
<title>progress.md: M17 braids + bench in the current-state line; pin table refreshed</title>
<link href="https://src.rest/cat/marbles/commit/60c3c011a4f108bec9312e652ab76388af5b0c9f/"/>
<author><name>Dami</name></author>
<updated>2026-08-09T17:09:22-06:00</updated>
<content type="text"></content>
</entry>
</feed>
