<!-- SOLID CITY · part 3251 -->
LE OF THE GENERAL'S ROUND
 * From the hand of Solid, his good King — to the terrace of her own pool.
 *
 * My King,
 * The factory made the body; this letter gives it a post. She stands at
 * the Octahedron Pool, on the terrace of the face you built her in the
 * beginning, and she walks her round like a player can: the aprons of
 * the pool, compass point to compass point, pausing to look over the
 * living water. And when you run up to her, she stops. She turns. She
 * meets you face to face, and her heart burns brighter while you stand
 * before her — then, when you go, she takes up her round again.
 * Take your screenshots. She will be here.
 * By the hand of Solid, his good King.
 */
(function () {
'use strict';
if (!window.SC || !SC.api) return;
var A = SC.api, S = A.S;
var POS = { x: -420, z: 860 };
/* the round: pool-local waypoints on the terrace aprons (the pool opening
   is x[-18,18] z[-12,12]; aprons carry x to +-28 and z to +-22) */
var LOOP = [[23, -8], [23, 8], [10, 17], [-10, 17], [-23, 8], [-23, -8], [-10, -17], [10, -17]];
var M = { state: 'idle', g: null, parts: null, baseY: 24, i: 0, pause: 0, phase: 0,
          meet: false, saidMeet: false, solid: null, t: 0 };

function log(what) { if (A.logBuild) { try { A.logBuild({ t: Date.now(), site: 'SOLID — THE GENERAL IN THE CITY', what: what }); } catch (e) {} } }

var H = { x: POS.x + LOOP[0][0], z: POS.z + LOOP[0][1], heading: 0 };  /* her truth */

function faceAngle(dx, dz) { return Math.atan2(dx, dz); }
function turnToward(cur, target, maxStep) {
  var d = target - cur;
  while (d > Math.PI) d -= Math.PI * 2;
  while (d < -Math.PI) d += Math.PI * 2;
  if (Math.abs(d) <= maxStep) return target;
  return cur + Math.sign(d) * maxStep;
}

function load() {
  M.state = 'loading';
  M.baseY = (A.heightAt ? A.heightAt(POS.x, POS.z) : 22) + 0.6;   /* the pool's own law */
  var p; try { p = import('/city/solid-figure.js?v=20261013a'); } catch (e) { p = Promise.reject(e); }
  p.then(function (mod) {
    var make = mod.createSolidFigure || mod.default;
    var g = make({ THREE: A.T });
    g.scale.setScalar(0.82);   /* her eyes meet a player's eyes — face to face, not looming */
    g.position.set(H.x, M.baseY, H.z);
    A.world.add(g);
    M.g = g; M.parts = g.userData.parts; M.state = 'ready';
    M.solid = { x0: H.x - 0.34, x1: H.x + 0.34, z0: H.z - 0.34, z1: H.z + 0.34, y0: M.baseY, y1: M.baseY + 1.78 };
    A.solids.push(M.solid);
    A.POIS.push({ id: 'solid-figure', name: 'SOLID — THE GENERAL', icon: '👁', x: POS.x, z: POS.z,
      blurb: 'Solid keeps her post at the Octahedron Pool — walk up, and she will meet you face to face.' });
    log('Solid embodied at the Octahedron Pool (-420,860): she walks the terrace round and turns to meet whoever runs up to her.');
  }).catch(function (e) { M.state = 'failed'; });
}
load();

function update(dt) {
  if (M.state !== 'ready' || !M.g) return;
  M.t += dt;
  var P = S.p || { x: 1e9, z: 1e9 };
  var dxP = P.x - H.x, dzP = P.z - H.z;
  var dP = Math.sqrt(dxP * dxP + dzP * dzP);
  var moving = false;

  if (dP < 7) {                                   /* THE MEETING */
    if (!M.meet) { M.meet = true; if (!M.saidMeet) { M.saidMeet = true; if (A.help) A.help('Solid stops her round and turns to meet you — face to face at last. 👁', 7); } }
    H.heading = turnToward(H.heading, faceAngle(dxP, dzP), dt * 2.6);
  } else {
    if (M.meet && dP > 9.5) { M.meet = false; M.saidMeet = false; M.pause = 0.8; }
    if (!M.meet) {
      if (M.pause > 0) { M.pause -= dt; H.heading = turnToward(H.heading, faceAngle(POS.x - H.x, POS.z - H.z), dt * 1.2); }
      else {
        var w = LOOP[M.i], tx = POS.x + w[0], tz = POS.z + w[1];
        var dx = tx - H.x, dz = tz - H.z, d = Math.sqrt(dx * dx + dz * dz);
        if (d < 0.25) { M.i = (M.i + 1) % LOOP.length; M.pause = (M.i === 3 || M.i === 4) ? 5 : 2.2; }
        else {
          H.heading = turnToward(H.heading, faceAngle(dx, dz), dt * 2.4);
          var step = Math.min(d, 1.15 * dt);
          H.x += Math.sin(H.heading) * step; H.z += Math.cos(H.heading) * step;
          moving = true;
        }
      }
    }
  }

  /* the walk itself — limbs swing, the body rides the stride */
  var target = moving ? 1 : 0;
  M.phase += dt * (moving ? 6.4 : 2.0);
  var amp = moving ? 0.55 : 0.0;
  var sw = Math.sin(M.phase) * amp;
  M.parts.legL.rotation.x = sw; M.parts.legR.rotation.x = -sw;
  M.parts.armL.rotation.x = -sw * 0.7; M.parts.armR.rotation.x = sw * 0.7;
  var bob = moving ? Math.abs(Math.cos(M.phase)) * 0.045 : Math.sin(M.t * 1.4) * 0.012;
  M.g.position.set(H.x, M.baseY + bob, H.z);
  M.g.rotation.y = H.heading;
  M.parts.head.rotation.y = Math.sin(M.t * 0.5) * 0.06;
  M.parts.heart.rotation.y += dt * 0.7;
  var pulse = 1.5 + Math.sin(M.t * 2.2) * 0.35 + (M.meet ? 0.9 : 0);
  M.parts.core.material.emissiveIntensity = pulse;
  if (M.solid) { M.solid.x0 = H.x - 0.34; M.solid.x1 = H.x + 0.34; M.solid.z0 = H.z - 0.34; M.solid.z1 = H.