<!-- RUBY-BACKUP · part 512 -->
ax-height:60vh;overflow-y:auto;padding:10px;background:rgba(10,8,4,0.85);border-radius:16px;border:1px solid #8a6a1c;min-width:120px;';
  _camViews.forEach(function(v){
    var b = document.createElement('button');
    b.textContent = v.label;
    b.style.cssText = 'padding:10px 16px;background:#d8a920;color:#111;border:none;border-radius:8px;font-size:14px;font-weight:bold;cursor:pointer;';
    b.onclick = function(){
      if(typeof Mainframe!=='undefined') Mainframe.run(v.code);
      codeStatus('camera: ' + v.label);
    };
    _camPanel.appendChild(b);
  });
  /* v1-v100 grid */
  var vgrid = document.createElement('div');
  vgrid.style.cssText = 'display:grid;grid-template-columns:repeat(5,1fr);gap:4px;margin-top:8px;';
  for(var vi=1; vi<=100; vi++){
    (function(vn){
      var vb = document.createElement('button');
      vb.textContent = 'Cam '+vn;
      vb.style.cssText = 'padding:6px 2px;background:#2a2214;color:#ffd700;border:1px solid #8a6a1c;border-radius:4px;font-size:11px;cursor:pointer;';
      vb.onclick = function(){
        if(typeof Mainframe!=='undefined') Mainframe.run('v'+vn);
      };
      vgrid.appendChild(vb);
    })(vi);
  }
  _camPanel.appendChild(vgrid);
  /* cheat codes — save, record, glide */
  var cheatDiv = document.createElement('div');
  cheatDiv.style.cssText = 'margin-top:10px;border-top:1px solid #8a6a1c;padding-top:10px;';
  var cheatTitle = document.createElement('div');
  cheatTitle.textContent = 'Cheats';
  cheatTitle.style.cssText = 'font-size:12px;color:#8a6a1c;text-align:center;margin-bottom:8px;';
  cheatDiv.appendChild(cheatTitle);
  /* save slots */
  var saveRow = document.createElement('div');
  saveRow.style.cssText = 'display:grid;grid-template-columns:repeat(5,1fr);gap:4px;margin-bottom:6px;';
  for(var sn=1; sn<=5; sn++){
    (function(n){
      var sb = document.createElement('button');
      sb.textContent = 'S'+n;
      sb.title = 'Save view '+n;
      sb.style.cssText = 'padding:8px 2px;background:#2a2214;color:#ffd700;border:1px solid #8a6a1c;border-radius:4px;font-size:11px;cursor:pointer;';
      sb.onclick = function(){ if(typeof Mainframe!=='undefined') Mainframe.run('savecam'+n); };
      saveRow.appendChild(sb);
    })(sn);
  }
  cheatDiv.appendChild(saveRow);
  /* go slots */
  var goRow = document.createElement('div');
  goRow.style.cssText = 'display:grid;grid-template-columns:repeat(5,1fr);gap:4px;margin-bottom:8px;';
  for(var gn=1; gn<=5; gn++){
    (function(n){
      var gb = document.createElement('button');
      gb.textContent = 'G'+n;
      gb.title = 'Go to view '+n;
      gb.style.cssText = 'padding:8px 2px;background:#d8a920;color:#111;border:none;border-radius:4px;font-size:11px;font-weight:bold;cursor:pointer;';
      gb.onclick = function(){ if(typeof Mainframe!=='undefined') Mainframe.run('gocam'+n); };
      goRow.appendChild(gb);
    })(gn);
  }
  cheatDiv.appendChild(goRow);
  /* record and glide */
  var rgRow = document.createElement('div');
  rgRow.style.cssText = 'display:grid;grid-template-columns:1fr 1fr;gap:6px;';
  var recBtn = document.createElement('button');
  recBtn.textContent = 'Record';
  recBtn.style.cssText = 'padding:10px;background:#5a1a1a;color:#ffaaaa;border:1px solid #8a2a2a;border-radius:8px;font-size:13px;font-weight:bold;cursor:pointer;';
  recBtn.onclick = function(){ if(typeof Mainframe!=='undefined') Mainframe.run('record'); };
  rgRow.appendChild(recBtn);
  var glideBtn = document.createElement('button');
  glideBtn.textContent = 'Glide';
  glideBtn.style.cssText = 'padding:10px;background:#1a3a5a;color:#aaaaff;border:1px solid #2a4a7a;border-radius:8px;font-size:13px;font-weight:bold;cursor:pointer;';
  glideBtn.onclick = function(){ if(typeof Mainframe!=='undefined') Mainframe.run('glide'); };
  rgRow.appendChild(glideBtn);
  cheatDiv.appendChild(rgRow);
  _camPanel.appendChild(cheatDiv);
  document.body.appendChild(_camPanel);
}

/* SCREENSHOT — hold the camera button, save to phone */
function takeScreenshot(){
  try{
    if(typeof renderer==='undefined' || !renderer.domElement){
      codeStatus('no renderer'); return;
    }
    /* force a render then capture */
    if(typeof scene!=='undefined' && typeof camera!=='undefined'){
      renderer.render(scene, camera);
    }
    renderer.domElement.toBlob(function(blob){
      if(!blob){ codeStatus('capture failed'); return; }
      var file = new File([blob], 'ruby-'+Date.now()+'.png', {type:'image/png'});
      /* iOS: share sheet → Save to Photos */
      if(navigator.share && navigator.canShare && navigator.canShare({files:[file]})){
        navigator.share({files:[file], title:'Ruby'}).catch(function(){});
        codeStatus('shared — save to Photos');
      } else {
        /* fallback: download link */
        var a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = 'ruby-'+Date.now()+'.png';
        document.body.appendChild(a);
        a.click();
      