<!-- SAGA-STAGING · part 44 -->
e(vx, vz, va + Math.PI/2);
    }
    /* City residential — 8 houses */
    for(var c = 0; c < 8; c++){
      house(100 + (c-4)*20, -50 + (c%2)*30, 0);
    }

  }catch(e){ console.error(e); }
}
if(typeof buildHomes === 'function'){ try{ buildHomes(); }catch(e){ console.error(e); } }

/* FISH — life in the water. 2026-10-04. */
function buildFish(){
  if(window.STAGING_CLEAN_MAP) return; // Clean map: old builder disabled
  try{
    window._dynamics = window._dynamics || [];
    var fishMat = new THREE.MeshStandardMaterial({color: 0xff8800, roughness: 0.5});
    /* Schools in harbor and tide pools */
    var schools = [
      {x: -100, z: -100, n: 15},  /* Harbor */
      {x: 1200, z: 300, n: 10},   /* Tide pools */
      {x: 3200, z: 500, n: 20}    /* Ocean */
    ];
    for(var s = 0; s < schools.length; s++){
      (function(){
        var sx = schools[s].x, sz = schools[s].z, n = schools[s].n;
        var fishes = [];
        for(var f = 0; f < n; f++){
          var fish = new THREE.Group();
          var body = new THREE.Mesh(new THREE.ConeGeometry(0.4, 1.5, 6), fishMat);
          body.rotation.x = Math.PI/2;
          fish.add(body);
          var tail = new THREE.Mesh(new THREE.PlaneGeometry(0.8, 0.6), fishMat);
          tail.position.z = -0.8;
          fish.add(tail);
          fish.position.set(sx + (Math.random()-0.5)*20, 0.2, sz + (Math.random()-0.5)*20);
          scene.add(fish);
          fishes.push({mesh: fish, tail: tail, off: Math.random()*10});
        }
        var schoolT = Math.random() * 100;
        window._dynamics.push(function(t, dt){
          schoolT += (dt || 0.016) * 0.5;
          for(var i = 0; i < fishes.length; i++){
            var fh = fishes[i];
            /* Swim in circle */
            var a = schoolT + fh.off * 0.3;
            var tx = sx + Math.cos(a) * 12;
            var tz = sz + Math.sin(a) * 12;
            fh.mesh.position.lerp(new THREE.Vector3(tx, 0.2 + Math.sin(t*2+fh.off)*0.1, tz), 0.08);
            fh.mesh.rotation.y = Math.atan2(tx - fh.mesh.position.x, tz - fh.mesh.position.z);
            /* Tail wag */
            fh.tail.rotation.y = Math.sin(t*8 + fh.off) * 0.5;
          }
        });
      })();
    }
  }catch(e){ console.error(e); }
}
if(typeof buildFish === 'function'){ try{ buildFish(); }catch(e){ console.error(e); } }

/* BIRDS FLOCKING — life in the sky. 2026-10-04. */
function buildBirds(){
  if(window.STAGING_CLEAN_MAP) return; // Clean map: old builder disabled
  try{
    window._dynamics = window._dynamics || [];
    var birdMat = new THREE.MeshBasicMaterial({color: 0x222222});
    /* 3 flocks */
    for(var f = 0; f < 3; f++){
      (function(){
        var flock = [];
        var cx = (Math.random()-0.5) * 400;
        var cz = (Math.random()-0.5) * 400;
        var cy = 80 + Math.random() * 40;
        for(var b = 0; b < 12; b++){
          var bird = new THREE.Group();
          var body = new THREE.Mesh(new THREE.ConeGeometry(0.5, 2, 4), birdMat);
          body.rotation.x = Math.PI/2;
          bird.add(body);
          var wingL = new THREE.Mesh(new THREE.PlaneGeometry(3, 1), birdMat);
          wingL.position.x = -1.5;
          bird.add(wingL);
          var wingR = new THREE.Mesh(new THREE.PlaneGeometry(3, 1), birdMat);
          wingR.position.x = 1.5;
          bird.add(wingR);
          bird.position.set(cx + (Math.random()-0.5)*30, cy + (Math.random()-0.5)*10, cz + (Math.random()-0.5)*30);
          scene.add(bird);
          flock.push({mesh: bird, wingL: wingL, wingR: wingR, off: Math.random()*10});
        }
        var flockT = Math.random() * 100;
        window._dynamics.push(function(t, dt){
          flockT += (dt || 0.016) * 0.3;
          /* Flock moves in a circle */
          var fx = cx + Math.cos(flockT) * 150;
          var fz = cz + Math.sin(flockT) * 150;
          for(var i = 0; i < flock.length; i++){
            var brd = flock[i];
            /* Follow flock center with offset */
            var tx = fx + Math.sin(brd.off + flockT*2) * 15;
            var tz = fz + Math.cos(brd.off + flockT*2) * 15;
            var ty = cy + Math.sin(brd.off*2 + t) * 5;
            brd.mesh.position.lerp(new THREE.Vector3(tx, ty, tz), 0.05);
            brd.mesh.rotation.y = Math.atan2(tx - brd.mesh.position.x, tz - brd.mesh.position.z);
            /* Flap */
            var flap = Math.sin(t*10 + brd.off) * 0.6;
            brd.wingL.rotation.z = flap;
            brd.wingR.rotation.z = -flap;
          }
        });
      })();
    }
  }catch(e){ console.error(e); }
}
if(typeof buildBirds === 'function'){ try{ buildBirds(); }catch(e){ console.error(e); } }

/* DAY/NIGHT CYCLE — the world breathes. 2026-10-04. */
(function(){
  window._dynamics = window._dynamics || [];
  var cycleTime = 0;
  var dayLength = 300; /* 5 minutes per day */
  window._dynamics.push(function(t, dt){
    try{
      cycleTime += (dt || 0.016);
      var phase = (cycleTime % dayLength) / dayLength; /* 0-