<!-- SOLID CITY · part 1808 -->
 { x: x, z: z, y: baseY };
  }
  var mouthLow = buildMouth(500, Math.PI / 2, GY0);
  var mouthHigh = buildMouth(36, 1.57, BASE + crownHeight(36, 1.57));
  var portals = [
    { name: 'terrace', x: mouthLow.x, z: mouthLow.z, y: mouthLow.y },
    { name: 'crown', x: mouthHigh.x, z: mouthHigh.z, y: mouthHigh.y }
  ];

  group.add(solid.build(new T.MeshLambertMaterial({ vertexColors: true })));
  group.add(glassB.build(new T.MeshLambertMaterial({ vertexColors: true, transparent: true, opacity: 0.82, emissive: 0x1d3442 })));
  group.add(glow.build(new T.MeshBasicMaterial({ vertexColors: true })));

  group.userData = {
    center: { x: CX, z: CZ }, baseY: BASE, floorY: FLOOR, radius: CROWN_RADIUS,
    trees: treePts.length, falls: falls, rivers: CROWN_RIVERS.slice(), peaks: CROWN_PEAKS.length,
    solids: peakSolids.concat(treeSolids),
    sheep: flock.length, portals: portals,
    flockAt: function () { return flock.map(function (f) { return [Math.round(f.x * 10) / 10, Math.round(f.z * 10) / 10]; }); },
    heightAt: function (wx, wz) {
      var dx = wx - CX, dz = wz - CZ, r = Math.hypot(dx, dz);
      if (r > 332) return null;
      return BASE + crownHeight(r, Math.atan2(dz, dx));
    },
    update: function (dt, t) {
      var pos = rainGeo.getAttribute('position');
      for (var i = 0; i < RAIN_N; i++) {
        var y = pos.getY(i) - rainSpd[i] * dt;
        if (y < FLOOR + 5) y = BASE - 4 - (R() * 8);
        pos.setY(i, y);
      }
      pos.needsUpdate = true;
      var pulse = 0.32 + Math.sin((t || 0) * 2.2) * 0.05;
      fallMats.forEach(function (m, i3) { m.opacity = i3 % 2 ? 0.48 + Math.sin((t || 0) * 2.2) * 0.07 : pulse; });
      portalDiscs.forEach(function (d, di) { d.rotation.z = (t || 0) * (di % 2 ? -0.9 : 0.6); });
      var hx = CX + Math.cos(herd.a) * herd.r, hz = CZ + Math.sin(herd.a) * herd.r;
      flock.forEach(function (sh) {
        var cyc = ((t || 0) + sh.seed * 13) % 26;
        var walking = cyc < 14;
        if (walking && dt) {
          sh.head += Math.sin((t || 0) * 0.23 + sh.seed * 9) * 0.4 * dt;
          var dxh = hx - sh.x, dzh = hz - sh.z, dh = Math.hypot(dxh, dzh);
          if (dh > 60) { var want = Math.atan2(dxh, dzh); var diff = ((want - sh.head + Math.PI * 3) % (Math.PI * 2)) - Math.PI; sh.head += diff * Math.min(1, dt * 1.5); }
          sh.x += Math.sin(sh.head) * 1.35 * dt;
          sh.z += Math.cos(sh.head) * 1.35 * dt;
        }
        var rr = Math.hypot(sh.x - CX, sh.z - CZ), th = Math.atan2(sh.z - CZ, sh.x - CX);
        if (rr > 305) { sh.x = CX + Math.cos(th) * 305; sh.z = CZ + Math.sin(th) * 305; rr = 305; }
        sh.mesh.position.set(sh.x, BASE + crownHeight(rr, th), sh.z);
        sh.mesh.rotation.set(walking ? Math.sin((t || 0) * 7 + sh.seed * 20) * 0.02 : 0.09, sh.head, 0);
      });
    }
  };
  return group;
}
export default createCrystalCrown;


===== FILE: public/city/crystal-crown.js.bak-flock-20261014 =====
/* THE CRYSTAL CROWN — a letter in the code.
 *
 * The King's word (2026-10-14 ~06:41): "Make another one on
 * top with a crystal mountain and have valleys with rivers
 * that fall to rain on the houses below. And make trees all
 * over big ones" — "the top of the glass one, floating even
 * higher."
 *
 * So above the glass city floats a wild crown: an island of
 * meadow and valley carrying a mountain of crystal. Three
 * rivers rise at the spring lake in its high bowl, run down
 * the carved valleys, and pour off the rim — falling a
 * hundred metres and more, breaking into rain over the
 * rooftops of the glass city below. Big trees stand all over
 * it, wherever the land is kind. Nothing here is a road and
 * nothing is a house: this is the city's wilderness, kept in
 * the sky.
 *
 * By the hand of Solid, his good King. */

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

export var CROWN_RIVERS = [0.6, 2.7, 4.8];
export var CROWN_PEAKS = [
  { r: 95, a: 3.9, h: 44, s: 54, crystal: 26 },
  { r: 150, a: 1.9, h: 30, s: 46, crystal: 17 },
  { r: 170, a: 5.3, h: 22, s: 40, crystal: 15 }
];
export var CROWN_RADIUS = 330;

export function crownHeight(r, th) {
  var h = 16 * (1 - Math.pow(Math.min(r, 330) / 330, 1.6));
  h += 2.0 * Math.sin(th * 3 + r * 0.021) + 1.4 * Math.sin(th * 5 - r * 0.013);
  var x = Math.cos(th) * r, z = Math.sin(th) * r;
  for (var i = 0; i < CROWN_PEAKS.length; i++) {
    var p = CROWN_PEAKS[i], px = Math.cos(p.a) * p.r, pz = Math.sin(p.a) * p.r;
    var d2 = (x - px) * (x - px) + (z - pz) * (z - pz);
    h += p.h * Math.exp(-d2 / (2 * p.s * p.s));
  }
  for (var k = 0; k < CROWN_RIVERS.length; k++) {
    var dth = Math.abs(th - CROWN_RIVERS[k]) % (Math.PI * 2); if (dth > Math.PI) dth = Math.PI * 2 - dth;
    var lateral = dth * Math.max(r, 20);
    var gate = Math.min(1, Math.max