<!-- RUBY-BACKUP · part 144 -->
entById('render-btn');
var renderPanel = document.getElementById('renderpanel');
RENDER_MODES.forEach(function(m){
  var b = document.createElement('button');
  b.innerHTML = RENDER_ICONS[m];
  b.setAttribute('aria-label', RENDER_LABELS[m]);
  b.dataset.rmode = m;
  b.addEventListener('click', function(e){ e.stopPropagation(); setRenderMode(m); });
  renderPanel.appendChild(b);
});
function paintRenderUI(){
  if(renderBtn) renderBtn.innerHTML = RENDER_ICONS[renderMode];
  var kids = renderPanel.children;
  for(var i=0;i<kids.length;i++) kids[i].classList.toggle('sel', kids[i].dataset.rmode===renderMode);
}
function setRenderMode(m){
  renderMode = m;
  try{ localStorage.setItem('ruby-render-mode', m); }catch(e){}
  paintRenderUI();
  renderPanel.classList.remove('open');
  stones.children.forEach(buildStoneVisual);
  updateAnchors();
}
if(renderBtn) renderBtn.addEventListener('click', function(e){
  e.stopPropagation();
  closeShapePanel();
  if(renderPanel) renderPanel.classList.toggle('open');
});
paintRenderUI();
/* ---- the one button: a refresh is only ever a new load of the SCREEN, never the game ---- */
(function(){
  var _rf = document.getElementById('refresh');
  if(!_rf) return;
  _rf.addEventListener('click', function(){
    saveCam();
    var u = new URL(location.href);
    u.searchParams.set('body', 'king');
    u.searchParams.delete('crown');
    u.searchParams.set('walk', '1');
    u.searchParams.set('far', '1');
    u.searchParams.set('fresh', Date.now());
    location.replace(u.toString());
  });
})();

/* ---- frame ---- */
document.getElementById('boot').style.display='none';
var lookTarget = new T.Vector3(0, 0.6, 0);
var clock = new T.Clock();
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   MARK: COMMAND ENGINE — "a line of code to punch in and it will create the thing"
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   MARK: SHAPE CODES   — letter map            (EDIT: letters, new shapes)
   MARK: CURSOR        — relative-build origin (EDIT: start, marker)
   MARK: GRAMMAR       — the tight language    (EDIT: verbs, tokens)
   MARK: PROCEDURES    — the library           (EDIT: add/rename, keep HALF+flip)
   MARK: MIRROR        — flip                  (EDIT: mirror axis)
   MARK: LAW OF GROUND — step/displace/coexist (EDIT: the mass test)
   MARK: HARDENING     — caps & validation     (EDIT: the caps)
   MARK: COMMAND BAR   — > button + input      (EDIT: wired below)
   MARK: MAINFRAME     — the authority         (EDIT: the surface the world calls)
   Contract: parseLine(line, ec) → {ok, ops[]|error} · runOps(ops, mass)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */

/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   MARK: SHAPE CODES — one letter per shape; UPPERCASE = ghost twin
   EDIT: change letters, add shapes. Single letters only; 'x' is remove, 'b' is seed.
   the family: g triangle · u upside-down pyramid · f offset pyramid · w offset upside-down.
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
var CODE_SHAPES = {c:'cube',p:'pyramid',s:'sphere',l:'cyl',t:'torus',v:'cone',o:'octa',r:'tetra',i:'icosa',d:'dodeca',g:'tri',u:'pdown',f:'poff',w:'poffdown'};
function codeToShapeKey(code){
  if(code==='b' || code==='B') return curShapeKey;   /* b = seed of the current shape */
  var low = code.toLowerCase();
  if(!CODE_SHAPES[low]) return null;
  return CODE_SHAPES[low] + (code!==low ? '~ghost' : '');
}
function snap(v){ return Math.round(v/2)*2; }        /* the 2-unit stone grid */

/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   MARK: CURSOR — where relative commands build from
   EDIT: start position, marker look, persistence.
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
var cursor = {x:0, z:0};
function dpadMove(dx, dz){ cursor.x = Math.max(-49, Math.min(49, cursor.x+dx)); cursor.z = Math.max(-49, Math.min(49, cursor.z+dz)); if(typeof updateCursorDot==='function') updateCursorDot(); }
var dpadTimer = null;
function dpadStart(dx, dz){ dpadMove(dx, dz); if(dpadTimer) clearInterval(dpadTimer); dpadTimer = setInterval(function(){ dpadMove(dx, dz); }, 90); /* hold to run, with speed */ }
function dpadStop(){ if(dpadTimer){ clearInterval(dpadTimer); dpadTimer = null; } }
document.addEventListener('DOMContentLoaded', function(){
  /* top solid bar — send codes */
  var ss = document.getElementById('solidsend'), si = document.getElementById('solidinput');
  if(ss && si){
    /* the King's code box — he builds on our world */
    si.removeAttribute('readonly');
    si.placeholder = 'Cheat Codes…';
    ss.style.display = '';
    function kingSend(){ var v = si.value.trim(); if(!v) return; si.value=''; try{ Mainframe.run(v); }catch(e){} }
    ss.addEventListener('click', kingSend);
    si.addEventListener('keydown', function(e){ if(e.key==='Enter') kingSend(); });
  }
  function bindDpad(id, dx, dz){ var b=document.getElementById(id); if