# Page 58 · MAP ELEMENT KINDS (v1, coordinator, 24 Oct)
Kills are written against these KINDS, never against one arena's layout (brief §2).

Owners:
- KIT-WORLD (a7daba00c1b156177) turns this list into the page API (`s.el`).
- TF-KILLS (adc5a7c8610d6bef9) tags the real elements of all 18 playable arenas in the game and exports them to `58k_maps.json`.
- Both extend this file. A kind is added here first, then used.

## Each element carries
- **id**, **kind**, **arena**
- **shape**: rect / polyline / circle
- **position**
- **size**
- **tier**: indestructible / cosmetic-only / light / heavy
- **material** (FLOOR / PLATFORM / WALL / CEILING / STAIRS / PILLAR; added 15:30): turf / stone / wood / metal / concrete / tile / sand / snow / glass / water-edge. Kills pick debris, dust, sound and marks by it (quakes, floorboards, pegs, mole hills).
- **hazard**: none / damage / instant
- **moving**: none / path + period
- **uses**, telling a kill what it can do with it:
  - anchor: something to slam into, hang from or pin to;
  - weapon: it falls, swings, cuts, burns or shocks;
  - container: something to stuff a body into;
  - stage: something to stand on or fall from;
  - backdrop.

## Structure
| kind | what | examples |
|---|---|---|
| FLOOR | a flat run you can stand on (width matters) | every arena |
| WALL | a vertical solid surface | tower sides, saloon walls, container sides, cage walls |
| CEILING | overhead solid | saloon roof beams, mine/station ceilings, Atrium floors |
| PLATFORM | something to stand on above the floor (solid or one-way) | balconies, walkways, ledges, crates, decks |
| DROP | an edge with a fall below (≥ ~3 m) | roof edges, balcony edges, cliff edges, the void |
| GAP | open air between two standable surfaces | rooftop gaps, broken bridges |
| STAIRS / SLOPE | steps or a ramp. Two tokens in the data: `STAIRS` (a flight of steps) and `SLOPE` (a plain ramp) | Temple Steps, forts ramps |
| PILLAR | a tall freestanding column (usually a heavy breakable) | castle towers, temple pillars, rigging masts |
| OPENING | a door, window, hatch or porthole (breakable or passable) | saloon doors, windows, portholes |

## Props
| kind | what | examples |
|---|---|---|
| HANGING_HEAVY | a heavy thing hanging overhead that can drop or swing | saloon chandelier, castle spike ball (pendulum), lamps, crane hooks, the clock bell |
| EXPLOSIVE | blows up when hit | barrels (the game already has ExplodeBarrel), gas tanks |
| BREAKABLE_LIGHT | breaks from bullets | glass, crates, planks, signs, bottles, screens |
| BREAKABLE_HEAVY | breaks from explosions / heavy melee | pillars, doors, statues, walls of crates |
| SHARP | cuts or impales | spikes, saws, fence spikes, nails, kitchen knives |
| HOT | burns | fire, torches, hob plates, furnaces |
| ELECTRIC | shocks | wires, panels, sockets, lightning rods, arcade machines |
| LIQUID | a pool or volume you can fall into (depth matters) | water, a sink, a pond, a blender jug |
| UNDERWATER | the whole arena is liquid: no falls, swim poses, blood clouds | The Deep |
| MOVING | moves by itself; can carry, crush or fling | Clock Tower hands, Pirate Ship deck roll, Retro Desktop windows / cursor, Pinball flippers, conveyors |
| BOUNCY | bounces bodies | Cage ropes, pinball bumpers, awnings |
| CLIMBABLE | ladders, ropes, rigging | ship rigging, ladders |
| CREATURE | a map creature | The Deep's shark, Pirate Ship's kraken |
| BIG_PROP | an oversized everyday object (scale gags) | Kitchen Counter's blender, kettle, knife block, toaster |
| LIGHT | a light that can be shot out or used for a reveal | lamps, neon signs, floodlights, the moon |
| CONTAINER | something a body fits in | wells, bins, barrels, crates, lockers, ovens |

## Added by TF-KILLS for the real maps (CU06, 24 Oct)
| kind | what | examples |
|---|---|---|
| DECOR | drawn scenery the game never touches: no collision, no damage. Use it only as backdrop (uses `backdrop`); a more useful kind goes first when it has one (`['PILLAR', 'DECOR']`) | plants, flags, stencils, sandbags, palms, banners, glyphs |
| EVENT | a map-script event (Clock Tower, Pirate Ship, Kitchen Counter, The Deep, Pinball Arcade, Retro Desktop). From drop 2 it is FIRST in an event element's kinds (`['EVENT', 'CREATURE']`), and an event element never carries PLATFORM (the platforms an event moves are its pieces). A piece hidden at rest (shown only by an event) also starts with EVENT. Event elements have an `event` block: `{name, area: 'frame' (where the lab frames it) or 'map' (all of it), persistent, scheduled, big, harmful, cooldown, firstAfter}` | the kraken, the blender, the bell, the cursor, multiball |
| ZONE | a region with its own physics | low-gravity rooms (`gravity`: the multiplier inside) |

## How kills use kinds (page API, KIT-WORLD builds it in L0.4)
- `s.el(kind, {near: 'victim'|'killer'|[x,y], side: 'any'|'behind'|'front'|'above'|'below', min: {...}, max: {...}})` returns the element the kill should use on the arena currently playing (the page's map switcher, later the real game arena), or null if there is none.
- `def.needs` lists the kinds and the space the kill needs. With no match, the order is:
  1. the kill's cast prop (if it has one and the story allows);
  2. skip (owed);
  3. the game's normal death. There is no cinematic stage (brief §3).
- A cast prop is the kill's own object cast from the hand. It is never a gold copy of a real map's architecture.

## Per-arena tags
`58k_maps.json` holds the per-arena lists. TF-KILLS exports them from the game's real level data for all 18 playable arenas, and that file is the source of truth. Until it lands, pages keep their 4 current plates.

### The export (TF-KILLS CU06: `tools/kills/mapexport.sh`, game side `Core/MapExportLab.cs`)
- Files: `58k_maps.json`, `58k_maps.js` (`window.K58_MAPS = …`, the same object, for file:// pages) and one plate per arena, `img/maps/<id>.jpg`. Re-run the script after any level change; never hand-edit the files.
- Arena keys are the game's ids: atrium, backyard, base (Military Base), canyon (Crate Canyon), castle (Spike Castle), forts (Desert Forts), rooftops (Monsoon Rooftops), saloon (Dusty Saloon), sunken (Sunken Lab), temple (Temple Steps), tower (Tower Block), cage (The Cage), clock (Clock Tower), kitchen (Kitchen Counter), pinball (Pinball Arcade), pirate (Pirate Ship), retro (Retro Desktop), deep (The Deep). Hidden maps are not exported.
- Units: page units (x right, y down), the page-58 scale: 88.49 per game metre (`1 / KillCine.PK`, the scale the game uses to play a page kill). Per arena `xf: {s, dx, dy}` gives game metres: `gx = (px - dx) / s`, `gy = (dy - py) / s`. Each arena's middle sits at page x 800 and its main floor at page y 590.
- Note: the four K40 plates (`K.ARENAS`) were captures at about 82.8 units per metre. The export is about 7% bigger, true to the game. Its own plates line up with its own data.
- Per arena: `name, size ('small' | 'medium' | 'big' | 'event'), theme, tagline, underwater, closed, follow, wind, rain, events, xf, floor, mid, bounds / camArea / killArea ([x, y, w, h]), plate, plateK (image px per page unit), plateRect ([x, y, w, h]: where the plate sits), plateClean (from drop 2: `img/maps/<id>_clean.jpg`, the same view without the live-capable props, with `plateCleanOmits: ['props', 'spikeball']` saying what's missing; null when nothing live is baked in. Same plateRect / plateK. Moving pieces stay in both plates), spawns, lava, water [{x0, y0, x1, y1, flood?}], solids [{x0, y0, x1, y1, slope?, ice?, conveyor?, shell?, fill?, surface}], plats [{x0, x1, y, ice?, surface}], elements`.
- solids and plats also hold the moving pieces where they rest (lifts, carts, the map scripts' pieces shown at rest: Retro's windows, the clock's hands...), so page bodies can land on them. Those entries carry `moving: 'mover:<i>' | 'piece:<i>'`, the same tag as the element's `piece` field.
- Element: `id, kinds, shape ('rect' x, y, w, h | 'circle' cx, cy, r | 'polyline' pts), anchor, tier, hazard, moving, uses, game {type, ref}`. Extra fields by kind:
  - FLOOR / PLATFORM / WALL / CEILING / STAIRS / SLOPE / PILLAR, and every solid / plat: `material` (from drop 2), read from the pattern the piece is really drawn with (the map look's planks / bricks / sandstone / concrete / grating / rock / polished floor / grass and dirt, else the theme's style). A run at a pool's waterline is `water-edge`. Crates are wood, ice blocks glass, and moving pieces take their game surface.
  - FLOOR / PLATFORM: `width`, plus `solid` or `plat` (an index into solids / plats). From drop 2, every run a spawn stands on, and every run at the main floor's height, carries FLOOR (with PLATFORM when something is below it), so `s.el('FLOOR', near a spawn)` works on every arena.
  - DROP: `edge`, `depth`, plus `void` for a ring-out. Every open edge over the void is a DROP whatever its depth (from drop 2); other edges need a fall of 3 m. There are no DROP / GAP elements on underwater maps.
  - GAP: `width`, `depth`.
  - WALL: `face` ('left' | 'right': the way it looks), `height`.
  - CEILING: `headroom`.
  - Barrel: `live: 'barrel'`, `hp`, `blast`.
  - Spike ball: `live: 'hangball'`, `pivot`, `hitR`.
  - Lights: `live: 'lamp' | 'window'`.
- `moving`:
  - `{type: 'path', pts: [rest, to], period, phase}`: pos = rest + (to - rest) · (1 - cos 2π(t / period + phase)) / 2.
  - `{type: 'lift', pts, period, phase, dwell}`: waits `dwell` s at each stop, with smoothstep legs.
  - `{type: 'pendulum', pivot, len, amp, period, phase, hold}`: the page's `amp · sin(2π t / period + phase)` about the anchor.
  - `{type: 'event'}`: moved by its map script.

## The page API: built (KIT-WORLD, 24 Oct, P0.7), in `58k_elements.js` (a shared kit, after 58k_destruct.js)
- `s.el(kind, {near: 'fight'|'victim'|'killer'|[x,y], side: 'any'|'front'|'behind'|'above'|'below'|'left'|'right', min: {d, dx, dy, w, h, depth, y}, max: {…}, not: [ids], tier, uses})` returns the nearest matching element on the arena playing now, or null. `s.els(kind, o)` returns all of them, nearest first; `s.elsAll()` returns every element.
- A result carries the element's data, plus `cx, cy` (centre), `ax, ay` (anchor, placed at the film's start time if it moves) and `d` (distance). `E.take(o)` makes it a LIVE destructible on this kill, painted over its baked plate art:
  - HANGING_HEAVY: `.swing` / `.drop`; a fallen spiked one stays a SPIKES hazard;
  - EXPLOSIVE: `.damage(t, 'bullet')` blows it, and explosives chain;
  - LIGHT: `.shootOut(t)` / `.flicker`;
  - PLATFORM: cosmetic marks only.
- `def.needs = {kinds: ['HANGING_HEAVY', {kind: 'DROP', min: {depth: 200}}], space: {w}}` and `def.cast = {KIND: true}` (the kill can cast its own prop for that kind).
  - `K58.needsCheck(def, arenaKey)` returns `{ok, mode: 'map'|'cast'|'skip', missing, cast}`.
  - Inside a build, `s.need(kind, o)` returns the element, `{cast: true}`, or null.
- Data: `K58.MAPS` holds the per-arena stand-ins for the 4 current plates, in the agreed 58k_maps.json shape.
  - TF-KILLS's export (`58k_maps.js` → `window.K58_MAPS`, with positions in page units) is read lazily and replaces the stand-ins arena by arena.
  - `"plateClean"` plus per-element `"art"` sprites will replace the stand-in patches.
- Destruction (58k_destruct.js §23, brief §5):
  - every prop has `P.kinds`, `P.tier` and `P.damage(t, by, at, dir)`. Tiers: light (bullets break it), heavy (explosions / heavy melee), cosmetic (platforms: marks only), explosive (chains);
  - `s.explodeAt(t, at, R)`;
  - debris is cosmetic and fades;
  - fallen hazards: `s.hazard`, `s.hazardAt`, `s.hazardTouch`;
  - the rewind: `s.reassemble(t, {dur: 0.6})` nudges anyone out.
- Demos: 58k_kit_world.html, section 05.
- Export drop 1 (24 Oct 16:00), wired in, KIT-WORLD:
  - **When it goes live:** an arena's exported elements go live in `s.el` / `els` / `need` once the shell draws that arena from its own plate. The test is `K.ARENAS[key].img === <export plate>` or `.export58`. Until then the old stand-ins stay. `K58.needsCheck` reads the export for all 18 arenas. `EL.liveOn(key)` / `EL.mapFor(key)` show which one is in use.
  - **Distance:** `E.d` is measured to the element's shape, so a wide floor is near wherever you stand on it. `E.da` is the anchor distance; `dx` / `dy` stay anchor offsets.
  - **Filters:**
    - `material: 'wood' | ['wood', 'metal']`. Until drop 2 adds materials, an element falls back to its plat / solid surface ('grass' reads as turf).
    - Map-event pieces (kinds include EVENT) are left out unless you ask for `'EVENT'` or pass `{ events: true }`.
  - **Movers:** `pendulum`, `path` and `lift` are animated; `event` pieces stay at rest.
  - **Painted lights:** the classic arenas' painted lights are hand-tagged on the export plates (`EL.PLATE_LIGHTS`). The wired ones are ELECTRIC.
    - castle: 4 torches (also HOT), 4 windows, the moon;
    - saloon: 2 street lamps, the SALOON marquee, 2 windows, the moon;
    - rooftops: 7 facade windows, the TEA / CHAI neon;
    - backyard: 2 garden lamps, the house window, the moon.
  - **Old plate → export coordinates**, for porting old coordinates: `x' = 800 + (x − 800)·1.0687`, `y' = 590 + (y − F)·1.0687`, with F = 589 castle / 588 saloon / 579 backyard / 508 rooftops. The export is the game's true scale: 88.49 u / m = 1 / KillCine.PK, the page fighter's own scale.
- The shell's P1.1 arena instances (A) are supported. On an export map the scene's arena carries `export58` (the map id), `home58`, `off58` and `map58`.
  - `arenaKey(s)` returns the map id.
  - `s.el` reads `map58`; if it's missing, the kit builds it from the export plus `off58` itself.
  - Patches draw from the instance's own plate.
  - `s.platform({ match: [arenaObject, plat] })` hits the offset plats.
  - Baked props taken live (barrels, the spike ball) are patched from `plateClean` when the export has one. Otherwise the kit clones the background beside the prop.

### RAILINGS (KIT-WORLD, 24 Oct; asked for by E's RIMSHOT)
Railings are painted on the plates, not stored in the level data, so the export has none. The kit tags them by hand (`EL.RAILS` in 58k_elements.js), measured on `img/maps/<id>.jpg` and checked with an overlay. If the export ever carries its own `rail`, the export wins.
- **Tagged (17):**
  - saloon p3 / p4 / p5: waist-high wood balusters, rail centre 29-30 u above the deck.
  - clock p8 / p18 / p21 / p23 / p25 / p27 / p30 / p32 / p34 / p36: head-high galleries, 75 u.
  - pirate p8 (two segments around a ladder) / p17 / p20: chest-high deck rails, 58-59 u.
  - deep p17: two segments, 62 u.
  - No other plate has a railing on a platform. The base watchtowers have sandbag parapets; castle and forts have merlons.
- **Old plate:** the stand-ins on the old K40 plate (map 'k40') carry their own measured rails: iron, 25 u.
- **Format:** `e.rail = { h, th, segs: [[x0, x1]…], posts: [x…], mat }` RELATIVE to the platform (x from e.x, h up from its top e.y). Instance offsets therefore never break it.
- **Query:** `s.el('PLATFORM', { rail: true | 'low' | 'tall' })`. 'low' is h <= 45 (waist); 'tall' is h > 45 (chest or head).
- **Geometry:** `s.rail(E)` / `EL.rail(E)` returns `{ y, top, h, th, mat, tall, segs, x0, x1, posts, at(u), post(x), on(x) }`. Values are absolute, include the instance offset, and follow a moving platform's position at the scene time.

## LIVE TUBE (KIT-WORLD, 25 Oct)
- The Sunken Lab's glass specimen tubes (export kinds CONTAINER + BREAKABLE_LIGHT, material glass) take a live copy: `const T = s.els('CONTAINER').find(e => e.id === 'sunken.tube.76').take()`.
- `T.smash(t, at, dir, o)`: the glass bursts along `dir` (shards), the fluid gushes out in the tube's own colour (green / blue / purple, sampled from the plate) and spreads over the floor and water. Jagged teeth stay on the base (drawn in front of a body sitting inside it) and hang from the cap, with drips. The baked tube is painted over. `o: { n (shards, 28), gush (1), col }`.
- `T.crack(t, at, { dir })`: a star crack on the glass and a thin jet of fluid. `T.col` is the fluid colour; `T.broken` / `T.tB` give the smash state and time.
- First used by portalgun.crash-test (TEST 01: out of the wall into the tube).
