eureka-site/README.md

190 lines
10 KiB
Markdown
Raw Permalink Normal View History

# How we built a PS1 dungeon to sell a code-review workflow
[Eureka](https://eureka.gamecult.org/forge/GameCult/Eureka) is a Claude Code skill built on
one rule: the agent that writes the code does not get to certify that the code
works. It needed a landing page. This repo is that page, and it turned into a
PlayStation 1 game you scroll through.
Served at **https://eureka.gamecult.org/**.
## Front Door
- **Value:** the landing page for [Eureka](https://eureka.gamecult.org/forge/GameCult/Eureka), a scroll-driven WebGL dungeon rendered as a PlayStation 1 game, plus MIT-licensed parts you can lift: a PS1 material and dither pass for three.js, a scroll-on-rails camera pattern, and self-contained organ builders.
- **Problem:** explain a code-review workflow (the agent that writes the code does not certify it) as something you travel through rather than read about.
- **Entry points:**
- `prototype/index.html`: the copy; each `<section data-stop>` pins one camera stop.
- `prototype/ps1.js`: the reusable PS1 kit (`ps1()` material, `framebuffer()`); `prototype/organs.js`: the organ builders; `prototype/world.js`: the scene and `ROUTE`; `prototype/main.js`: the scroll timeline.
- Run locally: `python -m http.server 8765 --directory prototype`.
- `BRIEF.md` and `gpt6-copy.md`: the two source briefs; `docs/research/landing-claims-audit-2026-10-09.md`: copy claims labelled CURRENT, STALE or UNVERIFIED against the doctrine.
- **Live:** the page served at https://eureka.gamecult.org/ from `prototype/`; deployment is in `gamecult-ops` at `runbooks/eureka-prototype-yggdrasil.md`.
- **Planned:** nothing recorded in this repo beyond refreshing copy flagged STALE or UNVERIFIED in the audit.
## Two briefs, neither in charge
We started with two documents, and both are in this repo.
The first was [`BRIEF.md`](BRIEF.md). The agent that had been running Eureka on
a live multi-repo campaign wrote it with no guidance from us, because we wanted
the view from the ground. It is good on evidence. It lists real defects, each
caught by a pass that did not write the code, sitting behind a green suite. It
is also confident about things nobody had asked it to decide, such as which
static-site generator to use. We kept the evidence and overruled the rest. The
dated rulings at the top of the file record what was overruled.
The second was [`gpt6-copy.md`](gpt6-copy.md), a long copy draft that came out
of a longer conversation about where Eureka and GameCult are going. The page's
text is cut from it, along with its taste for short lines that land one at a
time.
## A camera on rails
The reference was [acko.net](https://acko.net/). What we took from it was
specific: the page background is a WebGL scene, and scrolling moves the camera
through it along a fixed path. Reading the page is the same as travelling
through it.
So the page is a route. Every section of text pins one camera stop, and unnamed
points in between shape the flight. It begins in a hall where a cracked monument
reads ALL TESTS PASSING, in front of a wall of green checkmarks. The next stop
looks at a floor hatch stencilled GREEN, which has been pried up. Below the
hatch, the route runs:
1. Down a shaft into Eureka's organ chamber.
2. Through a lattice where Soul's probes flip green nodes to orange.
3. Along a gallery of specimen cases: the mutation runner's four false greens, and one empty case.
4. Past an archive where the rules keep their evidence.
5. Into the vanishing twin's chamber, where Epiphany's scaffolding stands mostly
empty.
6. Up a second shaft into the hall, where the monument has now split along its
crack.
One number owns all of it. Scroll position becomes a path parameter `u`, and `u`
drives the camera, the organs, the probe animation, the staccato lines, and the
monument splitting at the end. There is no second clock to drift out of sync.
## Going full PlayStation
The first pass rendered at low resolution with a dither, which was tasteful and
wrong. Then we found keijiro's
[Retro3D](https://github.com/keijiro/Retro3D), a Unity shader of about 20 lines,
and went all the way to PlayStation 1. The whole effect comes down to a few
tricks, and each one ports to WebGL in a line or two:
- **Vertex snapping.** The PS1's geometry chip had no sub-pixel precision, so
every projected vertex snaps to a 240-line pixel grid. That is where the
wobble comes from.
- **Affine textures.** Texture coordinates are multiplied by depth in the vertex
shader and divided back out per pixel. That cancels the GPU's perspective
correction and gives the PS1's texture swim. Large floors are split into
tiles, as PS1 games did, so the warp looks charming rather than broken.
- **15-bit colour** with the console's own 4×4 ordered dither, applied in a final
full-screen pass.
- **Everything else:** lighting computed per vertex, fog to black, no mipmaps,
nearest-neighbour filtering, and half-transparent surfaces for glass and
Soul's crystal.
Nothing here is a model file. Every texture is drawn to a `<canvas>` at load,
and every mesh is built in code.
## The organs
Eureka's faculties come from Epiphany, the larger system it grew beside and
then absorbed.
[Aquarium](https://github.com/GameCult/Aquarium/blob/main/docs/epiphany-agent-sdf-visual-language.md)
already defines how each organ looks, as raymarched distance fields with PBR
materials. We demade them:
- **Self** is a black core inside gold orrery rails.
- **Soul** is a see-through verdict crystal with a white oath light, blue edges
and a red risk seam.
- **Hands** is a dark tool with three enamel jaws and a hot cutting edge.
- **Imagination** is an opal seed wrapped in curling ribbon petals.
- **Life** is a teal nautilus shell carrying an ember and memory beads.
- **Eyes** is a black-glass lens in blue-metal gimbals, behind spiral aperture
petals that narrow as evidence arrives, with cyan evidence sparks.
They sit on Aquarium's own orbit slots, so the camera's circuit around the
chamber is the Aquarium layout. The seat where Epiphany kept her Face belongs
to the viewer: in Eureka, the operator is a human.
Epiphany's chamber is the vanishing twin: the twin absorbed before birth, whose
cells the survivor carries. All eight cages still stand, mostly empty. Eyes has
already gone to Eureka; Body and Face rise out of their cages and drift toward
her as you pass.
## The thing at the far plane
GameCult's mark is a camera aperture, and we wanted it to hang behind the fog as
a megastructure. An earlier AI rendering showed the whole thing, evenly lit and
front-on, and it read as a medallion. Scale comes from what you can't see. This
aperture is a separate sky layer: it follows the camera's rotation and never
moves closer. It is tilted so you see it at an angle and held at a fixed depth
of fog. Its six blades are habitats (forest, desert, ice, falls, highlands, a
night city) around a gold hub, with stations in orbit. Underground it fades to a
faint presence. The iris opens as you read.
## Small machines that earned their place
- **Framing follows the text.** Text panels covered the subject in most shots.
We didn't retune 26 camera angles. Each section already says which side its
panel is on, so the camera shifts its framing toward the other side, eased
between stops.
- **Stops are checked.** The page's sections and the route's stops must match
one to one, in order. The page checks this on load and says so in the console
when they don't.
- **Motion is optional.** Without JavaScript, or with reduced motion turned on,
it is a readable page of prose. Reduced motion replaces the flight with a
still frame per section.
- **Verification ran headless.** The in-app browser we were using could not
capture the page once it had scrolled, even with rendering paused. Every stop
was checked with headless Chrome driven by puppeteer instead, using the
`?debug` readout and the `?wp=N` jump.
## Take the toys
The retro 3D adventure is what makes this page special. Sharing toys is what
GameCult is for, so it's all MIT: take any of it.
- **The PS1 kit** is [`prototype/ps1.js`](prototype/ps1.js), about 240 lines.
Only a little of it is specific to this page: the brand palette, and two
opt-in effects (`nodes` for the lattice probes and `cells` for the wall's
re-graded checks) that you can ignore or delete.
- `ps1({ map, color, emissive, rim, alpha, ... })` returns one three.js
material with vertex snapping, affine textures, per-vertex lighting, rim
light, fog and PS1 half-transparency, each switched on by options.
- `framebuffer(renderer)` gives you the low-resolution target and the 15-bit
dither pass.
- There are helpers for canvas textures, tiled floors that keep the texture
warp in check, and merging many parts into one draw call.
- Copy it next to three.js, point your meshes at `ps1()`, and your scene is
now 1997.
- **The scroll-on-rails pattern** is about 40 lines of `main.js`: turn scroll
position into a path parameter by interpolating between section anchors, then
let everything else read that one number. The framing shift away from text
panels is another 10 lines on top.
- **The organs** in [`prototype/organs.js`](prototype/organs.js) are
self-contained builders. Each one returns a `{ group, update(t, k) }` object
you can drop into any three.js scene, as long as `ps1.js` comes with it.
If you make something with them, we'd love to see it.
## Where things live
| File | Owns |
| --- | --- |
| `prototype/index.html` | The copy. Each `<section data-stop>` pins a camera stop. |
| `prototype/world.js` | The scene, the aperture, and `ROUTE`. |
| `prototype/organs.js` | The organ demakes and the twin's scaffolding. |
| `prototype/ps1.js` | The PS1 material, the framebuffer and dither, and geometry helpers. |
| `prototype/main.js` | The scroll timeline and the frame loop. |
| `prototype/vendor/` | three.js 0.186.1 (MIT). |
Run it locally by serving `prototype/` over HTTP, since ES modules won't load
from `file://`:
```bash
python -m http.server 8765 --directory prototype
```
The Yggdrasil deploy is documented in `gamecult-ops`, in
`runbooks/eureka-prototype-yggdrasil.md`.