Commits
Doesn't replicate the dynamics from Fluoddity, thinking it may be due to world scale
difference (current version hardcodes at ws = 1.0).
Opus 4.8's description:
On load you get a 3×3 grid. Each cell warms to its converged frame and freezes. Hover a cell → only that one animates (the rest stay still);
move away → it freezes at its new state. Click a cell → it opens full-screen with a top bar: ← Back to grid and Breed from this →. The editor panels (Controls / Genome / Lineage) appear only in focus. Breeding spawns that organism's children as the next grid; Back just returns to the (cached, frozen) grid.
Fidelity is structural, not approximate: thumbnails are the same resident sim at the same pins (1024²/512², same seed) as the full-screen view — just rendered into a small texture and downscaled-to-fit. The preview can't drift from the actual because there's only one sim.
Files
- engine/shaders/blit.{vert,frag} — a vUv-varying blit so a thumbnail composites correctly into any sub-viewport (the existing display shader's gl_FragCoord/uViewport math breaks in sub-rects). glutil.createColorTarget (RGBA8/LINEAR) backs the thumbnails.
- engine/Engine.ts — mode: single|grid; setGeneration / setHover / setMode / warmup / setOnBuildDone. Grid frame builds one candidate per frame (warm→capture, a brief reveal), animates the hovered tile live, and renderGrid blits letterboxed squares. One resident sim, time-sliced — zero new shader math beyond the blit.
- evolution/spawn.ts (pure) — freshGenome / randomGenomes / spawnChildren; genome.svelte.ts now reuses freshGenome.
- state/generation.svelte.ts — CPPNs + compiled rules held non-reactively (Maps/typed-arrays never proxied), reactive nonce/size/cols/building; generationSpecs() is the orchestrator pull.
- ui/BreederGrid.svelte — transparent hit-target overlay (grid) + focus top bar. view.mode = grid|focus.
- App.svelte — grid-first; a generation $effect pushes specs to the engine; the genome $effect is gated to focus so leaving the grid never disturbs cached thumbnails.
Known v1 wrinkles (by design, flagged earlier)
- Hover re-warms on tile switch (~sub-second) since there's one resident sim. The instant-hover upgrade (per-tile GPU state, ~290 MB) is noted in memory if it ever annoys you.
- Breeding compiles 9 genomes synchronously (~0.2–0.5 s freeze) before the "evolving…" reveal. Async-compile is a later polish.
- Grid hover-highlight is a full-cell tint; the thumbnail is a centered square inside it — close but not pixel-aligned.
Opus 4.8 says:
The split. The flat inspector store is gone, replaced by three ontology-grouped stores that mirror the record schema:
- state/organism.svelte.ts — morphology (sensor gain/angle/distance, force mult, strafe, axial/lateral, deposit gain)
- state/environment.svelte.ts — the shared dish (drag, trail persistence, trail diffusion)
- state/view.svelte.ts — display-only (exposure, debug) + the restart signal
- state/substrate.svelte.ts — the orchestrator fold: assembles the engine's flat SubstrateParams from organism+environment (the engine boundary
is unchanged — it doesn't care about the ontology, it just needs the 10 params).
Controls.svelte now shows three labeled sections (Organism · Environment · View), and breeder.svelte.ts's record mapping is nearly 1:1 instead
of un-flattening a bag. dragCoefficient is deliberately not a live slider yet — it stays 1.0 in saved records until the Stokes product is
plumbed into the shader (so the env drag slider is the only drag knob for now). Reset restores Wild7 defaults per group; the engine wasn't
touched.
Persistence: yes, in-memory only, and yes it's planned. MemoryRepository is a heap Map — every refresh wipes it. The fix is LocalRepository on
IndexedDB behind the same Repository interface, so save/load/lineage code above it doesn't change at all. Given it already cost you organisms,
I'd pull it forward rather than wait.
Milestones remaining (recap): the real Picbreeder breeder grid (thumbnails of a population → select → breed) + thumbnail rendering, IndexedDB
persistence, the DAG lineage graph view you asked for, viability filtering (auto-reject duds), and all of atproto (OAuth + publish). We're
roughly mid-M3.
Hand-written WebGL2 engine for the v0 Fluodditylike substrate, driven by the
hardcoded 244-float Wild7 anchor rule (docs/golden/Wild7-tweak3.json). Proves
the substrate runs in-browser.
- engine/: imperative Engine (no Svelte) — ping-pong RGBA32F particle texture +
RGBA16F field/deposit, 4-pass loop: particle_update (2 sensors -> symmetrized
244-float plane-wave rule -> integrate) / deposit (additive gl.POINTS gaussian
scatter) / field_update (5-tap diffuse + persist) / display (HSV flow).
- Math per docs/v0_normalization.md (world_size = 1); rule layout per
generalized_engine_spec.md.
- Robustness found via Firefox debugging: field/deposit are RGBA16F so additive
blending needs no EXT_float_blend; textures are explicitly zero-filled because
drivers don't reliably honour null texImage2D init. CPU readback auto-exposure
dropped (Firefox blocks canvas readPixels) in favour of a fixed/tunable exposure
plus a GPU-side diagnostic display.
- state/inspector + ui/Controls.svelte: live sliders for the 10 v0 params (+
deposit gain, exposure, diagnostic toggle), pushed into the engine through the
orchestrator seam ($effect snapshot). Plain reactive data only — no GL in $state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Opus 4.8's description:
On load you get a 3×3 grid. Each cell warms to its converged frame and freezes. Hover a cell → only that one animates (the rest stay still);
move away → it freezes at its new state. Click a cell → it opens full-screen with a top bar: ← Back to grid and Breed from this →. The editor panels (Controls / Genome / Lineage) appear only in focus. Breeding spawns that organism's children as the next grid; Back just returns to the (cached, frozen) grid.
Fidelity is structural, not approximate: thumbnails are the same resident sim at the same pins (1024²/512², same seed) as the full-screen view — just rendered into a small texture and downscaled-to-fit. The preview can't drift from the actual because there's only one sim.
Files
- engine/shaders/blit.{vert,frag} — a vUv-varying blit so a thumbnail composites correctly into any sub-viewport (the existing display shader's gl_FragCoord/uViewport math breaks in sub-rects). glutil.createColorTarget (RGBA8/LINEAR) backs the thumbnails.
- engine/Engine.ts — mode: single|grid; setGeneration / setHover / setMode / warmup / setOnBuildDone. Grid frame builds one candidate per frame (warm→capture, a brief reveal), animates the hovered tile live, and renderGrid blits letterboxed squares. One resident sim, time-sliced — zero new shader math beyond the blit.
- evolution/spawn.ts (pure) — freshGenome / randomGenomes / spawnChildren; genome.svelte.ts now reuses freshGenome.
- state/generation.svelte.ts — CPPNs + compiled rules held non-reactively (Maps/typed-arrays never proxied), reactive nonce/size/cols/building; generationSpecs() is the orchestrator pull.
- ui/BreederGrid.svelte — transparent hit-target overlay (grid) + focus top bar. view.mode = grid|focus.
- App.svelte — grid-first; a generation $effect pushes specs to the engine; the genome $effect is gated to focus so leaving the grid never disturbs cached thumbnails.
Known v1 wrinkles (by design, flagged earlier)
- Hover re-warms on tile switch (~sub-second) since there's one resident sim. The instant-hover upgrade (per-tile GPU state, ~290 MB) is noted in memory if it ever annoys you.
- Breeding compiles 9 genomes synchronously (~0.2–0.5 s freeze) before the "evolving…" reveal. Async-compile is a later polish.
- Grid hover-highlight is a full-cell tint; the thumbnail is a centered square inside it — close but not pixel-aligned.
Opus 4.8 says:
The split. The flat inspector store is gone, replaced by three ontology-grouped stores that mirror the record schema:
- state/organism.svelte.ts — morphology (sensor gain/angle/distance, force mult, strafe, axial/lateral, deposit gain)
- state/environment.svelte.ts — the shared dish (drag, trail persistence, trail diffusion)
- state/view.svelte.ts — display-only (exposure, debug) + the restart signal
- state/substrate.svelte.ts — the orchestrator fold: assembles the engine's flat SubstrateParams from organism+environment (the engine boundary
is unchanged — it doesn't care about the ontology, it just needs the 10 params).
Controls.svelte now shows three labeled sections (Organism · Environment · View), and breeder.svelte.ts's record mapping is nearly 1:1 instead
of un-flattening a bag. dragCoefficient is deliberately not a live slider yet — it stays 1.0 in saved records until the Stokes product is
plumbed into the shader (so the env drag slider is the only drag knob for now). Reset restores Wild7 defaults per group; the engine wasn't
touched.
Persistence: yes, in-memory only, and yes it's planned. MemoryRepository is a heap Map — every refresh wipes it. The fix is LocalRepository on
IndexedDB behind the same Repository interface, so save/load/lineage code above it doesn't change at all. Given it already cost you organisms,
I'd pull it forward rather than wait.
Milestones remaining (recap): the real Picbreeder breeder grid (thumbnails of a population → select → breed) + thumbnail rendering, IndexedDB
persistence, the DAG lineage graph view you asked for, viability filtering (auto-reject duds), and all of atproto (OAuth + publish). We're
roughly mid-M3.
Hand-written WebGL2 engine for the v0 Fluodditylike substrate, driven by the
hardcoded 244-float Wild7 anchor rule (docs/golden/Wild7-tweak3.json). Proves
the substrate runs in-browser.
- engine/: imperative Engine (no Svelte) — ping-pong RGBA32F particle texture +
RGBA16F field/deposit, 4-pass loop: particle_update (2 sensors -> symmetrized
244-float plane-wave rule -> integrate) / deposit (additive gl.POINTS gaussian
scatter) / field_update (5-tap diffuse + persist) / display (HSV flow).
- Math per docs/v0_normalization.md (world_size = 1); rule layout per
generalized_engine_spec.md.
- Robustness found via Firefox debugging: field/deposit are RGBA16F so additive
blending needs no EXT_float_blend; textures are explicitly zero-filled because
drivers don't reliably honour null texImage2D init. CPU readback auto-exposure
dropped (Firefox blocks canvas readPixels) in favour of a fixed/tunable exposure
plus a GPU-side diagnostic display.
- state/inspector + ui/Controls.svelte: live sliders for the 10 v0 params (+
deposit gain, exposure, diagnostic toggle), pushed into the engine through the
orchestrator seam ($effect snapshot). Plain reactive data only — no GL in $state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>