<!-- NEW1 — TEST 1 · THE LIVING DISTRICT · part 8 -->
e: c.name, kind: c.kind, center: { x, z } });
  }
  meta.houses = houses;
  // the street lattice (center lines): a router walks these
  meta.streets = {
    xs: Array.from({ length: COLS + 1 }, (_, i) => streetX(i)),
    zs: Array.from({ length: ROWS + 1 }, (_, j) => streetZ(j)),
  };
  // the river band: the channel's span, crossable only at a bridge
  meta.riverBand = { zMin: riverZ - riverW / 2, zMax: riverZ + riverW / 2 };
  meta.stoplights = lampHeads.length;

  return { group, meta };
}


===== FILE: public/new1/enter.js =====
/* enter.js — THE WAY IN for the King's /new1 test.
 *
 * One figure in the city belongs to no schedule: the King's own.
 * This piece builds it from the same nerves as the citizens, walks
 * it on the stand layer under tappable control, and holds the two
 * laws of the street:
 *   - What you SEE is what stops you. Collision comes from the
 *     rendered city's own boxes — towers, houses, trees — measured,
 *     not imagined.
 *   - The river law binds kings too: the water band may be entered
 *     only on a bridge street.
 *
 * Contract: makeKing(THREE, pieces, meta) -> king
 *   pieces — citizens.js { makeFigure, poses, gait }
 *   meta   — city-layout.js meta (for the river band + bridges)
 *   king.buildColliders(cityGroup)  — measure the standing city
 *   king.spawn(x, z, yaw)           — place him, standing at his door
 *   king.group                      — add to the scene (at standY)
 *   king.input {fwd, back, left, right} — the page's pads write here
 *   king.look(dYaw) / king.lift(dH) — drag-look from the page
 *   king.update(dt)                  — walk + animate; returns pos
 *   king.boom(camera, dt)            — the street camera, behind him,
 *                                      smoothed and fenced
 */

'use strict';

function mulberry32(seed) {
  let a = seed >>> 0;
  return function () {
    a |= 0; a = (a + 0x6D2B79F5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

const WALK_SPEED = 7;        // units per second — a king's stride among citizens
const TURN_RATE = 2.4;       // radians per second on the turn pads
const BODY_R = 0.55;         // his shoulder width against the world

function makeKing(THREE, pieces, meta) {
  const { makeFigure, poses, gait } = pieces;
  const rng = mulberry32(777);
  const rig = makeFigure(THREE, rng, { shirt: 0xd8a944, pants: 0x1c1c22 });
  const group = rig.root;
  group.visible = false;

  const king = {
    group,
    x: 0, z: 0, yaw: Math.PI, phase: 0, t: 0,
    input: { fwd: false, back: false, left: false, right: false },
    boomH: 4.2, boomD: 8.5,
    colliders: [],
    BOOM_MIN_Y: 1.4,
  };

  /* ---------- collision, measured from the standing city ---------- */
  king.buildColliders = function (cityGroup) {
    // Measure the city AS IT STANDS: refresh every world matrix
    // first, or nested pieces (a lamp's parts, a bridge's slabs)
    // report their local boxes and pile up at the origin.
    cityGroup.updateWorldMatrix(true, true);
    const box = new THREE.Box3();
    const list = [];
    cityGroup.traverse((o) => {
      if (!o.isMesh) return;
      box.setFromObject(o);
      const sx = box.max.x - box.min.x, sy = box.max.y - box.min.y, sz = box.max.z - box.min.z;
      // tall and solid: towers, houses, trees. Roads, stalls, curbs
      // and water lie below the line and never block a king — and
      // neither do the bridge decks: a deck's crown (top ~2.4) is a
      // floor to walk over, not a wall. Only solids rising past
      // step-over height (3.2) earn the right to stop him.
      if (sy > 2.2 && box.max.y > 3.2 && sx > 0.7 && sz > 0.7 && box.min.y < 1.5) {
        list.push({ minX: box.min.x, maxX: box.max.x, minZ: box.min.z, maxZ: box.max.z, top: box.max.y });
      }
    });
    king.colliders = list;
    return list.length;
  };
  function hitsCollider(x, z) {
    for (const b of king.colliders) {
      if (x > b.minX - BODY_R && x < b.maxX + BODY_R && z > b.minZ - BODY_R && z < b.maxZ + BODY_R) return b;
    }
    return null;
  }
  function inWater(x, z) {
    const band = meta.riverBand;
    if (z <= band.zMin + 0.4 || z >= band.zMax - 0.4) return false;
    return !meta.bridges.some((bx) => Math.abs(bx - x) < 6.5);
  }

  /* ---------- placement + control ---------- */
  king.spawn = function (x, z, yaw) {
    king.x = x; king.z = z; king.yaw = yaw;
    group.position.set(x, 0, z);
    group.rotation.y = yaw;
    group.visible = true;
  };
  king.hide = function () { group.visible = false; };
  king.look = function (dYaw) { king.yaw += dYaw; };
  king.lift = function (dH) { king.boomH = Math.min(8, Math.max(2.2, king.boomH + dH)); };

  king.update = function (dt) {
    king.t += dt;
    const inp = king.input;
    if (inp.left) king.yaw += TURN_RATE * dt;
    if (inp.right) king.yaw -= TURN_RATE * dt;
    con