<!-- CODERS100 · part 24 -->
; ctx.moveTo(0, cy+g*scale); ctx.lineTo(W, cy+g*scale); ctx.stroke();
  }
  /* north arrow */
  ctx.fillStyle = '#ffd700'; ctx.font = '12px Georgia';
  ctx.fillText('N', cx-4, 16);
  ctx.beginPath(); ctx.moveTo(cx, 20); ctx.lineTo(cx-5, 32); ctx.lineTo(cx+5, 32); ctx.fill();
  /* districts */
  ctx.fillStyle = '#d8a920';
  var dx = (600-kingPos.x)*scale, dz = (600-kingPos.z)*scale;
  if(Math.abs(dx)<W/2 && Math.abs(dz)<H/2){
    ctx.beginPath(); ctx.arc(cx+dx, cy+dz, 6, 0, Math.PI*2); ctx.fill();
    ctx.fillText('Practice', cx+dx+8, cy+dz);
  }
  /* player — precise */
  var px = cx, py = cy;
  ctx.fillStyle = '#00ffff';
  ctx.beginPath(); ctx.arc(px, py, 5, 0, Math.PI*2); ctx.fill();
  /* facing direction */
  var fx = Math.cos(camYaw), fz = Math.sin(camYaw);
  ctx.strokeStyle = '#00ffff'; ctx.lineWidth = 2;
  ctx.beginPath(); ctx.moveTo(px, py); ctx.lineTo(px+fx*20, py+fz*20); ctx.stroke();
  /* coordinates */
  ctx.fillStyle = '#ffd700'; ctx.font = '11px monospace';
  ctx.fillText(Math.round(kingPos.x)+','+Math.round(kingPos.z), 8, H-8);
  /* redraw while open */
  if(mapOpen) requestAnimationFrame(drawMap);
}

/* ===== PRECISE COMPASS — true degrees ===== */
var compassEl = null;
function updateCompass(){
  if(!compassEl){
    compassEl = document.createElement('div');
    compassEl.style.cssText = 'position:fixed;top:70px;left:12px;z-index:90;width:60px;height:60px;border-radius:50%;background:#141006;border:2px solid #d8a920;display:flex;align-items:center;justify-content:center;color:#ffd700;font:11px monospace;';
    document.body.appendChild(compassEl);
  }
  var deg = Math.round(((camYaw*180/Math.PI)%360+360)%360);
  var dirs = ['E','SE','S','SW','W','NW','N','NE'];
  var dir = dirs[Math.round(deg/45)%8];
  compassEl.textContent = deg+'° '+dir;
}
/* update compass in animate loop */
var _origUpdateCam = updateCamera;
updateCamera = function(){
  _origUpdateCam();
  if(compassEl) updateCompass();
};

/* ===== 56 BUTTONS — uniform, intricate ===== */
var BTNS = [
  ['p1-temple','Build district',function(){ nextDistrict(); }],
  ['p1-map','Map',function(){ toggleMap(); }],
  ['p1-camera','Camera',function(){ toggleCamera(); }],
  ['p1-sun','Day',function(){ runCode('daycity'); }],
  ['p1-moon','Night',function(){ runCode('nightcity'); }],
  ['p1-pin','Where am I',function(){ runCode('whereami'); }],
  ['p1-hamburger','Menu',function(){ osOpen=false; osEl.classList.remove('open');; }],
  ['p1-plus','Create',function(){ say('create mode'); }],
  ['p1-minus','Delete',function(){ say('delete mode'); }],
  ['p1-cube','Shapes',function(){ say('shapes'); }],
  ['p1-palette','Render',function(){ say('render options'); }],
  ['p1-walker','Walk',function(){ moveMode='walk'; document.getElementById('joy').style.display='block'; say('walk'); }],
  ['p1-bird','Fly',function(){ moveMode='fly'; document.getElementById('joy').style.display='block'; say('fly'); }],
  ['p1-uparrow','Jump',function(){ say('jump!'); }],
  ['p1-hand','Grab',function(){ say('grab mode'); }],
  ['p1-speech','Chat',function(){ say('chat'); }],
  ['p1-gt','Codes',function(){ codeInput.focus(); }],
  ['p1-link','Go',function(){ say('go to...'); }],
  ['p1-house','Home',function(){ kingPos.set(0,0,0); say('home'); }],
  ['p1-music','Music',function(){ say('music'); }],
  ['p2-continuum','Continuum',function(){ say('continuum'); }],
  ['p2-place','Place',function(){ say('place mode'); }],
  ['p2-help','Help',function(){ say('help'); }],
  ['p2-export','Export',function(){ runCode('exportfbx'); }],
  ['p2-fixstation','Fix station',function(){ say('Playa 2.0 fix station'); }],
  ['p2-sky','Sky',function(){ say('sky options'); }],
  ['p2-treasure','Treasure',function(){ say('treasure hunt'); }],
  ['p2-clearcache','Clear cache',function(){ if(confirm('Clear?')) location.reload(); }],
  ['p2-waypoints','Waypoints',function(){ say('waypoints'); }],
  ['p2-kidmode','Kid mode',function(){ say('kid mode'); }],
  ['p2-crown','Crown',function(){ say('crown view'); }],
  ['p2-dimension','Dimension',function(){ say('dimension'); }],
  ['p3-soliditronium','Soliditronium',function(){ say('soliditronium'); }],
  ['p3-capsule','Capsule',function(){ say('capsule'); }],
  ['p3-fillgaps','Fill gaps',function(){ say('filling gaps'); }],
  ['p3-recolor','Recolor',function(){ say('recolor'); }],
  ['p3-saveview','Save view',function(){ say('view saved'); }],
  ['p3-gotoview','Go to view',function(){ say('going to view'); }],
  ['p3-presets','Presets',function(){ say('presets'); }],
  ['p3-aurora','Aurora',function(){ say('aurora'); }],
  ['p3-ember','Ember',function(){ say('ember'); }],
  ['p3-storm','Storm',function(){ say('storm'); }],
  ['p3-dawn','Dawn',function(){ say('dawn'); }],
  ['p3-invite','Invite',function(){ say('invite'); }],
  ['p4-whiteout','Whiteout',function(){ say('whiteout'); }],
  ['p4-rain','Rain',function(){ say('rain'); }],
  ['p4-wear','Wear',function(){ say('wear'); }],
  ['p4-walkline','Walkline',function()