Roster round-2, batch 2 — three new archetypes, mostly reusing existing behaviour branches:
- virion (norovirus): a tiny fast swarmer, its own pool of 40 so a cloud reads as a swarm.
Shares the seeker branch (chase + dissolve on contact). The arithmetic threat. -> L5.
- driller (H. pylori): a TANKY corkscrewer (hp 50). Seeker chase + a rotating perpendicular
drift (the helix), and it does NOT dissolve on contact — it grinds you and keeps drilling,
so you must out-damage it. A new behaviour branch. -> L3 stomach; previewed in L2 at s2240.
- beacon (Faecalibacterium): the reward-state commensal. Shares the commensal branch, heals
AND gives the biggest standing (25) with no coat cost. A bright cyan octahedral gem, the
special one of the family. -> L5; previewed in the L2 breather at s1580.
Verified in-engine: driller corkscrews + survives contact; virion is tiny + dissolves; beacon
heals coat and spikes standing to 50% in two tends. Three clean distinct silhouettes (gem /
cone / dot-swarm).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first foe with an ATTACH state machine, and the first that gives boost a defensive job.
Giardia chases like a seeker, CLAMPS its ventral suction disc onto your hull, and drains coat
while it rides — until a boost's i-frames throw it (or it lets go after attachMax, then can't
re-grab for reattachCd). The counterplay is timing a boost, not out-running it.
- enemies.js: `latcher` archetype — a two-state (chase / attached) branch. Attached, it rides
player.pos + a spin offset and drains `drain`/tick; ps.iframeT > 0 (boost) detaches and flings
it clear. Amber tetrahedron (the trophozoite), so a clinging one reads on the hull.
- levels/enemies.js: ARCHETYPES += latcher; catalogue `giardia_latch` (biome small_intestine).
- L2: one Giardia previewed on the open thoracic run (s1940) — it belongs to L4's villi maze,
but the grab works in a flow tube, so it teaches the boost-dodge verb now.
Verified: it chased + clamped, drained coat 100->84 while attached, and a simulated boost
(iframeT) shook it off.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A foe whose corpse keeps hurting — the definitive colon enemy. C. diff drifts with a corrosive
aura like any floater, but on death it leaves a SPORE_CLOUD: a static acid-green zone that
damages anything in it for ~5s, then disperses. Killing it costs you the ground it died on
(shoot the cloud to clear it, or fly around).
- enemies.js: two archetypes. `cdiff` (amber octahedron, shares the floater drift+aura branch)
drops a `spore_cloud` in kill(), placed at the death spot. `spore_cloud` (acid-green per the
readability law, foe:false so the phage ignores it and clearing it never scores) is static,
damages on contact, and counts down a `life`. Entities gained a `life` field (only the cloud
uses it).
- levels/enemies.js: ARCHETYPES += cdiff; catalogue `cdiff_bloom` (biome large_intestine —
registered for L5's encounter pass, not shoehorned into the esophagus).
Verified: killing a cdiff dropped a cloud at its death spot; sitting in it dropped coat 100->89;
the cloud expired after its life. Amber octahedron vs acid-green blob — clean read.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cleverest node in the reputation loop — a commensal that eats your mucus. Brushing it
COSTS coat but fills BIOME STANDING fast (gain 12 vs flora's 5): the "spend coat for a quicker
phage ally" trade against flora's safe heal-and-slow.
- enemies.js: flora's branch generalised to a shared COMMENSAL branch, sign-flipped by data
(cfg.coat gifts, cfg.coatCost nibbles); flora:tended now carries `gain`. New `mucus_grazer`
archetype — cyan (still flora, readability law), but a dodecahedron amoeba-blob so the coat
cost reads as a different bug, not a betrayal by the healing rod.
- combat/index.js: standing gain comes from the event's `gain`.
- levels: ARCHETYPES += mucus_grazer; catalogue `akkermansia`; L2 teaches it at s210, right
after the flora reef so the same-colour / opposite-trade contrast lands.
Verified: brushing it dropped coat 100->88 while standing hit 36% in 3 tends (4x flora's rate);
distinct blob vs the flora capsule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first ALLY, and the reputation loop that earns it — "don't shoot the biome, it helps you"
(V2_IDEAS) made mechanical.
- combat/enemies.js + balance.js: the `phage` archetype. A friendly seeker that hunts the
nearest FOE (not the player) and rams it — a bacteriophage bursts its host after `bursts`
hits. Fast (26 > every foe) so it catches things, fragile (hp 8) so it is spent, not a wall.
Entities now carry a `foe` flag (foes true; flora + phage false); kill() generalised so ANY
ally scores nothing and never combos. Fallback silhouette is a bare icosahedron = the phage's
real icosahedral capsid. Teal (EMISSIVE.ally), distinct from cyan "don't shoot" flora.
- combat/index.js: BIOME STANDING — one run-scoped float. flora:tended raises it, flora:harmed
drops it 25; at the symbiotic threshold the biome BUDS a phage near you (capped 3, 3s cooldown),
spending standing. Emits `standing {value}` for a future Lane E meter.
- levels/enemies.js: ARCHETYPES += phage; catalogue `phage`.
Verified deterministically in-engine: tending flora budded a phage, which hunted a spore_pod foe
(30hp) and rammed it dead; three-colour readability holds (amber foe / teal ally / cyan friend).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The round-2 microbe pass, vertical slice. Cross-lane (integrator call): the point was one
thread proven end to end — art pipeline in, friend and foe out.
- core/assets.js (D): the GLB loader, finally wired. GLTFLoader was vendored but never
imported and the manifest had 0 models, so enemies.js's `glb?.geometry` hook was dead code.
Now every manifest model preloads (AWAITED — pools set geometry at construction, a late load
can't retrofit an InstancedMesh) into ONE BufferGeometry normalized to a unit bounding
sphere; get('models',n).geometry lights up the hook. Optional-asset law intact: any failure
-> no geometry -> procedural fallback.
- combat/enemies.js + balance.js (B): two new archetypes.
flora — the FIRST FRIEND. Cyan (ART_BIBLE: flora reads friendly). Drifts like a
floater but its aura HEALS (sheds coat), never harms. Shootable — and shooting
it is the reputation trap: kill() gives no score, no combo, emits flora:harmed.
Verified: the aura fires player.refill({coat}); a shot flora scores 0.
spore_pod — a foe yeast cluster: the floater's drift+aura, but its OWN pool so its blobby
GLB will not reskin the food-debris floater.
Pool geometry now scales a GLB by the archetype radius (GLBs ship unit-normalized).
- levels/enemies.js (C): ARCHETYPES += flora, spore_pod; catalogue entries lacto_drifter
(Lactobacillus) + yeast_pod (Candida). L2 gets a light teach beat in the calm opening — a
friendly reef at s180, one yeast at s300, both off the racing line.
Ships playable as glowing primitives (a capsule + an icosahedron), exactly like the rest of
the round-1 roster; the Trellis/Hunyuan meshes drop in via the manifest with no code change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Landed before the cut: surf as a speed-lock onto world.crestSpeed(s) with surf.authority
(ruling #1) — riding beats throttle and holding a crest is throttle discipline; tuning.js
header corrected to the real wallRho frame (C's flag); enemies.js reads rho as a FRACTION
of safe radius (C's placement law); balance.js hazard + pickup constants; NEW hazards.js
(reflux_surge / aortic_squeeze / ring_gate, self-scheduling telegraphs, reset(fromS) built
for respawn) and NEW pickups.js (all five kinds, shape-coded).
Cut off before: wiring — nothing imports hazards/pickups yet; the fiction-id -> archetype
resolve (round-2 task #1) does NOT exist despite the enemies.js comment saying index.js
does it; player.kill/shove/refill are called but were never added; checkpoint/respawn and
gate -> level:complete not started; NOTES unwritten. F lands the glue next commit.
Committed by F to protect the shared tree.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flight (js/flight/): tube-mode controller in spline space (s,x,y) — flow-locked
forward motion, throttle as a spring-back lean, boost + i-frames, banking chase
cam on the parallel-transport frame, arcade wall response (shove + graze damage,
never a hard stop). Twin-stick input: WASD/left-stick moves the ship in the disc,
mouse/right-stick aims, Shift/Ctrl is throttle. Gamepad supported.
Combat (js/combat/): lysozyme cannon (pooled, instanced, heat-limited with
hysteresis lockout) + antacid torpedo emitting level:neutralize. Enemy framework
with floater/seeker/turret and turn-rate-limited homing darts, spawned from C's
level:event. Coat/hull model and the full bus surface E builds against.
Measured (deterministic stepper): flow-lock exact (3s at flow 14 -> s=44.0);
boost peak 30.8 u/s; heat 4s fire -> 2s lockout; wall slam 13.3 coat at 11.3 u/s
with forward speed untouched; 10 combat draws at 55 live enemies (budget <=80);
0.10 ms/frame CPU; 0 leaks over 20 create/dispose cycles. fps NOT claimed — rAF
does not run in the automated pane. Evidence: docs/shots/laneB/.
Three findings escalated in LANE_B_NOTES:
- qa.sh gate #1 is a no-op: node --check silently exits 0 on ESM, so the syntax
gate has never checked anything. I shipped a real SyntaxError past a GREEN qa.
Fix + verification handed to F.
- Surf is structurally broken: the peristalsis wave (13.64 u/s) is slower than
the player (19.6 u/s), so level 2's signature mechanic loses to mashing
throttle. Not tunable from this lane; escalated to A/F with options.
- Custom ShaderMaterials need #include <colorspace_fragment>, else ART_BIBLE's
hostile amber reaches the display as rgb(255,26,6). Fixed here; stub/walls
inherit it.
js/flight/dev.html is a dev harness (boot.js has no player wiring yet); it
retires once F pastes the snippet in LANE_B_NOTES.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>