<!-- NEW2 — TEST 2 · THE DISTRICT OF 800 · part 442 -->
cene.add(new THREE.HemisphereLight(0xbdd3ff, 0x1c241c, 0.85));
  var sun = new THREE.DirectionalLight(0xfff1d6, 1.6);
  sun.position.set(size * 0.45, size * 0.7, size * 0.25);
  scene.add(sun);

  /* --- 1. THE MAP FLOOR --------------------------------------------- */
  var floor = new THREE.Mesh(
    new THREE.PlaneGeometry(size, size),
    new THREE.MeshStandardMaterial({
      map: makeFloorTexture(THREE, size),
      roughness: 0.96,
      metalness: 0.0
    })
  );
  floor.rotation.x = -Math.PI / 2;
  floor.position.y = 0;
  floor.name = 'MAP_FLOOR';
  scene.add(floor);

  /* --- 2. THE STAND LAYER ------------------------------------------- */
  /* Invisible on purpose. Standing is resolved by the groundY()
   * contract below — never by raycast, never by decorative geometry —
   * so a character's feet have one law and it cannot be broken by a
   * badly placed floor tile. */
  var standLayer = new THREE.Mesh(
    new THREE.PlaneGeometry(size, size),
    new THREE.MeshBasicMaterial()
  );
  standLayer.rotation.x = -Math.PI / 2;
  standLayer.position.y = STAND_Y;
  standLayer.visible = false;
  standLayer.name = 'STAND_LAYER';
  scene.add(standLayer);

  function groundY(/* x, z */) { return STAND_Y; }

  /* --- 3. THE CAMERA RIG -------------------------------------------- */
  /* Anti-incursion fences (the King's word: keep the sight honest).
   *  - polar angle: never near-horizontal (would slice through towers
   *    or under the floor), never a dead top-down stare.
   *  - distance: never so close the frame is inside one building,
   *    never so far the district shrinks and void takes the frame.
   *    The fence is a share of the stage size, so at district scale
   *    the sky view still frames the whole district at once.
   *  - target: locked within a whisper of the district center.
   *  - absolute floor: camera height can never go below MIN_CAM_Y. */
  var LIMITS = {
    minPolar: 0.30,                 /* rad from vertical  (~17 deg) */
    maxPolar: 1.02,                 /* rad from vertical  (~58 deg) */
    minDist: size * 0.55,           /* 1430 at default size */
    maxDist: size * 1.12,           /* 2912 at default size */
    targetRadius: size * 0.03,      /* target may breathe with the stage */
    minCamY: 12
  };

  var camera = new THREE.PerspectiveCamera(
    opts.fov || 50, 1, 0.5, size * 6
  );

  var rig = {
    azimuth: (opts.azimuth != null) ? opts.azimuth : -0.65,
    polar: 0.62,
    dist: size * 1.04,
    orbitSpeed: (opts.orbitSpeed != null) ? opts.orbitSpeed
                                          : (Math.PI * 2) / 300,
    target: new THREE.Vector3(0, 0, 0)
  };

  function placeCamera(t) {
    /* gentle drift: a slow orbit, a slow breathing of height/reach */
    var polar = clamp(
      rig.polar + Math.sin(t * 0.045) * 0.05,
      LIMITS.minPolar, LIMITS.maxPolar);
    var dist = clamp(
      rig.dist + Math.sin(t * 0.03 + 1.7) * size * 0.035,
      LIMITS.minDist, LIMITS.maxDist);

    /* target breathes, fenced to a small disc around the center */
    var tx = Math.sin(t * 0.021) * LIMITS.targetRadius;
    var tz = Math.cos(t * 0.017) * LIMITS.targetRadius;
    rig.target.set(tx, 0, tz);

    var sp = Math.sin(polar), y = Math.cos(polar);
    camera.position.set(
      rig.target.x + dist * sp * Math.sin(rig.azimuth),
      dist * y,
      rig.target.z + dist * sp * Math.cos(rig.azimuth)
    );
    if (camera.position.y < LIMITS.minCamY) {
      camera.position.y = LIMITS.minCamY;
    }
    camera.lookAt(rig.target.x, 0, rig.target.z);
  }

  function setAspect(w, h) {
    if (h > 0) { camera.aspect = w / h; camera.updateProjectionMatrix(); }
  }
  if (renderer && renderer.domElement) {
    var el = renderer.domElement;
    setAspect(el.clientWidth || window.innerWidth,
              el.clientHeight || window.innerHeight);
  } else if (typeof window !== 'undefined') {
    setAspect(window.innerWidth, window.innerHeight);
  }

  placeCamera(0);

  function update(dt, t) {
    rig.azimuth += rig.orbitSpeed * dt;
    placeCamera(t);
  }

  function getCamera() { return camera; }

  /* --- birth certificate -------------------------------------------- */
  memoryLog(site, 'stage born: map floor ' + size + 'x' + size +
    ', stand layer at y=' + STAND_Y +
    ', camera rig fenced (polar ' + LIMITS.minPolar + '-' +
    LIMITS.maxPolar + ' rad, dist ' +
    Math.round(LIMITS.minDist) + '-' + Math.round(LIMITS.maxDist) + ')');

  return {
    scene: scene,
    floor: floor,
    standLayer: standLayer,
    standY: STAND_Y,
    groundY: groundY,
    camera: camera,
    getCamera: getCamera,
    update: update,
    setAspect: setAspect,
    limits: LIMITS,
    size: size
  };
}

/* Exports: ES module first, plain script tag as a fallback. */
if (typeof module !== 'undefined' && module.exports) {
  module.exports = { makeStage: makeStage };
}
if (typeof window !== 'undefined') {
  window.makeStage = makeStage