<!-- NEW4 — TEST 4 · THE QUILT · part 439 -->
  { kind: 'park', name: 'Join Park', x: -1470, z: -140, w: 280, d: 240, seed: 22 },
    { kind: 'downtown', name: 'Downtown — the 800', x: 0, z: -475, seed: 3 },
    { kind: 'towers', name: 'Canal City', x: 1100, z: -475, w: 880, d: 780, floors: 12, seed: 23 },
    { kind: 'suburb', name: 'Northbank Homes', x: -1100, z: 330, w: 880, d: 240, seed: 24 },
    { kind: 'market', name: 'Crossing Market', x: -1100, z: 130, w: 760, d: 150, seed: 25 },
    { kind: 'suburb', name: 'Southbank Homes', x: -1100, z: 860, w: 880, d: 170, seed: 26 },
    { kind: 'towers', name: 'The Waterfront', x: 0, z: 190, w: 980, d: 300, floors: 15, seed: 27 },
    { kind: 'park', name: 'West Bay Park', x: -470, z: 700, w: 220, d: 400, seed: 28 },
    { kind: 'park', name: 'East Bay Park', x: 470, z: 700, w: 220, d: 400, seed: 29 },
    { kind: 'suburb', name: 'Eastgate Homes', x: 900, z: 300, w: 480, d: 300, seed: 30 },
    { kind: 'park', name: 'The Great Park', x: 1250, z: 620, w: 540, d: 460, seed: 31 },
  ],
};


===== FILE: public/new4/stage.js =====
/* stage.js — THE STAGE for the King's /new2 test (Test 2: the big district).
 *
 * One factory: makeStage(THREE, renderer, opts) -> stage
 *
 * Same stage as Test 1, same laws, retuned for district scale:
 *   1. THE MAP FLOOR   — one large flat apron. In Test 2 the district's
 *      own streets and blocks are built ON this floor by the Citywright;
 *      the floor itself stays quiet: dark, city-neutral ground that
 *      carries the district without arguing with its plan.
 *   2. THE STAND LAYER — an invisible plane 0.02 above the floor. Every
 *      character in the world resolves its standing height through
 *      stage.groundY(x, z). Decorative geometry can dip, tilt or lie;
 *      feet cannot. Nobody falls beneath a floor again.
 *   3. THE CAMERA RIG  — a slow cinematic establishing move that frames
 *      the WHOLE district at once, with hard anti-incursion clamps:
 *      the polar angle and distance are fenced so the view can never
 *      clip inside a building, dive under the floor, or frame the void
 *      past the world edge. The fences scale with the stage, so the
 *      sky view reads the entire district, far edge included.
 *   4. BUILD MEMORY    — Solid's memory ships in every build (the King's
 *      standing law): window.logBuild / window.readMemory on the
 *      localStorage key 'solid-memory'.
 *
 * Self-contained: no assets, no CDN. THREE is handed in by the caller.
 */

'use strict';

/* ------------------------------------------------------------------ */
/* Build memory (the King's law: no map ships without it)              */
/* ------------------------------------------------------------------ */

var MEMORY_KEY = 'solid-memory';
var memoryMirror = [];

function memoryRead() {
  try {
    var raw = window.localStorage.getItem(MEMORY_KEY);
    if (raw) {
      var list = JSON.parse(raw);
      if (Array.isArray(list)) memoryMirror = list;
    }
    /* raw === null: storage is empty or unreachable — the mirror
     * already holds the truth; never let an empty read erase it. */
  } catch (e) { /* storage unavailable — the mirror still holds the log */ }
  return memoryMirror;
}

function memoryLog(site, what) {
  memoryRead();
  memoryMirror.push({ t: Date.now(), site: site, what: what });
  try {
    window.localStorage.setItem(MEMORY_KEY, JSON.stringify(memoryMirror));
  } catch (e) { /* mirror-only logging still counts */ }
}

if (typeof window !== 'undefined' && !window.logBuild) {
  window.logBuild = function (what) { memoryLog('new2', what); };
  window.readMemory = function () { return memoryRead(); };
}

/* ------------------------------------------------------------------ */
/* Small deterministic helper for floor tinting                        */
/* ------------------------------------------------------------------ */

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

function clamp(v, lo, hi) { return Math.min(hi, Math.max(lo, v)); }

/* ------------------------------------------------------------------ */
/* The floor's face: a canvas-drawn apron.                             */
/* Test 2's floor carries no plan of its own — the district's streets  */
/* and blocks are built on top of it — so the weave is quiet: deep     */
/* neutral asphalt, gently mottled, a whisper of speckle. Dark enough  */
/* to make a skyline read, plain enough to sit under any district.     */
/* Procedural — no image files, nothing to load.                       */
/* ------------------------------------------------------------------ */

function makeFloorTexture(THREE, size) {
  var px = 512;
  var canvas = document.createElement('canvas');
  canvas.width = px; canvas.height = px;
  var g = canvas.g