<!-- RUBY-BACKUP · part 228 -->
HREE.Vector3(-width/2+0.5, 0.15, 0),
    new THREE.Vector3(-width/4, 0.15, depth/8),
    new THREE.Vector3(0, 0.15, -depth/8),
    new THREE.Vector3(width/4, 0.15, depth/6),
    new THREE.Vector3(width/2-0.5, 0.15, depth/4)
  ]);
  var riverGeo = new THREE.TubeGeometry(riverCurve, 40, 0.6, 8, false);
  var riverMat = new THREE.MeshStandardMaterial({
    color: 0x2299cc, transparent: true, opacity: 0.8,
    roughness: 0.1, metalness: 0.3
  });
  var river = new THREE.Mesh(riverGeo, riverMat);
  g.add(river);
  /* riverbed — stones */
  var bedGeo = new THREE.TubeGeometry(riverCurve, 40, 0.75, 8, false);
  var bed = new THREE.Mesh(bedGeo,
    new THREE.MeshStandardMaterial({color: 0x6a5a4a, roughness: 1}));
  bed.position.y = -0.15;
  g.add(bed);
  /* flow animation */
  var flowT = 0;
  var flowAnim = setInterval(function(){
    flowT += 0.02;
    riverMat.opacity = 0.75 + Math.sin(flowT*2)*0.1;
    /* move texture offset for flow illusion */
    if(riverMat.map) riverMat.map.offset.x -= 0.01;
  }, 50);
  g.userData.flowAnim = flowAnim;
  /* mist — hanging in the valley */
  for(var m=0; m<6; m++){
    var mist = new THREE.Mesh(
      new THREE.SphereGeometry(2+Math.random()*2, 8, 8),
      new THREE.MeshStandardMaterial({color: 0xffffff, transparent: true, opacity: 0.12})
    );
    mist.position.set(
      (Math.random()-0.5)*width*0.7,
      3+Math.random()*3,
      (Math.random()-0.5)*depth*0.7
    );
    mist.scale.y = 0.4;
    g.add(mist);
  }
  g.position.set(x*0.13, 0, z*0.13);
  return g;
}
function buildValleys(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  if(VALLEYS){
    VALLEYS.forEach(function(v){
      try{ scene.remove(v); }catch(e){}
      /* stop waterfall anims */
      v.traverse(function(o){ if(o.userData.anim) clearInterval(o.userData.anim); });
    });
  }
  VALLEYS = [];
  var px = mePos.x, pz = mePos.z;
  /* three valleys, like the islands */
  var v1 = buildHawaiianValley(px-150, pz-40, 20, 40);
  scene.add(v1); VALLEYS.push(v1);
  var v2 = buildHawaiianValley(px+140, pz+50, 24, 45);
  scene.add(v2); VALLEYS.push(v2);
  var v3 = buildHawaiianValley(px+20, pz-150, 18, 35);
  scene.add(v3); VALLEYS.push(v3);
  codeStatus('valleys like Hawaii — pali walls, waterfalls, mist. Like home.');
}
function clearValleys(){
  if(VALLEYS){
    VALLEYS.forEach(function(v){
      try{ scene.remove(v); }catch(e){}
      v.traverse(function(o){ if(o.userData.anim) clearInterval(o.userData.anim); });
      if(v.userData.flowAnim) clearInterval(v.userData.flowAnim);
    });
    VALLEYS = null;
  }
  codeStatus('valleys cleared');
}
function buildWildTerrain(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  if(TERRAIN_GROUP){
    TERRAIN_GROUP.forEach(function(o){ try{ scene.remove(o); }catch(e){} });
  }
  TERRAIN_GROUP = [];
  var px = mePos.x, pz = mePos.z;
  /* islands — some with volcanoes */
  var islands = [
    {x: px-80, z: pz-60, r: 12, v: true},
    {x: px+70, z: pz-80, r: 10, v: false},
    {x: px-60, z: pz+70, r: 14, v: true},
    {x: px+80, z: pz+60, r: 8, v: false}
  ];
  islands.forEach(function(isl){
    var island = buildIsland(isl.x, isl.z, isl.r, isl.v);
    scene.add(island);
    TERRAIN_GROUP.push(island);
  });
  /* long mountains */
  var m1 = buildMountainRange(px-100, pz+20, 12, 6);
  scene.add(m1); TERRAIN_GROUP.push(m1);
  var m2 = buildMountainRange(px+100, pz-20, 10, 5);
  scene.add(m2); TERRAIN_GROUP.push(m2);
  /* rough terrain */
  var r1 = buildRoughTerrain(px+40, pz-100, 20);
  scene.add(r1); TERRAIN_GROUP.push(r1);
  var r2 = buildRoughTerrain(px-40, pz+100, 20);
  scene.add(r2); TERRAIN_GROUP.push(r2);
  /* cliffs with trails */
  var c1 = buildCliffTrail(px-120, pz, 8);
  scene.add(c1); TERRAIN_GROUP.push(c1);
  var c2 = buildCliffTrail(px+120, pz, 10);
  scene.add(c2); TERRAIN_GROUP.push(c2);
  codeStatus('wild terrain — 4 islands (2 volcanoes), mountains, rough terrain, cliff trails.');
}
function clearWildTerrain(){
  if(TERRAIN_GROUP){
    TERRAIN_GROUP.forEach(function(o){ try{ scene.remove(o); }catch(e){} });
    TERRAIN_GROUP = null;
  }
  codeStatus('wild terrain cleared');
}

/* THREE ZONES — city separate from rural counties and tribal villages */
var RURAL_GROUP = null;
var TRIBAL_GROUP = null;
function buildFarm(x, z){
  var g = new THREE.Group();
  /* barn */
  var barn = new THREE.Mesh(new THREE.BoxGeometry(2, 1.5, 1.5),
    new THREE.MeshStandardMaterial({color: 0xaa3322, roughness: 0.8}));
  barn.position.y = 0.75; g.add(barn);
  var roof = new THREE.Mesh(new THREE.ConeGeometry(1.4, 0.8, 4),
    new THREE.MeshStandardMaterial({color: 0x664422, roughness: 0.8}));
  roof.position.y = 1.9; roof.rotation.y = Math.PI/4; g.add(roof);
  /* fields — rows */
  for(var r=0; r<4; r++){
    var row = new THREE.Mesh(new THREE.BoxGeometry(4, 0.1, 0.5),
      new THREE.MeshStandardMaterial({color: 0x4a6a2a, roughness: 1}));
    row.position.set(0, 0.05, -2 - r*0.8);
    g.add(