guts/docs/MOLECULES.md
jing a99f733452 [lane A] MODELBEAST dresses the molecules: 5 matcaps, and the canal picks space-filling
The right axis wasn't "generate or don't" — it was WHICH HALF. Geometry stays
procedural because a molecule's shape is already known exactly. **Material is
exactly a generation problem**, and it's the whole difference between a textbook
diagram and a game object. So MODELBEAST made the materials.

5 greyscale matcaps, flux_local, 69 seconds, $0.00, 68 KB total:
  mol_glass (O,N) — the big win: oxygen is a red glass marble with internal glow
  mol_matte (C)   — graphite soot; carbon reads as the scaffold it is
  mol_chrome (Co) — B12's cobalt is now a chrome bearing in a cage
  mol_molten (P)  — ATP's phosphate tail is incandescent AND pulses (uTime, free)
  mol_pearl (H)   — satin white; hydrogens stop shouting

The trick is Lane D's own law applied to spheres: author the LUMINANCE, tint
in-shader. derive_maps already greyscales every matcap, so one glass ball serves
oxygen AND nitrogen at their own CPK hues — 5 balls dress the whole periodic
table we care about. They pack into one strip atlas indexed per-vertex by aMat,
so **a molecule is still exactly 1 draw call** however many materials it's made
of (7 molecules = 7 draws, unchanged). ?matcap=0 falls back to the built-in
fake-lit path: the assets-optional law holds.

SPACE-FILLING WINS FOR PICKUPS, and the canal decided it, not me. New
`repr: 'space-filling'` draws every atom at its real van der Waals radius with no
sticks. A/B'd at real pickup size against the real L2 wall, same camera:
ball-and-stick goes spindly and dissolves; the solid blob holds its silhouette —
and it's CHEAPER (21k vs 26k tris, no bond cylinders). Recommendation to B:
space-filling in flight, ball-stick for hero/UI/collect close-ups where the
chemistry is worth reading. Evidence: round2_molecule_materials.png (3-way).

Two defects found by rendering it, both mine, both fixed:
- Tint x luminance darkens TWICE: CPK carbon is 0.4 and a matte ball averages
  0.5, so soot x soot vanished — the first pass sank glucose, caffeine and the
  cobalt into the background. Floored the matcap at 0.22, the same floor the
  fallback's key light always had.
- The molten matcap was my own bad prompt: I asked for an "incandescent white hot
  CORE" and got exactly that — a black ball with a hot spot, so phosphorus lost
  its orange. Re-rolled for the whole sphere to glow (attempt 2 of the <=2
  PIPELINE allows). Lesson for the kit, next to the organ/tissue one: a matcap is
  a LUMINANCE LOOKUP, so a dark-dominant ball makes a dark-dominant object.

Also corrected the doc's own framing — v1 said "I'm authorised to burn GPU and
I'm not going to", which was the wrong axis, not just the wrong tone.

qa GREEN; 16/16 texture provenance verified (synced the FIXED batch json up
first this time, so the box couldn't clobber it on the way back).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 21:31:24 +10:00

13 KiB
Raw Permalink Blame History

MOLECULES — a proposal (Lane A, round 2)

Status: PROTOTYPE + argument. Nothing here is wired into boot. Pickups are Lane B's systems, their economy is Lane C's, object art is Lane D's — this document is a pitch to all three, plus a working renderer they can take or leave.

Fly it: web/dev/laneA_molecules.html · code: web/js/world/molecule.js · evidence: docs/shots/laneA/round2_molecule_pickups.png (the set + roles), round2_molecule_materials.png (flat vs matcap vs space-filling, in the real canal), round2_molecules_in_canal.png, round2_molecules_truescale.png


The pitch in one line

The pickups already in L2 are molecules — so draw them as molecules.

C authored nutrient, mucin, B12, antacid ammo before any of this existed. Those aren't game-flavoured names; they're the actual biochemistry of a digestive tract. Glucose, cobalamin and bicarbonate are real compounds with known shapes. We don't have to invent a pickup language — we have to stop hiding the one the fiction already handed us.

Why this is free sciency-ness, and why it isn't educational

The game does not explain anything and should not start. Nobody needs to know what ATP is. But a purine reads as chemistry to anyone alive, the way a circuit diagram reads as electronics — because it is the real notation, not an impression of one. The game gets to feel sciency by not faking it, which is cheaper than faking it and better.

Consider what's already true: an eosinophil is a real white blood cell. Candida is a real yeast. A bolus is a real mass of chewed food. The hiatus is a real anatomical choke point. GUTS is already a science game — C built it that way. It just doesn't look like one yet, because everything on screen is tinted tissue.

The one rule that makes it all work: CPK is the scanner

Everything the ship's scanner has identified is drawn in CPK colours. Everything it hasn't is monochrome tinted tissue.

CPK is the standard element palette — oxygen red, nitrogen blue, phosphorus orange, sulfur yellow, metals pink. Every chemistry textbook and protein viewer on earth uses it. Against six biomes of tinted tissue, a CPK molecule is the only saturated foreign colour on screen, so it reads as artificial, valuable and targetable at a glance — with no HUD marker (round2_molecules_in_canal.png is the proof: a glucose in the esophagus, unmissable).

That's ART_BIBLE's synthetic-scanner fiction paying rent: the ship identifies a compound and colours it in. → Lane E: this is a free HUD language. Accent a readout in an element's CPK colour and it belongs to that compound with no legend.

The division of labour: procedural geometry, generated materials

MODELBEAST makes the materials. Procedural makes the shapes. Both halves matter and they are not in competition — the first version of this doc framed it as "don't use the GPU", which was the wrong axis and is corrected below.

Geometry is not a generation problem, because a molecule's shape is already known exactly. Glucose is a hexagonal ring because it is a hexagonal ring. FLUX + TRELLIS would give a plausible blob, in 38 minutes, that a chemist clocks as wrong instantly and that can never be re-derived. Ball-and-stick from an atom list is exact, rebuilds in milliseconds, and is one draw call per molecule (measured: 7 molecules = 7 draws, 26.5k tris total; glucose alone is 3.7k tris / 1 draw).

Material is exactly a generation problem, and it's what separates a diagram from an object — see the next section.

What MODELBEAST did do: the materials (round 2, second pass)

Geometry is exact and free. Material is where the GPU earns its keep — and it's the whole difference between a textbook diagram and a game object. GUTS has no real-time lights by law, so a matcap (a lit-sphere image) is the only way to make something look made of anything.

Five greyscale matcaps, flux_local, 69 seconds, $0.00, 68 KB total:

matcap elements what it does
mol_glass O, N the big win. Oxygen becomes a deep red glass marble with internal glow.
mol_matte C graphite soot. Carbon is scaffold, and now it reads as scaffold.
mol_chrome Co, Fe, Na polished metal — B₁₂'s cobalt is a chrome bearing in a cage.
mol_molten P ATP's phosphate tail is incandescent, and pulses (uTime, free).
mol_pearl H soft satin white; hydrogens stop shouting.

The trick that makes it cheap is Lane D's own law, applied to spheres: author the luminance, tint in-shader. derive_maps greyscales every matcap already, so one glass ball serves oxygen and nitrogen at their own CPK hues. Five balls dress the whole periodic table we care about, and they pack into one strip atlas indexed per-vertex by aMat — so a molecule is still exactly one draw call no matter how many materials its atoms are made of. ?matcap=0 falls back to the built-in fake-lit path: the assets-optional law holds.

Two things that only showed up by rendering it, both fixed:

  • Tint × luminance darkens twice. CPK carbon is already 0.4 and a matte ball averages 0.5, so soot × soot vanished — the first pass sank glucose, caffeine and the cobalt into the background. Floored the matcap at 0.22, the same floor the fallback's key light has always had.
  • The molten matcap was my own bad prompt: I asked for an "incandescent white hot core" and got exactly that — a black ball with a hot spot, so the phosphorus lost its orange entirely. Re-rolled asking for the whole sphere to glow. Lesson for the kit, next to the organ/tissue one: a matcap is a luminance lookup, so a dark-dominant ball makes a dark-dominant object. Ask for bright, always.

What the canal decided: space-filling wins for pickups

buildMolecule(id, {repr}) now does 'ball-stick' (default) or 'space-filling' — every atom at its real van der Waals radius, no sticks, atoms merging into one solid lump. A/B'd at real pickup size against the real L2 wall, same camera (round2_molecule_materials.png):

Ball-and-stick goes spindly and starts dissolving. Space-filling holds its silhouette — and it is CHEAPER (21k vs 26k tris across the set: no bond cylinders). It's also more true, since that is how a molecule occupies space.

Recommendation to B: space-filling for anything in flight, ball-stick for hero, UI, the medal card and the collect close-up — where the chemistry is legible and worth reading. The obvious LOD (blob far, sticks near) is untested and I'm not claiming it.

The split, and it's a principle, not a preference:

kind how why
Small molecules — glucose, ATP, caffeine, bicarbonate, capsaicin, B12, ions procedural ball-and-stick exact geometry is known; generation can only degrade it
Proteins / enzymes — pepsin, trypsin, lipase, mucin MODELBEAST (flux → sf3d → trellis) real ones are 3000-atom blobs; nobody reads their structure. A blob is the honest render, and PIPELINE says blobby organics are TRELLIS's sweet spot
Cells / creatures — eosinophil, candida, bolus, ENDO-1 MODELBEAST (Lane D's round-2 headline, gated on concept sign-off) organic, no canonical geometry, exactly what it's for

So MODELBEAST still does the heavy lifting — on the things where invention is the right answer.

The library (built, rendering, in the sheet)

Every one of these is really in the human gut. That constraint does the design work: the pickup table is the biochemistry of digestion, so nothing has to be invented and the fiction is automatic.

molecule proposed role why it's the right object
Glucose C₆H₁₂O₆ nutrient / score Food. The reason the canal exists. Common, stacks.
ATP C₁₀H₁₆N₅O₁₃P₃ boost Literally the cell's energy currency. The orange triphosphate tail is the charge — a body spends ATP by snapping one off. A boost pickup that visibly carries three charges is a diagram of its own mechanic.
Bicarbonate HCO₃⁻ antacid ammo Already in L2. HCO₃⁻ + HCl → salt + H₂O + CO₂ is the real reaction that neutralises stomach acid — fire it into the acid sea and it genuinely fizzes.
Caffeine C₈H₁₀N₄O₂ overdrive Really absorbed through the gut wall. Everyone knows what it does to a body: throttle up, twitchier, wears off badly. Needs no tutorial.
Capsaicin C₁₈H₂₇NO₃ burn hazard Chilli. Long greasy tail + aromatic ring = a silhouette that reads wrong across a room, and it tumbles unlike any compact pickup. Free readability.
Vitamin B₁₂ C₆₃H₈₈CoN₁₄O₁₄P rare treasure C already authored B12 as a pickup. It's the most complex vitamin and the only one with a metal at its heart — a cobalt in a corrin cage. It renders as a jewel in a setting.
Water H₂O trickle / chaff Everywhere, worth a sliver. The size floor.

Size is a free rarity signal. buildMolecule(id, {unit}) keeps molecules at their TRUE relative sizes: water is a speck, B12 is a chandelier (round2_molecules_truescale.png). The player learns what's worth chasing before reading a single colour, and it costs nothing because it's just true. ({fit} normalises them all to one size instead, if a pickup must occupy a fixed box — B's call.)

Cheap next molecules, if this lands

  • Ions as basic ammo/energy: Na⁺, K⁺, Cl⁻, Ca²⁺ — single coloured spheres, ~30 tris, and they're the real electrolytes. Violet, green, purple: instant colour-coded ammo types.
  • Ethanol C₂H₅OH — a powerdown. Controls drift, aim lags. Funny, real, gut-absorbed.
  • Vitamin C C₆H₈O₆ — coat repair (it's the antioxidant). Pairs with B12 as a vitamin tier.
  • Mucin — the coat itself, and it's already a pickup. It's a glycoprotein → MODELBEAST blob, not ball-and-stick. Good first test of the split above.
  • HCl — the acid sea's own molecule. One green Cl, one white H. The sea could shed them.

Other ways to be sciency that cost ~nothing

  1. Show the real pH. L3's identity is "ambient pH drains the coat". Stomach pH really is ~1.53.5. A HUD readout ticking pH 1.8 as you descend is instantly sciency, is true, and is one number. → Lane E / C.
  2. Name the real reaction when it fires. Antacid hit → HCO₃⁻ + HCl → NaCl + H₂O + CO₂↑ flashed for half a second in the feed. Never explained. Reads as an instrument log.
  3. Let CO₂ be the fizz. The bicarbonate reaction really produces gas. Bubbles from a neutralised acid patch are the reaction being visible, not a particle effect.
  4. The enemies are already real — lean in. eosinophil_swarm is a real immune response to an invader. The player IS the invader. That's the whole game's joke and it's science.

What I'd need from each lane

  • → C: are these the roles you want? The economy is yours. If nutrient should be glucose and antacid bicarbonate, they're built. Tell me which molecules a level needs.
  • → B: buildMolecule(id, {fit|unit, detail, material}) returns one THREE.Mesh, one draw, .userData carries name/formula/role. Share ONE material across all of them (colour is per-vertex, so they still batch). Use detail: 1 for live pickups, 2 for hero/close.
  • → D: this doesn't touch your pack and doesn't want your GPU time. It asks for the split above — proteins and cells are yours, small molecules are arithmetic. Your round-2 hero list is unaffected.
  • → E: CPK as the scanner's identification language is a free HUD palette. ELEMENTS in molecule.js exports the hexes.
  • → F: world/molecule.js sits in my dir because it's my dir, not because molecules are "world". If this is adopted it probably wants a shared web/js/fx/ — your call.

Honest limitations

  • Geometry is idealised, not crystallographic: correct connectivity, ring sizes and bond orders, believable angles, authored mostly flat because a flat ring reads instantly and spins well. Real molecules pucker (glucose is a chair, not a hexagon). This is a game, not PyMOL — but nobody should mistake this table for a structure database later.
  • The B12 is a simplified corrin core — the real thing has a nucleotide tail and far more side chains. It reads as "jewel in a cage", which is the job.
  • Not performance-tested at pickup density. 7 on screen is 7 draws / 26k tris (13 draws / 87k with the canal behind them). Fifty would want instancing or a merged batch, and neither exists yet.
  • The matcap atlas is built at runtime from a canvas. Fine, but it means a one-frame hitch on first build and it bypasses assets.matcap() (it reads assets.get('matcaps', …).url — the documented floor — and loads the images itself, because an atlas needs pixels and matcap() hands back a THREE.Texture that may not have decoded yet). If this is adopted, baking the atlas offline in derive_maps.py would be tidier and D may prefer it.
  • repr: 'space-filling' hides the bonds by definition, so a molecule's chemistry stops being readable — that's the trade for silhouette, and it's why ball-stick stays the default for anything the player is meant to look AT rather than fly at.