<!-- SOLID CITY · part 2874 -->
= opts.createHero || null;
    var group = new T.Group(); group.name = 'the-population';
    var walkers = [], standers = [], census = { total: 0, forge: 0, plate: 0, simple: 0, shade: 0, meshes: 0, tris: 0, forgeFailed: false };

    function lam(c, e) { return new T.MeshLambertMaterial({ color: c, emissive: e || 0x000000 }); }
    function countTris(g) {
      var m = 0, tr = 0;
      g.traverse(function (o) {
        if (o.isMesh) {
          m++;
          var geo = o.geometry;
          if (geo) tr += Math.round((geo.index ? geo.index.count : (geo.attributes.position ? geo.attributes.position.count : 0)) / 3);
        }
      });
      census.meshes += m; census.tris += tr;
    }
    function nameplate(name, sub, color) {
      var cv = document.createElement('canvas'); cv.width = 512; cv.height = 128;
      var ctx = cv.getContext('2d');
      try {
        ctx.fillStyle = 'rgba(8,8,14,0.55)'; ctx.beginPath(); ctx.arc(256, 52, 6, 0, 6.29); ctx.fill();
        ctx.font = '600 44px Georgia, serif'; ctx.textAlign = 'center';
        ctx.fillStyle = color || '#f2e8d5'; ctx.fillText(name, 256, 58);
        ctx.font = '26px Georgia, serif'; ctx.fillStyle = 'rgba(220,225,235,0.85)';
        ctx.fillText(sub, 256, 100);
      } catch (e) {}
      var sp = new T.Sprite(new T.SpriteMaterial({ map: new T.CanvasTexture(cv), depthTest: true, transparent: true }));
      sp.scale.set(3.1, 0.78, 1); sp.position.y = 2.35; sp.name = 'nameplate';
      return sp;
    }

    /* ——— SIMPLE FOLK: the house figure, limbs on pivots ——— */
    function simpleFolk(cfg) {
      var g = new T.Group();
      var cloth = lam(cfg.cloth), skin = lam(cfg.skin), hairM = lam(cfg.hair), gold = lam(0xd8a833, 0x2a1a04);
      function limb(mat, w, h, d, px, py) {
        var j = new T.Group(); j.position.set(px, py, 0);
        var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.y = -h / 2; j.add(m); g.add(j); return j;
      }
      var legL = limb(cloth, 0.16, 0.78, 0.17, -0.11, 0.80), legR = limb(cloth, 0.16, 0.78, 0.17, 0.11, 0.80);
      var body = new T.Mesh(new T.BoxGeometry(0.50, 0.62, 0.28), cloth); body.position.y = 1.11; g.add(body);
      var belt = new T.Mesh(new T.BoxGeometry(0.52, 0.06, 0.30), gold); belt.position.y = 0.83; g.add(belt);
      var armL = limb(cloth, 0.11, 0.62, 0.12, -0.315, 1.40), armR = limb(cloth, 0.11, 0.62, 0.12, 0.315, 1.40);
      var head = new T.Mesh(new T.SphereGeometry(0.155, 12, 10), skin); head.position.y = 1.60; head.scale.set(0.92, 1.05, 0.96); g.add(head);
      var cap = new T.Mesh(new T.SphereGeometry(0.16, 12, 8, 0, Math.PI * 2, 0, Math.PI / 2), hairM); cap.position.y = 1.635; g.add(cap);
      g.userData.limbs = [armL, legL, armR, legR];
      return g;
    }

    /* ——— THE SHADE: a lathe robe, a fresnel ghost ——— */
    function shadeFigure() {
      var g = new T.Group();
      var pts = [];
      [[0.02, 0], [0.30, 0.02], [0.27, 0.45], [0.20, 0.95], [0.155, 1.32], [0.05, 1.42]].forEach(function (p) { pts.push(new T.Vector2(p[0], p[1])); });
      var robeMat = lam(0x1a1626);
      robeMat.onBeforeCompile = function (sh) {
        var inj = 'float fresK = pow(1.0 - abs(dot(normalize(normal), normalize(vViewPosition))), 2.2);\n outgoingLight += vec3(0.42, 0.48, 1.0) * fresK * 0.85;\n';
        var fs = sh.fragmentShader;
        if (fs.indexOf('#include <output_fragment>') >= 0) sh.fragmentShader = fs.replace('#include <output_fragment>', inj + '#include <output_fragment>');
        else if (fs.indexOf('#include <opaque_fragment>') >= 0) sh.fragmentShader = fs.replace('#include <opaque_fragment>', inj + '#include <opaque_fragment>');
      };
      robeMat.customProgramCacheKey = function () { return 'the-shade'; };
      var robe = new T.Mesh(new T.LatheGeometry(pts, 14), robeMat); g.add(robe);
      var head = new T.Mesh(new T.SphereGeometry(0.13, 12, 10), lam(0x0d0b14)); head.position.y = 1.52; g.add(head);
      [-1, 1].forEach(function (sd) {
        var eye = new T.Mesh(new T.SphereGeometry(0.016, 6, 5), new T.MeshBasicMaterial({ color: 0x9fd4ff }));
        eye.position.set(sd * 0.05, 1.54, 0.115); g.add(eye);
      });
      return g;
    }

    function addFigure(kind, fig, spot) {
      fig.position.set(spot.x, spot.y, spot.z);
      if (spot.face != null) fig.rotation.y = spot.face;
      group.add(fig); countTris(fig);
      census.total++; census[kind]++;
      if (spot.plateName) fig.add(nameplate(spot.plateName, spot.plateSub || '', spot.plateColor));
      if (spot.walk) {
        walkers.push({ g: fig, kind: kind, cx: spot.walk.cx, cz: spot.walk.cz, r: spot.walk.r, a: spot.walk.a0 || 0, dir: spot.walk.dir || 1, speed: spot.walk.speed || 1.35, fixedY: spot.walk.fixedY, phase: Math.random() * 6.28 });
      } else {
        standers.push({ g: fig, kind: kind, face: spot.face || 0, baseY: spot.y, phase: Math.random() * 6.28, hero: spot.hero || null });
      }
      return fig;
    }

    function forgeDesc(o) {
      return Ob