[lane B+C] L1 Oral Cavity: the tutorial, and the Mast Cell — the boss you win by not shooting

L1 has been a 2-event skeleton since round 1, waiting (in its own status field) on "Lane B's
arena-mode controller". That exists now, so C's round2_plan is built as written: molar
crush-cycles, the saliva tide, amylase droplets, the three samples exactly where C put them
(behind the molars / under the tongue / a tonsillar crypt), and the epiglottis exam. 24 events.

The teaching order is the level: move (orbs, no current) -> LOOK (the arena opens and you can
stop, which no other level allows) -> shoot (one droplet, then two) -> coat (the molar ring
grazes you, mucin is right there) -> RESTRAINT -> flow returns (the tide, the funnel) -> the
exam. Every verb alone, in the calmest room in the game, before anything is asked of it. Two
hazards are deliberately re-used rather than invented: the molar crush IS a ring_gate and the
saliva tide IS a non-lethal surge, so L2's gates and its reflux finale become callbacks instead
of new ideas.

THE MAST CELL (LANE_C_NOTES §Boss specs 5) sits at the exact midpoint. A sentinel immune cell:
cyan, no attack, no chase, inert aura (auraDps 0 — it shares the floater's drift branch and its
aura does literally nothing). Fly past and the encounter just ends. Shoot it and it degranulates
— droplets close in from the walls (which is how "the cavity swells shut" is expressed, because
a runtime tube radius is not in Lane A's contract), the coat bleeds, and past half health the
airway closes on a 25s timer. You always get through. The only question is what you get through.

It needed a new boss `kind: 'sentinel'` with its own update path, because forcing a thing with
no rings and no windows through the phase machine would have been worse than a branch. Damage is
the failure state, so every number describes a consequence rather than a fight.

Verified, all three player choices: SPARE -> "spared", coat untouched at 100, karma +25, score 0.
SHOOT -> "degranulated", coat 100->56. KILL -> "anaphylaxis-survived", coat 100->6. Score is 0 in
every case: shooting it buys literally nothing, so no medal can ever reward the mistake.

Two bugs the testing paid for: `def.phases[0]` crashed on a boss that has no phases, and the
first degranulation drain (5/s) was UNDER the player's 8/s coat regen — measured coat going
80 -> 100 during a histamine cascade, i.e. the punishment was healing you. Now 14 and 22, which
are net -6/s and -14/s against regen.

L1 is no longer a skeleton: its checkpoint-gap and zero-samples warnings are gone, and the
campaign now opens on a real tutorial instead of an empty mouth with a gate at the end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-26 00:13:52 +10:00
parent d39c0b9358
commit f9aeaf259f
4 changed files with 150 additions and 8 deletions

View File

@ -121,6 +121,14 @@ export const BALANCE = {
// reap timing, and a boss that silently spawns no core is the worst bug in the file.
mucosal_node: { hp: 150, radius: 2.6, score: 400, pool: 12 },
// mast_cell — L1's sentinel (LANE_C_NOTES §Boss specs 5). A patrolling immune cell with NO
// attack: auraDps 0 means it shares the floater's drift branch and its aura does nothing at
// all. hp 400 is not a health bar, it is a THRESHOLD — high enough that killing it takes
// deliberate sustained fire, so the cascade is never something a player did by accident with
// one stray pellet. score 0 and foe:false: there is no reward here, in any sense.
mast_cell: { hp: 400, radius: 3.2, score: 0, drift: 1.1, bob: 0.3,
auraRadius: 4.0, auraDps: 0, auraTick: 0.5, pool: 2 },
// beacon (Faecalibacterium) — the reward-state commensal. The most anti-inflammatory bug in
// you; a screen of these IS a healthy gut. Shares the commensal branch: heals AND gives the
// biggest standing (gain 25) with no coat cost. Rare (pool 10) — the pure payoff node.

View File

@ -49,6 +49,28 @@ const BOSSES = {
],
},
// LANE_C_NOTES §5. The restraint boss, and the one that is not shaped like a boss at all —
// hence `kind: 'sentinel'` and its own update path. There is no ring, no window and no hp bar
// you are meant to empty: there is a cell on patrol, and a question. Damage is the FAILURE
// state, so every number here describes a consequence rather than a fight.
mast_cell: {
kind: 'sentinel',
telegraph: 0,
node: 'mast_cell',
hp: 400, // the threshold the entity spawns with (balance.js agrees)
passS: 70, // travel this far past it and the encounter resolves, either way
// P2 Degranulation — triggered by ANY damage. Histamine: the cavity fills from the walls
// inward (droplets pinned at high rho ARE the swelling, expressed in entities) and the coat
// drain doubles. Note it never chases and never shoots: the level got worse, not the cell.
// drain is NET-of-regen or it is nothing: the player regenerates coat at 8/s (tuning.js
// coat.regen) and drain() does not reset that timer, so the first cut at 5/s meant getting
// histamine actually HEALED you (measured: coat 80 -> 100 during a degranulation). 14 leaves
// a real -6/s bleed; the cascade has to be felt or the lesson has no teeth.
degran: { every: 1.7, cap: 10, rho: 0.9, drain: 14 },
// P3 Anaphylaxis — past half. The airway is closing, and now there is a clock.
ana: { at: 0.5, doom: 25, every: 0.9, cap: 18, drain: 22 }, // -14/s net: the airway closing
},
// LANE_C_NOTES §4. The reputation boss. `standing` gates the whole encounter on entry, and
// keeps mattering: every commensal you kill in the lair re-armours a plate (see onHarm).
appendix_sovereign: {
@ -126,10 +148,22 @@ export function createBoss({ bus, rng, player, enemies, flags = {}, getKarma = n
const def = BOSSES[ev.id] ?? BOSSES.pyloric_guardian;
const f = {
id: ev.id ?? 'pyloric_guardian', def, s: ev.s ?? 0,
nodes: [], vents: [], phase: def.phases[0], phaseIdx: 0,
// `phases` is absent on a sentinel (it has no rings and no windows) — optional all the
// way down rather than a fake one-entry table, so the sentinel path stays honestly separate.
nodes: [], vents: [], phase: def.phases?.[0] ?? null, phaseIdx: 0,
open: false, t: 0, bloomT: 0, doomT: 0, warned: false, done: false,
};
// The sentinel spawns one cell and no vents, because it is not attacking anybody.
if (def.kind === 'sentinel') {
f.tier = 0; f.spawnT = 0; f.doomT = 0;
f.cell = enemies.spawn(def.node, { s: f.s, rho: 0.25 });
if (f.cell) f.cell.hp = def.hp;
active = f;
bus.emit('boss:start', { id: f.id, s: f.s, phases: 3, tier: 'patrol' });
return f;
}
// LANE_C_NOTES §4: the Sovereign is the one boss whose existence is decided before you
// arrive. KARMA (the unspendable conduct ledger, not the spendable standing meter) is read
// ONCE, on entry — a verdict on how you played the campaign, not on how recently you cashed
@ -166,12 +200,70 @@ export function createBoss({ bus, rng, player, enemies, flags = {}, getKarma = n
for (const e of [...f.nodes, ...f.vents]) if (e.alive) e.alive = false;
active = null;
bus.emit('boss:end', { id: f.id, outcome });
bus.emit('audio:cue', { name: outcome === 'win' ? 'gate_pass' : 'death' });
// `spared` and `communion` are WINS that involve no killing, and the instrument has to agree
// with the design or it teaches the opposite lesson: a triumphant cue for walking away is
// most of how L1 tells the player that walking away was the answer.
const good = outcome === 'win' || outcome === 'spared' || outcome === 'communion';
bus.emit('audio:cue', { name: good ? 'gate_pass' : 'death' });
}
// The sentinel: L1's Mast Cell. Its entire state is "has the player hurt it yet", and the
// player's own restraint is the only input. Nothing here attacks — the escalation is the LEVEL
// getting worse, which is the point C's spec makes: the punishment is not damage, it is
// consequence, and it is authored by the person holding the trigger.
function updateSentinel(f, dt) {
const e = f.cell;
const ps = player?.state;
if (!e || !ps) { finish(f, 'lost'); return; }
const frac = e.alive ? e.hp / f.def.hp : 0; // killed outright = maximum cascade
if (frac < 0.999 && f.tier === 0) {
f.tier = 1; // DEGRANULATION — the first hit does this
bus.emit('boss:phase', { id: f.id, phase: 2, reason: 'degranulation' });
bus.emit('audio:cue', { name: 'overheat' });
}
if (f.tier === 1 && frac <= f.def.ana.at) {
f.tier = 2; // ANAPHYLAXIS — and now a clock
f.doomT = f.def.ana.doom;
bus.emit('boss:phase', { id: f.id, phase: 3, reason: 'anaphylaxis' });
bus.emit('audio:cue', { name: 'death' });
}
if (f.tier > 0) {
const cfg = f.tier === 2 ? f.def.ana : f.def.degran;
player.drain?.(cfg.drain * dt); // histamine: the coat goes, continuously
f.spawnT -= dt;
if (f.spawnT <= 0) {
f.spawnT = cfg.every;
const crowd = enemies.live.filter((x) => x.alive && x.type === 'floater').length;
// Pinned near the wall and closing in: this IS "the cavity swells shut", built from
// entities because a runtime tube radius is not in Lane A's contract. Noted in NOTES.
if (crowd < cfg.cap) enemies.spawn('floater', { s: ps.s + 20 + rand() * 40, rho: f.def.degran.rho });
}
if (f.doomT > 0) {
f.doomT -= dt;
if (f.doomT <= 0) { player.kill?.('anaphylaxis'); finish(f, 'anaphylaxis'); return; }
}
}
// Resolution: you always leave. The only question is what state you leave in.
if (ps.s > f.s + f.def.passS) {
if (f.tier === 0) {
// SPARED. The best outcome in the encounter is the one where nothing happened, and the
// game has to say so out loud or the lesson does not land.
player.refill?.({ coat: 40 });
bus.emit('flora:tended', { s: f.s, gain: 25 }); // it IS the biome; conduct is credited
finish(f, 'spared');
} else {
finish(f, f.tier === 2 ? 'anaphylaxis-survived' : 'degranulated');
}
}
}
function update(dt) {
const f = active;
if (!f || f.done) return;
if (f.def.kind === 'sentinel') { updateSentinel(f, dt); return; }
const live = f.nodes.filter((e) => e.alive);
@ -258,7 +350,7 @@ export function createBoss({ bus, rng, player, enemies, flags = {}, getKarma = n
return {
update,
get active() { return active; },
get phase() { return active?.phase.id ?? 0; },
get phase() { return active?.phase?.id ?? active?.tier ?? 0; },
get open() { return !!active?.open; },
reset() { if (active) finish(active, 'reset'); },
dispose() { for (const off of offs) off(); if (active) finish(active, 'dispose'); },

View File

@ -148,6 +148,16 @@ const ARCHETYPES = {
geo: () => new THREE.DodecahedronGeometry(B.enemies.mucosal_node.radius, 0),
color: EMISSIVE.hostile,
},
// mast_cell — L1's sentinel. CYAN, and the colour is the whole encounter: the readability law
// says cyan is not your enemy, and the level is watching whether the player believes it. A big
// soft icosphere so it reads as a cell full of granules rather than a target. foe:false, so
// killing it scores nothing — the only thing shooting it buys you is the cascade in boss.js.
mast_cell: {
cfg: B.enemies.mast_cell,
geo: () => new THREE.IcosahedronGeometry(B.enemies.mast_cell.radius, 2),
color: EMISSIVE.neutral,
foe: false,
},
// beacon (Faecalibacterium) — the reward commensal. Cyan (flora family), a bright octahedral
// gem so it reads as the special one; shares the commensal branch (heal + big standing).
beacon: {
@ -334,7 +344,9 @@ export function createEnemies({ scene, world, bus, rng, assets = null }) {
e.auraT = cfg.auraTick;
}
}
} else if (e.type === 'floater' || e.type === 'spore_pod' || e.type === 'cdiff') {
// mast_cell rides this branch too: it drifts a patrol and its aura is INERT (auraDps 0),
// which is the mechanical statement that it is not attacking you and never was.
} else if (e.type === 'floater' || e.type === 'spore_pod' || e.type === 'cdiff' || e.type === 'mast_cell') {
// drifts and bobs; taxes the lane it occupies rather than chasing. spore_pod (yeast) and
// cdiff (C. difficile) share this exactly — floaters with their own pool/mesh. cdiff's
// twist is only at death (kill() drops a spore_cloud), never in how it moves.

View File

@ -4,16 +4,19 @@
"name": "Oral Cavity",
"tagline": "Learn to swim",
"seed": 20260701,
"par": { "time": 300, "score": 6000, "samples": 3 },
"par": { "time": 300, "score": 2500, "samples": 3 },
"next": "L2_esophagus",
"design": {
"owner": "Lane C",
"status": "SKELETON (round 1) - shape only: biomes, lengths, arenas, gate. Encounters, pickups, samples and tutorial beats are round 2+, after Lane B's arena-mode controller exists. Do not read the (near-empty) events list as a design.",
"identity": "The tutorial, and the only level that is mostly arena. Teaches move / shoot / coat in safety, then examines all three at the epiglottis.",
"status": "AUTHORED (round 3). The skeleton waited on 'Lane B's arena-mode controller' and that now exists, so the round2_plan below is built: molar crush-cycles, saliva tide, amylase droplets, the three samples where C put them, and the epiglottis exam.",
"identity": "The tutorial, and the only level that is mostly arena. Teaches move / look / shoot / coat in safety - and then, at its centre, teaches the thing the whole game is about, which is that not everything in here is your enemy.",
"anatomy": "Vestibule (outside the teeth) -> oral cavity proper (the arena, ringed by molars) -> oropharynx, narrowing to the epiglottis gate.",
"biome_note": "biome = tissue/look family (Lane A's registry), segments[].name = the anatomy. There is no 'pharynx' biome and there should not be: the oropharynx is deliberately given the ESOPHAGUS palette so the tube turns teal as you approach the epiglottis. The colour shift is the wayfinding - it tells you where you are going before the gate does.",
"scale": "Real oral cavity is ~8cm across; arena radius 90 units = 18cm diameter. Dilated ~2x - much less than L2's 14x, because arenas need room to fight in and the mouth is already a room.",
"round2_plan": "Molar crush-cycles as timed hazards on the arena rim, saliva tides as a periodic current that sweeps the arena, amylase droplets as the tutorial floater. The epiglottis gate is a timing exam: dive on the swallow. 3 samples: one behind the molars, one in a tonsillar crypt, one under the tongue."
"teaching_order": "move (orbs, no current) -> LOOK (the arena opens, and in 6DOF you can stop, which no other level lets you do) -> shoot (one droplet, then two) -> coat (the molar ring grazes you, mucin is right there) -> RESTRAINT (the mast cell) -> flow returns (the tide, then the funnel) -> the exam (the epiglottis). Every verb is taught alone, in the calmest room in the game, before anything is asked of it.",
"why_the_mast_cell_is_here": "A tutorial teaches verbs; this one also has to teach the THESIS - the body is weather, and the immune system is not evil, it just cannot tell what you are. The Mast Cell is the only encounter in the game you win by holstering the gun, and it is placed at the exact midpoint of the tutorial so the lesson arrives before L2 shows the player their first cyan flora colony. A player who shoots it does not fail: they get the cascade, they get through anyway, and they have learned it the way that sticks. Spec: LANE_C_NOTES §Boss specs 5.",
"checkpoint_density": "Nine checkpoints in 720 units, which is the densest in the game and looks absurd next to L2's ten in 3600. It is not: flow here is 2 u/s (C's 'the only place where nothing is pushing them'), so the 30s death-cost law works out to ~69 units per checkpoint. A slow room is a forgiving room and this is the tutorial - the law and the level agree for once.",
"par_rationale": "300s is the honest traversal at flow 2. par.score 2500 is sized to the pacifist route: 3 samples (1500) + the orb lines + the droplets that are actually meant to be shot. Killing the mast cell scores NOTHING, so the score medal can never reward the mistake."
},
"segments": [
{
@ -49,6 +52,33 @@
],
"events": [
{ "s": 20, "type": "checkpoint", "name": "Injection Point" },
{ "s": 40, "type": "pickup", "kind": "nutrient_orb", "count": 4, "spread": 55, "note": "TEACH MOVE. The first thing in the game is a line of orbs in still water with nothing to hurt you. It teaches the racing line before it scores anything - the opening contract every level honours, but here it is the whole lesson." },
{ "s": 85, "type": "checkpoint", "name": "Vestibular Fold" },
{ "s": 110, "type": "spawn", "enemy": "amylase_droplet", "count": 1, "note": "TEACH the obstacle. One droplet, drifting, in a 14-unit tube at 2 u/s. It has a corrosive aura and the player has all the time in the world to notice that steering around it costs nothing." },
{ "s": 150, "type": "checkpoint", "name": "Behind the Teeth" },
{ "s": 170, "type": "pickup", "kind": "biopsy_sample", "count": 1, "theta": 0.4, "rho": 0.92, "note": "SAMPLE 1/3 - behind the molars, where C put it. Deliberately the easiest collectible in the game: wall-pinned in still water with nothing chasing, so the tutorial can teach 'these exist and they sit off the racing line' without also charging for it." },
{ "s": 200, "type": "spawn", "enemy": "amylase_droplet", "count": 2, "spread": 45, "note": "TEACH SHOOT. Two of them blocking a comfortable line - the first thing in GUTS the player is actually invited to destroy. That matters, because 120 units later the game offers them something they must not." },
{ "s": 215, "type": "checkpoint", "name": "The Cavity" },
{ "s": 250, "type": "hazard", "kind": "ring_gate", "period": 5.0, "open": 3.5, "warn": 3.0, "note": "TEACH the molar crush-cycle. C's round2_plan asks for crush-cycles on the arena rim; mechanically a periodic ring seal IS a bite, and it is a verb the campaign already owns - so L1 teaches it and L2's gates at s2100/s2800 become a callback rather than a new idea. 70% open with a 3s telegraph at 2 u/s: you clear it without thinking, which is exactly why it belongs here." },
{ "s": 280, "type": "checkpoint", "name": "Molar Ring" },
{ "s": 300, "type": "pickup", "kind": "mucin_glob", "count": 1, "note": "TEACH COAT, immediately after the first thing that can graze you. The economy's law in miniature: the game pays you right after it charges you, and the player learns what the left-hand bar is for by watching it refill." },
{ "s": 320, "type": "boss", "id": "mast_cell", "note": "THE THESIS, at the exact midpoint of the tutorial. A sentinel immune cell on patrol: cyan, no attack, no chase, inert aura. Fly past and the encounter simply ends and the biome thanks you. Shoot it and it degranulates - histamine floods the cavity, droplets close in from the walls, the coat drains twice as fast, and past half health the airway starts closing on a 25s timer. You still get through. You just get through a worse mouth, and you made it. Spec: LANE_C_NOTES §Boss specs 5." },
{ "s": 345, "type": "checkpoint", "name": "Tongue Base" },
{ "s": 370, "type": "pickup", "kind": "nutrient_orb", "count": 3, "spread": 45 },
{ "s": 410, "type": "checkpoint", "name": "Sublingual" },
{ "s": 430, "type": "pickup", "kind": "biopsy_sample", "count": 1, "theta": 4.71, "rho": 0.85, "note": "SAMPLE 2/3 - under the tongue, where C put it. Costs a detour to the floor of the cavity while the arena's 6DOF is still novel: the first collectible that asks the player to use the freedom they were just handed." },
{ "s": 450, "type": "spawn", "enemy": "amylase_droplet", "count": 3, "spread": 65, "note": "TEST the droplet: three at once, in the open. Everything taught so far, with room to fail safely." },
{ "s": 475, "type": "checkpoint", "name": "Faucial Arch" },
{ "s": 500, "type": "hazard", "kind": "reflux_surge", "speed": 5, "from": -30, "span": 140, "warn": 3.0, "lethal": false, "note": "THE SALIVA TIDE (C's round2_plan). A slow harmless wash sweeping forward at 5 u/s against a 2 u/s current - it will catch a dawdling player and it cannot kill them. This is the surge VERB in its safest possible form, 1200 units before L2's teaching burp and 2500 before L2's lethal finale. By the time an acid wall is genuinely chasing them, the player has met the shape of it twice." },
{ "s": 540, "type": "checkpoint", "name": "Oropharynx" },
{ "s": 560, "type": "pickup", "kind": "biopsy_sample", "count": 1, "theta": 2.36, "rho": 0.9, "note": "SAMPLE 3/3 - a tonsillar crypt, where C put it. In the funnel, where the current has started to build: the last sample is the first one that must be taken at speed, which is the shape of every sample from L2 onward." },
{ "s": 600, "type": "spawn", "enemy": "amylase_droplet", "count": 2, "spread": 40, "note": "Traffic in the funnel - the first time the player meets a known enemy while the flow is doing something to them." },
{ "s": 640, "type": "pickup", "kind": "mucin_glob", "count": 1, "note": "Last top-up before the exam. If the mast cell went badly, this is the difference." },
{ "s": 700, "type": "gate", "id": "epiglottis", "to": "L2_esophagus", "note": "The exam: dive through on the swallow. Timing gate, not a boss." }
]
}