master
barrett-land Revert adom-nucleus -> adom-project-manager; repoint viewers to adom-2dboard / adom-schematic aa8944a 2mo ago
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Viewer</title>
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{width:100%;height:100%;overflow:hidden;background:#0d1117;color:#c9d1d9;font-family:-apple-system,'Segoe UI',Helvetica,Arial,sans-serif}
  #viewer-wrap{position:absolute;inset:0}
  #preload-msg{position:absolute;inset:0;z-index:1;pointer-events:none;display:flex;align-items:center;justify-content:center;color:#6e7681;font-size:13px}
  #error{position:absolute;inset:0;display:none;flex-direction:column;align-items:center;justify-content:center;background:#0d1117;z-index:200;padding:16px;text-align:center}
  #error.visible{display:flex}
  #error h2{color:#f85149;margin-bottom:8px;font-size:15px}
  #error p{color:#8b949e;font-size:13px;max-width:400px}
</style>
</head>
<body>
  <div id="viewer-wrap"></div>
  <div id="preload-msg">Loading 3D viewer…</div>
  <div id="error"><h2>3D not available</h2><p id="error-msg"></p></div>
  <script>
    // Project Manager-hosted copy of the wiki's adom-3d-viewer (Babylon 9). It loads the SAME
    // bundle + Draco decoder, but proxied same-origin through Project Manager's /v3d/ route
    // (Project Manager reverse-proxies the wiki's PUBLIC /static/vendor/adom-3d-viewer-babylon9/),
    // and it loads the MODEL from Project Manager's own authenticated board-glb route. Everything
    // is same-origin from the browser's view, so no cross-site session cookie is needed —
    // which is exactly why a PRIVATE board renders here when the wiki's cross-origin iframe
    // (SameSite=Lax cookie stripped) 404s. Same Babylon viewer, works public + private.
    window.__V3D_BASE = new URL('v3d/', location.href).href;
    window.__viewerLoadFailed = function(msg){
      var e=document.getElementById('error'),em=document.getElementById('error-msg'),l=document.getElementById('preload-msg');
      if(em)em.textContent=msg||'The 3D viewer could not be loaded.'; if(e)e.classList.add('visible'); if(l)l.style.display='none';
    };
  </script>
  <script type="module" src="v3d/adom-3d-viewer-babylon9.esm.js" onerror="window.__viewerLoadFailed && window.__viewerLoadFailed()"></script>
  <script type="module">
    (function(){
      var q=new URLSearchParams(location.search);
      var slug=q.get('slug')||'';
      var v=q.get('v')||'';
      var up=(q.get('up')||'z').toLowerCase();
      var loadingEl=document.getElementById('preload-msg');
      var loaded=false;
      var timer=setTimeout(function(){
        if(loaded)return;
        window.__viewerLoadFailed(typeof window.Adom3DViewerBabylon9==='undefined'
          ? 'The 3D viewer could not be loaded.'
          : 'The 3D model is taking too long to load.');
      },25000);
      var Viewer=window.Adom3DViewerBabylon9;
      if(window.__viewerFailed || typeof Viewer==='undefined'){ clearTimeout(timer); window.__viewerLoadFailed('The 3D viewer could not be loaded.'); return; }
      // Self-host the Draco decoder (proxied) so KHR_draco_mesh_compression GLBs decode.
      try{
        if(window.BABYLON && window.BABYLON.DracoCompression){
          var B=window.__V3D_BASE+'draco/';
          window.BABYLON.DracoCompression.Configuration={decoder:{
            wasmUrl:B+'draco_wasm_wrapper_gltf.js',
            wasmBinaryUrl:B+'draco_decoder_gltf.wasm',
            fallbackUrl:B+'draco_decoder_gltf.js'
          }};
        }
      }catch(e){}
      // Model comes from Project Manager's own authenticated route (same-origin).
      var glbUrl='board-glb/'+encodeURIComponent(slug)+(v?('?v='+encodeURIComponent(v)):'');
      try{
        // zUp:true for our pipeline GLBs (step2glb --molecule stamps Z-up); ?up=y flips it
        // for a raw Y-up export. Matches the wiki viewer's zUp:true default.
        var viewer=Viewer.init(document.getElementById('viewer-wrap'),{zUp:up!=='y',showViewCube:true,showGround:true});
        if(loadingEl)loadingEl.style.display='none';
        viewer.loadModel(glbUrl).then(function(){
          loaded=true; clearTimeout(timer); viewer.frameModel();
          try{ if(viewer.toggleAxes) viewer.toggleAxes('world',false); }catch(e){}
        }).catch(function(err){
          clearTimeout(timer);
          window.__viewerLoadFailed('Error: '+((err&&err.message)||'the GLB could not be loaded'));
        });
      }catch(err){
        clearTimeout(timer);
        window.__viewerLoadFailed('The 3D viewer failed to start: '+((err&&err.message)||'unknown error'));
      }
    })();
  </script>
</body>
</html>