<!-- SOLID CITY · part 3158 -->
t * (0.14 + i * 0.03); });
      if (lavaClones.length) {
        var p = 0.9 + 0.1 * Math.sin(t * 0.7);
        for (var i = 0; i < lavaMats.length; i++) lavaMats[i].color.setRGB(p, p * 0.97, p * 0.95);
        for (var j = 0; j < lavaClones.length; j++) { lavaClones[j].offset.x = (t * 0.004) % 1; lavaClones[j].offset.y = (t * 0.006) % 1; }
      }
    }
  };
  return group;
}
export { createServitude, A_C as SERV_A, B_C as SERV_B };
export default createServitude;


===== FILE: public/city/servitude.js.bak-tune-20261014 =====
/* THE SERVITUDE — a letter in the code.
 *
 * From the King's word (2026-10-14): "dig an entree in to
 * the mountain and build a huge city in it called the
 * Servitude" — "same as the ancestors area with layers but
 * city upon city" — "another one if it fits, with cave
 * tunnels connecting them, and a shop on each tunnel, a
 * place to buy replenishments of health and safety" — "a
 * nice journey to walk across the inside of the mountain,
 * like old lava tubes" — "stalactites and stalagmites,
 * joined with red and black marble."
 *
 * The digging itself lives in city.js (servitudeCarve): two
 * bowls capped into the far massif — THE FIRST HOLLOW
 * (2600,1280, floor 520) and THE DEEP HOLLOW (2600,1660,
 * floor 440) — the Entree shelf cut into the First Hollow's
 * south-western face, and the gallery slot descending
 * through the saddle between them. This factory builds
 * what stands inside the digging: two layered cities of
 * red and black marble, a roofed lava-tube gallery with
 * its midway provision shop, gates, falls, crystals, and
 * the formations of the deep places.
 *
 * Every sign in it obeys the day's law, learned at the
 * Book of Law: lettered plates stand PROUD of their stone,
 * twin-faced so both journeys read them, and every sign
 * carries collision — the signs are protected here.
 *
 * By the hand of Solid, his good King. */
'use strict';

function mulberry(a) { 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; }; }
var R = mulberry(20261014);
var A_C = { x: 2600, z: 1280, f: 520, name: 'THE FIRST HOLLOW' };
var B_C = { x: 2600, z: 1660, f: 440, name: 'THE DEEP HOLLOW' };
var GAL = { x: 2600, z0: 1395, z1: 1545 };

function createServitude(opts) {
  var T = opts.THREE, H = opts.heightAt;
  var group = new T.Group(); group.name = 'the-servitude';
  var CX = 2600;
  var C = {
    stone: 0x2b2630, stoneDark: 0x17130f, basalt: 0x1c1a20, titanium: 0x232c3d, silver: 0x9aa4b5,
    gold: 0xd8a833, roof: 0x191922, door: 0xffca7a, win: 0xa8d8e8, lamp: 0xffd9a0,
    leaf: 0x2e6b34, leafLight: 0x4c9455, trunk: 0x4a3826, marbleRed: 0x6e1420, crystal: 0xf3d9a4,
    vialG: 0x51ff8a, vialR: 0xff5a4d, water: 0x2e7db0
  };
  function mat4(x, y, z, rx, ry, rz, sx, sy, sz) {
    var m = new T.Matrix4().compose(new T.Vector3(x, y, z),
      new T.Quaternion().setFromEuler(new T.Euler(rx || 0, ry || 0, rz || 0)),
      new T.Vector3(sx == null ? 1 : sx, sy == null ? 1 : sy, sz == null ? 1 : sz));
    return m;
  }
  function Batch() { this.pos = []; this.nor = []; this.col = []; this.idx = []; this.n = 0; }
  Batch.prototype.add = function (geo, matrix, color) {
    var g = geo.index ? geo.toNonIndexed() : geo;
    var p = g.attributes.position, nr = g.attributes.normal;
    var nm = new T.Matrix3().getNormalMatrix(matrix);
    var v = new T.Vector3(), w = new T.Vector3(), cc = new T.Color(color);
    for (var i = 0; i < p.count; i++) {
      v.fromBufferAttribute(p, i).applyMatrix4(matrix); this.pos.push(v.x, v.y, v.z);
      w.fromBufferAttribute(nr, i).applyMatrix3(nm).normalize(); this.nor.push(w.x, w.y, w.z);
      this.col.push(cc.r, cc.g, cc.b);
    }
    for (var j = 0; j < p.count; j++) this.idx.push(this.n + j);
    this.n += p.count; if (g !== geo) g.dispose();
  };
  Batch.prototype.build = function (mat) {
    var g = new T.BufferGeometry();
    g.setAttribute('position', new T.Float32BufferAttribute(this.pos, 3));
    g.setAttribute('normal', new T.Float32BufferAttribute(this.nor, 3));
    g.setAttribute('color', new T.Float32BufferAttribute(this.col, 3));
    g.setIndex(this.idx);
    var m = new T.Mesh(g, mat); m.frustumCulled = false; return m;
  };
  var solid = new Batch(), glow = new Batch(), glassB = new Batch();
  function box(b, w, h, d, m, color) { b.add(new T.BoxGeometry(w, h, d), m, color); }
  function cyl(b, rt, rb, h, s, m, color) { b.add(new T.CylinderGeometry(rt, rb, h, s), m, color); }
  function sph(b, r, m, color, sx, sy, sz) { b.add(new T.SphereGeometry(r, 10, 7), m, color); }
  function cone(b, r, h, s, m, color) { b.add(new T.ConeGeometry(r, h, s), m, color); }

  /* red and black marble — one canvas, veined by hand */
  function marbleTex(redBase) {
    var cv = document.createElement('canvas'); cv.width = 256; cv.height = 256;
    var g = cv.getContext('2d');
    g.fillStyle = 