# Page 58 · KIT API DIGEST (carried over from the old brief, 24 Oct). Each kit file's header comment is the full API.

## KIT ROUND: new shared tool sets (the user's picks, 23 Oct ~20:55)
The user picked these new tool sets. Four new Mac kit builders make them, each in its own shared file. KILLPAGES-A adds all six files to `K58.SHARED`; a missing file is skipped quietly.

| file | owner | what |
|---|---|---|
| `58k_anatomy.js` | KIT-BODY | ORGANS + ANATOMY: ribcage that cracks open, a beating heart, lungs, brain, guts rope, spine discs, drawn inside an opened torso / skull; the ANATOMY PEEL (skin, then muscle, then bone, limb by limb) |
| `58k_matter.js` | KIT-BODY | NEW DEATH MATERIALS: acid melt, inflate + pop, glass / porcelain shatter, pixel-glitch dissolve, burst into gold coins, paper tear, crush into a cube |
| `58k_destruct.js` | KIT-WORLD | DESTRUCTIBLE SET KIT: planks that snap, crates, exploding barrels, glass panes, signs, collapsing platforms / walls / balconies, real debris |
| `58k_worlds.js` | KIT-WORLD | POCKET-WORLD LIBRARY for the teleport kills: hell, space, underwater, colosseum, white void, ice cave, neon city, plus promoted builder worlds (subway car, disco, funfair) |
| `58k_replay.js` | KIT-REPLAY | INSTANT REPLAY + REWIND: time visibly runs backwards (VHS), then the kill replays from 2-3 other 2D framings with a REPLAY bug |
| `58k_sound.js` + `sfx/` | KIT-SOUND | REAL SOUND, synced to the film (play / pause / scrub / SLOW): automatic sounds on the existing tools, plus `s.snd()` cues for bespoke ones |

Every builder: once a kit's header is posted, use it in the kills still to build and upgrade the finished ones where it makes them better. Sound reaches every kill automatically through the auto-hooks; add bespoke `s.snd` cues as you go.

## KIT APIs POSTED (read each file's header comment for the full API)
- `58k_anatomy.js` (KIT-BODY, window.K58A), 21:25. Calls are stubs until each tool lands; write against them now.
  - Calls: s.organs, s.openChest, s.ribsCrack, s.heartBeat, s.heartOut -> h (squeeze / drop / throw / shot / stop), s.heartShot, s.lungs (breathe / gasp / collapse / pop), s.brainSplat, s.skullOpen, s.gutsSpill -> g, s.spinePull -> sp, s.spineSnap, s.peel, s.peelAll.
  - Automatic, no call needed: insides at waist cuts, slice and halve ends, x-rays, F's torso faces and holeThrough rims.
- `58k_matter.js` (KIT-BODY, window.K58M), 21:25: s.melt, s.inflatePop, s.shatter({kind: glass|porcelain}), s.glitch, s.coins, s.paperTear, s.cube, all as (b, t, o). Each returns m {t0, t1, at()}. Lit to read on dark realms.

## def.lead + KILL CAM TRIGGER API POSTED (KILLPAGES-A, 21:40). Full text: _tools/58k_API.md section 5. The format is final; the shell implementation lands within the hour.
- `lead: { dur (1.2-4 scene s, default 2.4), style: 'advance'|'retreat'|'trade'|'chase'|'brawl', a: {from|dx, jump}, v: {from|dx, weapon, fights: 'shoot'|'punch'|'dodge'|'run'|'none', jump}, kill: 'shot'|'burst'|'punch'|'kick'|'swing'|'cast', hp, arena (the REAL arena, for realm kills), cam, trig: 0.85, exit: 2.2, script(s, A, V, T0) {…} }`
  - script = your own lead-in at NEGATIVE scene times, with the killing hit at about -0.05.
- Timing: the kill still runs at scene t 0..def.len. The lead-in runs before 0. The trigger is a film-time freeze AT scene 0. The exit runs after def.len.
- Set pieces ink in DURING the trigger on film time: `s.fspan(0, s.trig.film, (u, view) => …)` or `s.onTrigger(fn)`. They ink out at `s.exitT` / `s.onExit(fn)`.
- `s.deathCrack(t, {at, dur:1.6, tilt, keep}) -> {t, film}` is the death-realm signature; the KIT-WORLD crossing follows right after it. `s.setArena(key)` / `s.setArenaAt(t, key)` switch arenas.

## ARRIVALS API POSTED (KIT-WORLD, 21:35): `58k_arrive.js` header. Being verified now; the coordinator pings when it's confirmed working. Then every builder switches their own ink fallbacks to it, for one shared look.
- `s.inkIn(target, o)`: with no time it runs during the kill-cam trigger, on film time; or `s.inkIn(t, dur, target, o)`. target = a layer fn (registered layers are swapped in place), a prop with .draw, a Body, 'bg'|'mid'|'top', or an array. Look: a gold nib traces the outline and inner lines with wet blots, then the colour bleeds in from the line (gold first, then real colours) and a shine sweeps across.
- `s.inkOut(target, o)`: with no time it runs at s.exitT. The reverse.
- `s.pullOut(b, t, 'knife'|'cleaver'|'machete'|'scissors'|'cape'|'blindfold'|'sight'|'grenade'|'lighter'|'rose'|'bottle'|'coin'|'card'|'hook'|'syringe'|'rope'|{weapon}|fn, {hand, from:'back'|'belt'|'coat'|'boot'|'air'}) -> H`
  - H has drop / throw / stow / snip / flick / pin / wear / mount / flare, plus tip() and pos().
- Guard calls with `if (s.inkIn)` until it's in K58.SHARED.

**CASTING, for everyone, now:** every gold ink-in goes through `s.castInk(caster, [t], target, o)` (58k_arrive.js; read its header):
- the killer casts offensive / staging pieces ('sweep' / 'trace' / 'snap' / 'muzzle' / 'slam');
- the victim casts defensive cover ('thrust');
- exits use s.castInkOut;
- no bare s.inkIn anywhere;
- hand props through s.pullOut.

## GOLD INK COMES FROM THE HAND (the user, 22:50): "gold ink should come from hand, instead of gun"
- No casts from the gun. The coordinator patched 58k_arrive.js so style 'muzzle' now casts as a hand 'snap'.
- Builders: pick hand styles ('sweep' / 'trace' / 'snap' / 'slam', and 'thrust' for victims) and remove 'muzzle' from your calls.
- KIT-WORLD: retire the muzzle gesture properly (keep the alias to 'snap').

## REALM TOOLKIT + CASTING KNOBS POSTED (KIT-WORLD, 00:30). Read the headers of 58k_worlds.js and 58k_arrive.js.
- castInk: 11 hand styles (sweep, trace, snap, point, beckon, claw, spin, fist, rip, slam, thrust) and many knobs (speed, size, height, hold, line arc / straight / zigzag / spiral / wave / drip, land point, glyph seed). Combine them so no two kills cast alike. Note it in your ledger KITS column.
- Realms: s.realm(key, {sky, ground, parts, light, grade}), s.cross(... sink / rot / lightsout / burn / rise / swallow), s.ret(... snap / spit / fade / crumble), s.dropCorpse, s.groundMark.
- TAKEN by the SMG page, never reuse their signature looks: the black river + ferryman + hands (BELOW), the graveyard + named stone + coffin (NAME ON THE STONE), the looping ash void + peeling shadow (NOWHERE). The crossings sink (tar), rot (floorboards to grave) and lightsout (void), and the returns spit (puddle), grave-mark and no-shadow, are also used.
- Every future realm builds its own identity from parts plus your own drawing: a new sky / ground / signature horror element, a new crossing and a new return, checked against the ledger.
- (00:58) The 11 REALM LAB compositions on 58k_kit_world.html (butcher hell, bone throne, frozen ninth circle, hourglass library, gallows forest, drowned cathedral, mirror limbo, field of crosses, spider abyss, eye of the abyss, pit of hands) are PARTS DEMOS. Don't copy one as it is into a kill: compose your own realm (sky layers + ground + parts + your own drawing + your own crossing / return), and log it in the ledger. The ~40 seeded parts, 13 crossings and 15 grounds give endless combinations; use them so every realm is one of a kind.

## REPLAY KIT POSTED (KIT-REPLAY, 01:25): 58k_replay.js header; demos on 58k_kit_replay.html
- `s.rewind(t, {to:'start'|<0, style, speed, cam})`: 8 looks (vhs, film, digital, cctv, manga, crt, negative, holo); it can rewind back into the gameplay lead-in ("how it happened").
- `s.replay(t, {angles:[...]})`: 18 cams, 10 wipes, 7 telestrator kinds, 6 bug styles, 11 filters, speed ramps, freeze endings. A rewind and a replay at the same t chain into one segment. `s.pipReplay(t, {...})` over the live action.
- The MIX GUIDE has 1-2 per 25-kill weapon (mostly MYTHIC / LEGENDARY). Stage each replay uniquely: cam / wipe / look / bug combinations never repeat, and log them in the ledger KITS column.

## BODY KIT ADDITIONS (KIT-BODY, 02:00): 58k_anatomy.js header; 47 demos on 58k_kit_body.html
- s.eyePop (the eye on its optic nerve), s.jawOff (jaw + teeth fly; the tongue dangles), s.teethOut, s.ribOut -> a rib as a bone blade in the killer's hand, s.gutsNoose (his own guts round his neck), s.artery (carotid / femoral / brachial / wrist / aorta jets per heartbeat), s.skeletonWalk, s.peel(b, t, 'scalp'), openChest {style:'claws'}, peel style 'strip', shatter kind 'obsidian' (realms), cube 'ball' / 'slab'.
- Need a body tool that isn't there? SendMessage KIT-BODY (a38d1cba93f1f8a49) one line and it gets added.
- (24 Oct, KIT-BODY) **TWELVE NEW DEATHS** in `58k_bodyx.js` (window.K58X; loads with 58k_matter.js automatically; demos in section 04 of 58k_kit_body.html, 12 + 18 re-cuts). The ledger count showed impale 30, slice 29, holes 27, x-ray 26, skull 21, guts 17, eyePop 11 used; these had 0-1 uses, so use them instead. All (b, t, o), seeded, scrub-exact, 60 fps at 4x throttle, sound-hooked; fronts spread along the skeleton (o.from: 'feet' | 'hands' | 'ends' | 'head' | 'chest' | a joint | [x,y]) so they port to the Unity rig 1:1. Customise every use (options + seed) and log it in the KITS column.
  - `s.electrocute(b, t, {from: 'sky'|'ground'|[x,y]|fn, col: blue|white|purple|green|red|gold, hz, arcs, cook, skel: 0..1 (x-ray strobe), hair, sockets, lift, end: plank|crumple|kneel})`
  - `s.petrify(b, t, {stone: granite|marble|sandstone|basalt|jade, from, creep, endT, end: crumble (head rolls)|topple|sand (dune)|stay, moss, cracks})`
  - `s.char(b, t, {from, flame: fire|blue|green|hell, burn, curl (boxer pose), endT, end: heap (skull on embers)|stand (blown away)|crack (coals)})`
  - `s.frostbite(b, t, {style: ice|gangrene, from: 'ends', creep, order: [cuts], gap, snap: shatter|whole, icicles, breath})`
  - `s.liquefy(b, t, {style: burst|drain|boil, liquid: blood|water|bile|mercury|ink|acid, at (puncture), endT, drain})`
  - `s.shrinkWrap(b, t, {film: clear|black|pink|blue, style: vacuum|heat, end: mummy|pack, label})`
  - `s.tendonRip(b, t, part, {by: killer (holds the wrist), dir, dist, dur, n, kinds, throw})`, part: armF|armB|foreF|foreB|legF|legB|shinF|shinB|head
  - `s.hollow(b, t, {how: siphon (to: point|fn)|pores|wound, drain, end: crack (empty inside)|crumble|blow})`
  - `s.wax(b, t, {wax: white|red|black|bees|blue, wick: head|hands|both, burn, left, end: out|stub})`
  - `s.stuffing(b, t, {kind: feathers|straw|cotton|beans|sawdust, burstT, at, dir})`
  - `s.corrode(b, t, {kind: acid|toxic|venom|lava|bile, how: rain|splash (at), n, cuts, dur})`: layered holes (skin, muscle, bone, see-through); limbs drop at the joints
  - `s.crystallize(b, t, {gem: amethyst|emerald|ruby|ice|citrine|void, from, grow, n, end: shatter|stay|tower})`
  - (11:40) MORE: `s.decay(b, t, {dur, end: bones|dust, stand, grass})` a time-lapse rot · `s.jigsaw(b, t, {inside: meat|hollow, order: top|random|hit, at})` he is a puzzle, pieces pop out · `s.implode(b, t, {to, dur, spin, col})` pulled into a singularity · s.petrify stone 'salt' · s.crystallize end 'geode' (rock shell cracked open, crystal-lined) and `points: [[x,y]...]` (clusters erupt from exact hit points).
  - Sound ids (KIT-SOUND scores them): matter.electro.* · matter.stone.* · matter.char.* · matter.frost.* · matter.liquid.* · matter.wrap.* · body.tendon.* + body.limb.free · body.hollow.* · matter.wax.* · matter.stuff.* · matter.corrode.* · matter.crystal.* (timings in the file header).
- (02:05, SOUND-2) s.hush(t, amt) holds until another hush, so ALWAYS lift it (a later s.hush(t2, 1)). An unlifted hush silenced ONE PUNCH. Builder s.snd / sndNow calls are fine: the sound layers upgrade and dedupe them.
- (02:10) SHARED FILES MUST NEVER BREAK MID-EDIT. Every 58k page loads the shared kits, so a half-written 58k_destruct.js broke ALL pages for a while. Owners of shared files (58k_cine.js, 58k_page.js, 58k_slice.js, 58k_arrive.js, 58k_worlds.js, 58k_destruct.js, 58k_anatomy.js, 58k_matter.js, 58k_replay.js, 58k_sound.js, 58k_snd_*.js) do multi-step changes in a working copy (e.g. _scratch/<file>.next.js), syntax-check it (node --check), then swap it in with one write. Lane files follow the same rule where possible.

## DETERMINISM + RESILIENCE (02:20)
- KIT-REPLAY is DONE (58k_replay.js; 58k_kit_replay.html). It now runs QA-DETERMINISM + PERF over every page; table in _tools/58k_QA.md. Expect messages about nondeterministic or slow kills and fix them first.
- Keep all drawable state on objects (bodies, particles, scene fields), never in closure variables. Seeded s.rng only (no Math.random / Date.now in build or draw). Draw textures directly rather than through canvas patterns where frames must be exact. A frame must render identically by scrub, by play, and on a fresh load, or it can't rewind and can't be ported exactly.
- The shell now survives a broken kit file (it's logged once and its kills skipped) and catches a build or step that throws (logged once per kill). Still keep shared files parseable at every save.

## GORE LADDER + KILL SYSTEM SWITCHES API (KILLPAGES-A + KIT-BODY, 24 Oct; P0.4 / P0.5; live in 58k_cine.js)
**The level.**
- `K58.gore`: the global level, 0..5, default 5. It is saved in localStorage (`k58.gore`).
- `K58.GORE = { VLOW: 0, LOW: 1, MED: 2, HIGH: 3, VHIGH: 4, EXTREME: 5 }`, plus `K58.GORE_NAMES` and `K58.GORE_INFO` (the §6 text).
- `K58.setGore(lv)`: sets and saves the level, rebuilds every loaded player at its current frame, and fires `K58.emit('gore', null, lv)`.
- **A scene reads the level ONCE, when it is built.** Nothing flips mid-film. To render any level without touching the global, pass `opts.gore`:
  - `view.load(def, { gore: 2 })`
  - `K58.still(def, frames, w, h, { opts: { gore: 2 } })`
  - `K58.offscreen` views likewise.

**In kills and kits.**
- `s.gore`: the scene's level.
- `s.goreAt(n)`: true when `s.gore >= n`.
- `s.bloodK = [0, .12, .4, .6, .8, 1][s.gore]`. Scale your OWN red (custom fx, rings, cores) by it.
- Every gore beat needs a crafted version at every level (brief §0 / §6).

**K40's own gore (the shell).** 40k_gore.js is not edited; the shell maps it.

| level | what the shell does |
|---|---|
| 5 EXTREME | the current look, unchanged; pools and bodies stay all round; lens splatter |
| 4 VERY HIGH | 80% blood; stains fade after ~10 s; no lens splatter |
| 3 HIGH | 60% blood; no bone chunks or bone shards |
| 2 MEDIUM | 40% blood, no gibs, pools fade fast. Nothing comes off: `s.cut / shred / extra / headPop` and cine's `slice / halve / headSlice / scalp` leave DARK GASHES (`b.gash58`, drawn by the shell). See-through holes draw as dark wounds. |
| 1 LOW | every blood call is a small dark puff; no wounds; the dead get knockout stars |
| 0 VERY LOW | no blood: sparks, dust and stars. The dead fade out in a puff 1.2 s after the K.O. Set `b.keep58 = true` to keep a body; kits don't add their own fade. |

- Below EXTREME, the blood draws from its own seeded rng, so `s.rng` (the kill's own randomness) is the same at every level.
- `Body.sever` is NOT wrapped. Kits that call it directly gate it themselves at MEDIUM and below.
- Helper: `K58.addGash(s, b, spec, {ang, len})` adds a shell gash. `spec` is a cut name ('head', 'armF', 'waist' …), 'skull', or `[jointA, jointB, u]`.

**The switches (brief §7).**
- `K58.SWITCHES`: the list (id, group, name, description, default).
- `K58.sw`: the values, saved in `k58.sw`.
- `K58.setSw(id, v)`: sets one and rebuilds the films; fires `K58.emit('switch', null, {id, v})`.
- The ids: `chain`, `multihit`, `jump`, `wounded` (the 4 multi-kill triggers), `midround`, `zone`, `destruction`, `gore`, `flash` (reduce flashing), `motion` (reduced motion).
- A scene snapshots them at build: `s.sw('zone')`, `s.sw('flash')` …; `s.sw('gore')` is the level.
- With `flash` on, the shell already softens its flashes and drops impact strobes, chroma and glitch.
- Every 58k page header has the GORE chip and the KILL SYSTEM panel (`K58.settingsUI(bar)` puts them on any other page).

## THE GAME'S 18 ARENAS: the plate swap + the MAP switcher (P1.1, shell: 58k_cine.js §9c, 58k_page.js)
- Data: TF-KILLS's export `58k_maps.js` (`window.K58_MAPS`, loaded first by every weapon page and listed in `K58.SHARED`), plates `img/maps/<id>.jpg`. Page units at 88.49 per game metre, which is the page fighter's own scale (KillCine.PK), so **fighters are unchanged and the arenas swap**.
- **A kill keeps the coordinates it was written in; the arena comes to it.** When a scene sets one of the four old real arenas (castle / saloon / backyard / rooftops), the shell gives it an INSTANCE of the export, which is not in K.ARENAS. The instance is the plate, solids and plats translated by `off58` so that a floor of the target map lands under the kill's home anchor:
  - castle (800, 589) · saloon (800, 588) · backyard (800, 579) · rooftops (690, 431), the old centre roof A, which is the export's roof at y 510.
  - Instance fields: `export58` (map id), `home58`, `off58: [ox, oy]`, `spot58`, `floor` / `mid` (the kill's own), `img` / `x0` / `y0` / `w` / `h` (the export plate placed), `solids`, `plats` (slopes become 8 u steps).
  - KIT-WORLD's s.el / els / need read the instance (export58 + off58), so elements come back in the kill's own coordinates. Never mix the old K40 plate with exported coordinates.
- `K58.map`: `'home'` (default: each kill on its own arena's export plate) · a map id (every kill on that map) · `'k40'` (the old plates, for comparing). `K58.setMap(m)` saves it and rebuilds every loaded film at the same frame. The MAP chip in the header opens the arena board.
- `K58.mapCheck(def, m)` returns `{ mode, missing, cast, target, spot, port }`:
  - mode `home` (written here) · `map` · `cast` · `skip` · `realm` (not on a real arena) · `k40`.
  - The checks:
    - kinds (`def.needs` element form via K58.needsCheck; the old words map: flat → FLOOR, wall → WALL, ledge / height / roof / edge → DROP, gap → GAP or DROP, plat → PLATFORM, ceiling → CEILING, barrel → EXPLOSIVE, water → LIQUID, pendulum → HANGING_HEAVY);
    - underwater + needs ground → `DRY GROUND`;
    - room: a dry FLOOR run (hills and crates split it) wide enough for the kill's footprint (`K58.footprint(def)`: its fighters at t = 0) → `ROOM`;
    - footing: every fighter, after the kill's own t = 0 set-up, stands on real ground of the instance → `FOOTING`;
    - `sky` → no CEILING over the spot.
  - `skip` = the view draws the **OWED card** (the map, NO <KIND> chips, "<KILL> SKIPS ON <MAP>"), never a broken frame.
  - On its HOME map a kill whose fighters would stand wrong on the export (an old ledge or platform at another height) gets `port: true` and **stays on its old plate** until ported (tag "· OLD PLATE"). Port it with s.el positions; the tag then clears by itself.
- PORTING A KILL TO THE EXPORT (P2.1): take positions from `s.el(kind, {near})` instead of hard-coded x / y. Use `s.arena.floor` for the floor, and never a literal 588 / 589 / 579 / 431. Stand fighters on `s.floorAt(x)`.
  - A fully ported kill sets `coords: 'export'` on its def. It is then written in the export's own coordinates: main floor 590, middle 800, rooftops roof A at (682.4, 510). Its home offset is 0, and on other maps it moves as a block.
  - KIT-WORLD's fit, to convert an old literal to export coordinates: `x' = 800 + (x − 800) · 1.0687`, `y' = 590 + (y − F) · 1.0687` (F = 589 castle, 588 saloon, 579 backyard, 508 rooftops).
- MID-ROUND point of view: `K58.zoneView` is `'inside'` (default) or `'outside'`. The page toggle is saved per page; stills and sheets always use inside. The driver passes `o.view` to the zone look.
- `def.room58 = [x0, x1]` (kill units from the home middle): the floor room the kill needs, if its action runs past where the fighters stand at t = 0 (slides, throws, charges). It replaces the measured footprint in the map fit.
- `def.anchor58`:
  - `{ kind: 'WALL' | ['WALL', 'PILLAR'], face: 'right' | 'left', x }` puts a real face of that kind on the kill's x on every map.
  - `{ kind: ['PLATFORM', 'CEILING'], under: true, x, h: [d0, d1] }` puts something to hang from over x, d0..d1 above the floor.
  - In the build, `s.hangAt(x, d0, d1)` returns that underside's y.
  - A map with no fitting feature shows OWED.
- MID-ROUND zone look: the page's pick, else one of `K58.ZONE_APPROVED` (KIT-WORLD's config; today ['veil']). The look's crafted cast plays on Faris in the frozen trigger.
- `def.spot58(X, mapId) -> [x, y] | null`: the kill's own staging, for kills that need an element relation (a platform over the floor at both fighters, a light near the fight, a ledge over a lane).
  - X is the export arena data, in export coordinates. Return the floor point where the kill's home middle lands, or null when this map can't stage it.
  - null skips the kill and shows OWED, with missing = [def.spot58why || 'SPOT'].
  - On the kill's own home map the hook also re-seats it (unless def.coords === 'export').
  - It wins over anchor58 and the floor fit. The fighter FOOTING check still runs.
- `s.goreCam(t, at, o)` (shell, 25 Oct): the XT gore close-up. At gore >= `o.min` (default 5) the camera pushes into a wound point and holds it, tracking it; lower levels keep the kill's own camera. Each kill still chooses its own point, timing and framing.
  - `at` = [x, y] or a function (tracked live), e.g. `() => V.along('m-n', 0.6)`.
  - `o = { min: 5, w: 90 (or ws: { 5: 80, 4: 110 } per level), dur: 0.6 (the push), hold: 1.2 (how long it keeps tracking after the push), dx, dy, rot, ease: 'io' }`.
  - Call it after the kill's own camera calls for that moment (the later camera program wins). Example: `s.goreCam(5.9, () => V.along('m-n', 0.6), { ws: { 5: 84, 4: 110 }, min: 4, hold: 1.6 })`.
  - `o.final: true` (the 01:23 last-frame rule): the close the film ENDS on. It holds through the end and the exit, and from its start the camera is LOCKED at that gore level: every later camera call (the kill's own pull-backs, crashes, the exit) is ignored. Use it for the last close of every film; no hold maths needed. Example: `s.goreCam(6.0, () => V.at('head'), { min: 4, ws: { 5: 72, 4: 92 }, dur: 0.5, final: true })`.
  - `at` must be a pure function of scene time or sim state, never a value written during drawing (a frame rendered without the one before it would get it wrong).
  - TIP (G, 25 Oct): for the FINAL image, place the goreCam LAST in the camera program (after every camera call at or after its time) and set `hold: def.len + 3 - t` so it holds to the film's last frame; a shorter hold lets the kill's own camera pull back out before the end. Lower levels keep their own ending (min: 4 or 5).
- TIP (C, 25 Oct): RELEASING A PINNED RAGDOLL (the body steered by `p.pin` functions, then let go):
  - Keep every particle at least its own radius (`p.r`) above the floor when you let go. In `Body.step` the floor collision pushes an overlapping particle out in one step, and the velocity is read back as (x - ox) / h. A 5 u overlap launches him upward at about 1,200 u/s.
  - Set `p.ox = p.x; p.oy = p.y` with the release.
  - A pose tighter than the ragdoll's reach limits (a ball, a fold) springs open on release, because the 'r' constraints have a fixed `min`. Relax them to the pose first: `for (const q of b.C) if (q.min != null) q.min = Math.min(q.min, dist(q.a, q.b) * 0.9)`.
  - `s.cut` / `b.sever` do nothing on a fighter who is still alive (no `P` yet): the limb silently stays on. Cut after `die()`, or use a live-body cut (C's `KC.liveCut` in kc.js hides the segment, flies the piece and severs for real at death).
- `KC.spotPost(X, { rel: -40, lane: true })` (C's kc.js, a `def.spot58` helper, 25 Oct): returns export `[x, y]` that seats the kill so a NARROW freestanding PILLAR (at most 80 u wide, at least 110 u above its floor, a mast through a deck counts, a clear lane on its left) lands at middle + rel; with no such post it returns any clear floor lane (the kill casts its own post), or null with `lane: false`. No current map has a narrow post (the exported PILLARs are towers, map-end walls and a gantry column), so NARROW ESCAPE casts its pole everywhere; it is kept for a future map drop.
- TIP (L, 25 Oct): `s.freeze(t, dur)` takes hold on the first FRAME after t (about 1/60 s later), so anything scheduled between t and that frame (a camera call, a pose at t + 0.002) fires BEFORE the hold and overrides what you meant to play inside it. Schedule post-freeze events at t + 0.02 or later, and drive anything that animates inside the freeze from the film clock (`v.real - v.clock.fOf(t)`), not from scene time or a camProg's u.
- REAL DEAD FACE (KIT-BODY, 58k_anatomy.js, 25 Oct 10:59; brief §9 XT FACES ARE REAL): the engine's default dead face (every corpse whose kill paints no face, and every `b.faceNow = 'xx'`) is now gore-aware. XT / VH: an open, glazed, half-lidded eye with a blown pupil, bloodshot sclera, a slack mouth and a trickle of blood (variants: frozen = frosted lashes, drowned = swollen and bloodshot with a bubble, burned = whited-out). HIGH: the same eye, dry. MEDIUM and down: the X glyph as before. Any face a kill paints itself ('pain', 'none', own deadFace(g) ...) is untouched; it is a b.faceNow accessor, deterministic. Faces: K.FACES.d58{W|D}{n|f|u|c}.
- `def.stage58(mapId, X, info) -> { ok, missing, spot, note }`: the kill's own staging verdict on maps other than its home. It runs after the generic checks, so the OWED card names the kind the kill really lacks.
  - `{ ok: false, missing: 'WALL' }` (or `['WALL', 'DROP']`) skips the kill and REPLACES the generic labels: the card says NO WALL, not NO ROOM.
  - `{ ok: true, spot: [x, y] }` (export coords) stages the kill there. The placement labels (ROOM / FOOTING / SPOT) give way, FOOTING is re-checked on the new spot, and the kind checks stay. `ok: true` without a spot changes nothing.
  - Shorthands: `false` = `{ ok: false }` (card: NO STAGE); `'WALL'` or `['WALL', 'DROP']` = `{ ok: false, missing }`; `true` / `null` = no verdict.
  - `note` is one plain line on the card, under the SKIPS line (≤110 chars).
  - `info = { home, spot, missing, has(kind), els(kind), floor }`: the generic spot (or null), the generic labels, a kind check on this map, the export elements of a kind, and the main floor y.
  - A hook that throws reads as `{ ok: false, missing: ['STAGE'] }`, with a console warning.
- EXPORT HOMES: a kill may be written on any of the 18 maps by setting `def.arena` to the export id ('pirate', 'tower', 'kitchen', …).
  - Its home anchor is that map's middle on its main floor, (800, floor), in kill units. With `coords: 'export'` it is the export's own coordinates.
  - `def.spot58` re-seats it at home and elsewhere.
  - There is no old plate, so the OLD PLATES switch leaves it on the export. A home it can't stand on is OWED (FOOTING).
  - The page waits for its plate before `k58-loaded`.

## SCRUB TEST (KIT-WORLD, 25 Oct): catch draw crashes the load probe misses
- The probe and still sheets only render the frames you sample. A layer or overlay can still throw on frames nobody looked at (for example a radius going negative during an overlay's scale-in). That throw stops the film for the viewer.
- The scrub test loads each kill in an offscreen view, then seeks and RENDERS every 0.05 s of film (lead-in, trigger, replays and exit included) at the gore levels you name. It reports each film's length, the frames rendered and the first errors with their film times.
- Files: `_tools/scrub/58k_scrub.js` (the in-page eval: set `KEYS = ['weapon.kill-id', …]` and `GS = [5, 2, 0]`) and `_tools/scrub/58k_scrub.sh` (usage: `SCRUB_PAGE=58k_<page>.html SCRUB_DIR=<scratch> 58k_scrub.sh "['k1','k2']" "[5,2,0]" OUT PORT`; it drives KIT-WORLD's headless kwperf runner on a private port). Or paste the eval into any headless page run of your own.
- Expect `errs: []` for every key and level. Use a distinct debug port, because shared ports return another builder's page.

## HORROR FLOOR KIT LIFT (KIT-BODY, 26 Oct 01:21, coordinator-approved; live in `58k_anatomy.js`). PORT SPEC for TF-PORT-ENGINE
Every piece is a pure function of the body, its scene (seeded) and t. Nothing is random, so stills and finalT stay exact. Each piece is data-tunable through `window.K58A`.
- **(c) XT DEAD-FACE VARIANTS** (`K58A.xtFace58(b)`, read by the `b.faceNow` accessor, EXTREME only):
  - Applies only where a kill left the engine dead face ('xx' or none on a dead body). VERY HIGH keeps d58W, so XT and VH differ. HIGH d58D, MEDIUM 'xx', LOW / VERY LOW dazed58 (A's table `K58.FACE_LEVELS`).
  - Death type wins:
    - `mat58.kind` frost → `d58Xf` (frost crust, iced-over cracked eye, blue lips, icicles);
    - char / electro → `d58Xc` (charred cracked skin, embers in the cracks, cooked white eye, lipless teeth, smoke);
    - brine or an underwater scene → `d58Xu` (blue-grey bloat, bulging bloodshot eye, foam at mouth and nose).
  - Otherwise there's a per-kill pick from h = (FNV-1a(def.id || def.key) % 10007) / 10007:
    - h < 0.10 → `d58Xeye` (eye out on its cord, torn socket);
    - h < 0.18 → `d58Xjaw` (lower jaw gone, cavity breaks the head outline, tongue and blood sheets);
    - h < 0.25 → `d58Xskull` (front of the face flayed to bone, lidless eye, bare grin);
    - anything else stays plain d58W.
  - A variant missing from the weapon's pool also falls back to plain. Pools (`K58A.XTFACE.pools`, by `XTFACE.cls[weapon]`):
    - gun: eye / skull / jaw;
    - shotgun: jaw / skull;
    - blunt: eye / jaw;
    - blade: skull / jaw;
    - boom: skull / eye / jaw;
    - energy: skull.
  - Never applies when:
    - the kill set the face itself (crafted faces always win);
    - the head is gone, dented or cleaved;
    - the anatomy kit already opened the head (a.eye / a.jaw / a.skull / a.teeth);
    - the body is in any other material (petrify, wax, gold …).
  - Faces are drawn in head space (r 18.5, facing +x, eye at 9.6,-4, mouth at 12,8). The only motion is a slow t-sway of the hanging eye and tongue. `K58A.XTFACE.off = true` disables all of it.
- **(a) CALIBRE WOUNDS** (`K58.woundStyle(ctx, b, t, B, lv)` + `.takes(b, lv)`, called by A's hook in the shell's wound wrapper; flag `K58A.WOUND58.on`, on):
  - Replaces K40's round meat decal for `b.wounds` at EXTREME (full) and VERY HIGH (the hole only). HIGH and below are unchanged (A's gating).
  - Class comes from the scene weapon (`WOUND58.cls`); a hole's own `kind` wins (`s.holes(b, [{ c, u, kind }])`):
    - **small** (pistol, golden): ragged raw rim, dark hole;
    - **auto** (smg, ar, burst, minigun): the same hole stitched three times along the limb;
    - **large** (revolver, handcannon, sniper): a crater with a raw rim, a muscle ring, a dark cavity, 1-2 bone chips;
    - **pellet** (pump, sawedoff): 8 pellet holes round a torn centre;
    - **laser**: a cauterised black slit with a glowing edge, no blood;
    - **beam**: a blistered boiling patch with skin sloughing below it.
  - At EXTREME each hole also gets three extras:
    - an **exit blowout**: one ragged tear-drop of raw flesh pointing away from the shot (−b.fc), drawn UNDER the hole and past the outline;
    - **spray** dots along the exit direction;
    - a gravity **run** that stops at `sc.floorAt(x, y - 2)`.
  - Holes are clipped to their limb's capsule (half width W/2 + 0.6·outline), so they never spill off the body. The head circle is clipped out.
  - `takes()` is false for bodies under a look transform (squash, flatX, clipY, erode, scan, skel, only, xray, gold) or in a material. Those keep the engine holes.
- **(b) THE HERO WOUND + READABLE AT SMALL SIZES**:
  - The biggest small / auto / large / pellet hole on the body at EXTREME is drawn 1.4x. What's inside it shows: one broken rib reaching in for a torso hole, the bone's cut face with marrow for a limb. A wet gloss sits on the rim. It's clipped to the limb like every hole.
  - `K58A.READ58` (on): on a dead body at VERY HIGH / EXTREME, the anatomy kit's body draw floors every INK stroke at 1.5 screen px and every BONE stroke at 0.9 px (the stroke width is computed from the current transform). Organ, rib, face and wound outlines then survive wide shots. Port: the same floor in the renderer, in screen px.
- **(d) GRAVITY BLOOD** (`K58A.GRAV58`, on; EXTREME only, never underwater; live 02:00).
  - It's KIT-BODY's own layer on `K.Blood` (wraps `update` and `drawBack`). It never calls the scene's rng and never adds engine drops, splats or pools, so a kill's own blood is untouched.
  - **Ledge pours**: an engine pool that spreads past the edge of the solid it lies on pours off that edge as a sheet. The sheet falls at 520 u/s to `sc.floorAt(edge ± 1.5, y0 + 3)` and starts a second pool there (r = 6 + 2.2·width, 2.2 s). Each pool edge pours once.
  - **Hanging drips**: a dead body (0.4 s after `deathT`) is "hanging" when its lowest point is 16 u or more above the floor under it and still (|y − oy| ≤ 1.5 per step). A string of blood stretches from that point and lets go of a drip every 0.25 s. The drips fall at 1275 u/s² and feed one pool under him (r 3.2 → 13).
  - Its pools draw through the engine's pool painter (same look). It caps at 24 drips in flight.
  - Close XT finals rarely show it; it's mostly visible in the wider film beats.
- **(e) `K58.brutCheck(def)` / `K58.brutCheckPage()`** (live 02:00; MANDATORY on every XT before a sheet, brief §9 02:00).
  - Renders the XT final (`K58.finalT` at gore 5, 480 × 221) and returns `{ key, ok, flags, vH, vA, fA, lum, face, faceOk, measured }`.
  - The victim is measured from his K40 body boxes (pieces included). When he isn't a K40 body (cut pieces, props, a costume), he's measured in pixels instead: the frame minus the same frame with the kill layers stripped, with blood-red pixels and Faris's box left out.
  - Flags (data `K58A.BRUT58`):
    - **TINY**: vH < 0.22 or vA < 0.05;
    - **FARIS**: Faris's area is more than 2.2× the victim's while vH < 0.45;
    - **OFFFRAME**: under half the victim's box is on screen and what shows is small (vA < 0.12);
    - **DARK**: mean luminance in the victim's box is under 34;
    - **LIVEFACE**: the victim is still alive at the final with 'shock' / 'pain' / 'dot' / 'angry';
    - **NOFACE**: his head is off frame (skeletons, x-ray, materials and a lost head are exempt);
    - **UNMEASURED**: nothing measurable, so check by eye.
  - TINY / OFFFRAME / FARIS from the body boxes get a second opinion in pixels: a prop payoff that reads (a thrown head, organs, pieces) clears them.
  - `PIXELS` is only a note that the pixel measure was used.
  - Calibrated on the graded pages (sabre, hammer, RPG, hand cannon):
    - it flagged 27 of the 31 brutality FAILs whose failure is a camera matter (small, dark, Faris-dominated; the 4 misses sit just over the thresholds);
    - it doesn't catch hidden-behind-a-prop or gag finals, so those stay by eye;
    - it flags 4 of the 26 PASS kills: crafted heads (only the brain left, a close teeth-and-eye payoff) and live 'shock' faces (correctly flagged under the face bar).
