← Commit history

Use the shared responsive inline video layout; verify real Hydrogen pane widths and closed state

John Lauer ·56480ad040 ·29d ago ·parent 562f223
4 files changed +61−17
dashboard/index.html+2−5
@@ -2,11 +2,8 @@ :root{color-scheme:dark;--bg:#0d1117;--card:#161b22;--text:#e6edf3;--muted:#8b949e;--line:#30363d;--teal:#00b8b1}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:15px 'Familjen Grotesk',system-ui,sans-serif}header{height:44px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px;padding:0 16px}header img{width:18px;height:18px}header strong{font-size:15px}header span{color:var(--muted);font-size:13px}.spacer{flex:1}button,a{touch-action:manipulation}button{background:var(--card);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:8px 12px;cursor:pointer}button:hover,button:focus-visible{border-color:var(--teal)}main{margin:auto;padding:16px}h1{font-size:30px;margin:0 0 8px}h2{font-size:19px}p{line-height:1.6;color:var(--muted)}a{color:var(--teal)}.pills{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0}.pill{border:1px solid var(--line);border-radius:20px;padding:6px 12px;font-size:12px}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}.card{padding:22px;background:var(--card);border:1px solid var(--line);border-radius:12px}.card button{margin-right:8px}video{width:100%;max-height:70vh;background:#000}dialog{width:min(1100px,95vw);background:var(--card);color:var(--text);border:1px solid var(--line);border-radius:12px}dialog::backdrop{background:#0008}pre{white-space:pre-wrap;word-break:break-word}.close{float:right}#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--card);padding:12px;border:1px solid var(--teal);border-radius:8px;display:none}@media(max-width:720px){.grid{grid-template-columns:1fr}header span{display:none}main{padding:16px}} </style><header><img src="/dashboard/icon.svg" alt=""><strong title="Codex integration">Codex</strong><span>Engineering in Hydrogen</span><div class="spacer"></div><span id="machine">Container</span><button id="help" title="Show or hide starter prompts" aria-label="Starter prompts">?</button><button id="settings" title="Integration details" aria-label="Integration details"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m10 2 4 0 1 3 3 2 3 0 1 4-2 2-1 3 1 3-4 2-2-2-3-1-3 1-2-4 2-2 1-3-1-3 4-2z"/><circle cx="12" cy="12" r="3"/></svg></button></header><main><div id="newbie"></div><div class="pills" id="status"><span class="pill">Checking local integration</span></div><h1>Turn a prompt into working engineering.</h1><p>Orient Codex in your Adom workspace, then drive real tools through Adom Bridge.</p><div class="grid"><section class="card"><h2>Astra routes and checks a real Fusion board</h2><p>Watch Astra-calculated 45-degree routes, native vias and connected thermal pours appear in Fusion. Then reproduce the workflow on your desktop with the packaged skills.</p><button data-demo="https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4">Watch the latest video · 3:43</button><a href="https://wiki.adom.inc/adom/codex/files/docs/REPRODUCE-FUSION.md" target="_blank">Reproduce this with Astra</a><p>Copy the first prompt into Codex and select Astra. Send to AI is paused on Hydrogen 1.0.230 because its provider routing failed our desktop test.</p></section><section class="card"><h2>Workspace setup</h2><p>The package installs an ecosystem entry point, a focused skill and a context command. Your existing instructions and credentials stay yours.</p><button id="inspect">Inspect this workspace</button><a href="https://wiki.adom.inc/adom/codex/files/docs/BOOTSTRAP.md" target="_blank">Setup guide</a></section><section class="card"><h2>Astra routes live in KiCad</h2><p>Watch traces, layer-changing vias and branched nets appear in the real editor. The captions explain the calculation and the measured results.</p><button data-demo="01-astra-live-routing-3x.mp4">6-net demo · 23 sec</button><button data-demo="02-astra-crossbar-24-3x.mp4">24-net demo · 31 sec</button></section><section class="card"><h2>Real-board comparisons</h2><p>Watch a public Adom board go from the human reference to zero traces and independently calculated routing, with narrated explanations and measured KiCad results.</p><button data-demo="04-public-adom-solenoid-full-routing-narrated.mp4">Public board · narrated · 82 sec</button><a href="https://wiki.adom.inc/adom/codex/files/docs/ASTRA-KICAD.md" target="_blank">Read the engineering log</a></section><section class="card"><h2>Codex Desktop</h2><p>Planned: verified desktop installation and a Bridge connection between Hydrogen and Codex Desktop. Desktop controls are not installed by this version.</p><a href="https://wiki.adom.inc/adom/codex/files/docs/DESKTOP-BRIDGE.md" target="_blank">Integration roadmap</a></section></div></main><dialog id="player"><button class="close" id="close-video" title="Close video">Close</button><h2>Astra engineering demonstrations</h2><video id="video" controls playsinline></video></dialog><dialog id="details"><button class="close" id="close-details">Close</button><h2>Local integration</h2><pre id="context"></pre></dialog><div id="toast" role="status"></div><script src="/dashboard/vendor/newbie-panel.js"></script><script> const $=s=>document.querySelector(s);function toast(s){$('#toast').textContent=s;$('#toast').style.display='block';setTimeout(()=>$('#toast').style.display='none',4000)}-function play(file){document.querySelector('#fusion-demo')?.pause();$('#video').src=file.startsWith('https://')?file:'/videos/'+file;$('#player').showModal();$('#video').play().catch(()=>toast('Press Play to start the video.'))}-const panel=AdomNewbiePanel.mount({mount:'#newbie',apiBase:'/codex',app:'codex',appName:'Codex',slug:'codex',toggleButton:'#help',onToggle:open=>{if(!open)document.querySelector('#fusion-demo')?.pause()},demo:{label:'Watch the routing demo',meta:'Fusion thermal routing, 3 min 43 sec',onPlay:()=>document.querySelector('#fusion-demo').play().catch(()=>toast('Press Play to start the video.'))},phrases:["Codex Astra, reproduce this Fusion demo",'Codex, inspect this workspace','Codex, review my PCB thermal paths']});-const demoColumn=document.querySelector('#newbie .anp-left');-const inlineDemo=document.createElement('video');inlineDemo.id='fusion-demo';inlineDemo.controls=true;inlineDemo.playsInline=true;inlineDemo.preload='none';inlineDemo.poster='/dashboard/fusion-demo-poster.jpg';inlineDemo.src='https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4';inlineDemo.setAttribute('aria-label','Astra Fusion thermal routing video');inlineDemo.style.cssText='display:block;width:100%;margin-top:12px;border-radius:8px;aspect-ratio:16/9';demoColumn.appendChild(inlineDemo);-const demoCaption=document.createElement('p');demoCaption.textContent='Astra in Fusion · 3:43 · narrated';demoCaption.style.cssText='font-size:12px;margin:6px 0 0';demoColumn.appendChild(demoCaption);+function play(file){document.querySelector('.anp-video')?.pause();$('#video').src=file.startsWith('https://')?file:'/videos/'+file;$('#player').showModal();$('#video').play().catch(()=>toast('Press Play to start the video.'))}+const panel=AdomNewbiePanel.mount({mount:'#newbie',apiBase:'/codex',app:'codex',appName:'Codex',slug:'codex',toggleButton:'#help',demo:{label:'Play the Fusion demo',meta:'3:43 · narrated · Astra in Fusion',video:{src:'https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4',poster:'/dashboard/fusion-demo-poster.jpg',title:'Astra routes a Fusion board with connected thermal copper'}},phrases:["Codex Astra, reproduce this Fusion demo",'Codex, inspect this workspace','Codex, review my PCB thermal paths']}); async function inspect(){try{const r=await fetch('/api/status');if(!r.ok)throw Error('Context unavailable');const s=await r.json();$('#context').textContent=JSON.stringify(s,null,2);$('#details').showModal()}catch(e){toast(e.message)}} $('#inspect').onclick=inspect;$('#settings').onclick=inspect;$('#close-details').onclick=()=>$('#details').close();$('#close-video').onclick=()=>$('#player').close();$('#player').addEventListener('close',()=>$('#video').pause());document.querySelectorAll('[data-demo]').forEach(b=>b.onclick=()=>play(b.dataset.demo)); function status(s){$('#machine').textContent=s.container.hostname;$('#status').replaceChildren(...['Entry point: '+(s.instructionsInstalled?'installed':'not installed'),'Bridge CLI: '+(s.tools['adom-bridge']?'available':'missing'),'Host target: select in Bridge'].map(t=>{let e=document.createElement('span');e.className='pill';e.textContent=t;return e}))}
dashboard/vendor/newbie-panel.js+56−9
@@ -78,6 +78,19 @@   .anp-left{flex-direction:row; align-items:center; gap:12px;} } +/* A video is content, not an icon in the legacy 220px demo-button column.+ * Opt-in only: existing button-only panels keep their original layout. */+.anp.anp--video{grid-template-columns:minmax(0,720px) minmax(360px,1fr);align-items:start;}+.anp--video .anp-left{min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:12px;}+.anp-video{display:block;width:100%;height:auto;max-height:none;aspect-ratio:16/9;object-fit:contain;background:#080c11;border-radius:8px;}+.anp-video-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;}+.anp--video .anp-phrase span{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere;padding:10px 8px 10px 0;}+.anp--video .anp-tbl{max-width:none;}+.anp--video .anp-right{align-self:center;}+@container anp (max-width:1099px){+  .anp.anp--video{grid-template-areas:"head" "left" "right";grid-template-columns:minmax(0,1fr);}+}+ .anp-toasts{position:fixed; left:50%; bottom:22px; transform:translateX(-50%); z-index:99999;   display:flex; flex-direction:column-reverse; gap:8px; pointer-events:none;} .anp-toast{pointer-events:auto; display:flex; align-items:center; gap:10px; max-width:min(92vw,520px);@@ -331,7 +344,9 @@     var key = 'anp:' + slug + ':open';      var wrap = el('div', 'anp-wrap');-    var panel = el('section', 'anp');+    var videoCfg = cfg.demo && cfg.demo.video;+    var video = null;+    var panel = el('section', 'anp' + (videoCfg && videoCfg.src ? ' anp--video' : ''));     panel.setAttribute('aria-label', 'Say it: sample prompts for ' + appName);      var head = el('div', 'anp-head');@@ -345,14 +360,26 @@     panel.appendChild(head);      var left = el('div', 'anp-left');+    var controls = left;+    if (videoCfg && videoCfg.src) {+      video = el('video', 'anp-video');+      video.src = videoCfg.src;+      if (videoCfg.poster) video.poster = videoCfg.poster;+      video.controls = true; video.playsInline = true; video.preload = 'none';+      video.setAttribute('aria-label', videoCfg.title || 'Demonstration video');+      left.appendChild(video);+      controls = el('div', 'anp-video-toolbar');+      left.appendChild(controls);+    }     var demo = el('button', 'anp-demo', ICON.play + '<span>' + esc((cfg.demo && cfg.demo.label) || 'Play the demo') + '</span>');     demo.type = 'button';     demo.addEventListener('click', function () {-      if (cfg.demo && typeof cfg.demo.onPlay === 'function') cfg.demo.onPlay();+      if (video) video.play().catch(function () { toast('Press Play on the video to start playback.', 'info'); });+      else if (cfg.demo && typeof cfg.demo.onPlay === 'function') cfg.demo.onPlay();       else toast('This dashboard has no demo wired up yet', 'err');     });-    left.appendChild(demo);-    if (cfg.demo && cfg.demo.meta) left.appendChild(el('span', 'anp-meta', esc(cfg.demo.meta)));+    controls.appendChild(demo);+    if (cfg.demo && cfg.demo.meta) controls.appendChild(el('span', 'anp-meta', esc(cfg.demo.meta)));     panel.appendChild(left);      var right = el('div', 'anp-right');@@ -411,6 +438,7 @@      * open pins it open forever and graduating it closed marks it user-dismissed. It looks      * like "the panel sometimes ignores graduation". (lbr, 2026-08-25) */     function setOpen(open, remember, source) {+      if (!open && video) video.pause();       panel.hidden = !open;       wrap.style.display = open ? '' : 'none';   /* no dead margin when collapsed */       if (toggleBtn) {@@ -457,7 +485,7 @@       close:  function (o) { setOpen(false, !(o && o.remember === false), 'api'); },       toggle: function () { setOpen(panel.hidden, true, 'api'); },       isOpen: function () { return !panel.hidden; },-      overBudget: over, toast: toast, selfCheck: function () { return selfCheck(panel); }+      video: video, overBudget: over, toast: toast, selfCheck: function () { return selfCheck(panel); }     };   } @@ -532,8 +560,22 @@     if (!aligned) ok = false;     rows.push({ what: 'copy icons in one column', want: '1 x-position', got: Object.keys(xs).length + ' x-positions', pass: aligned });     var cols = cs.gridTemplateColumns.split(' ').filter(Boolean).length;-    rows.push({ what: 'columns at this width', want: panel.getBoundingClientRect().width >= TWO_COL_MIN ? '2' : '1',-                got: String(cols), pass: true });+    var withVideo = panel.classList.contains('anp--video');+    var expectedCols = panel.parentElement.clientWidth >= (withVideo ? 1100 : TWO_COL_MIN) ? 2 : 1;+    var colsOk = cols === expectedCols;+    if (!colsOk) ok = false;+    rows.push({ what: 'columns at this width', want: String(expectedCols), got: String(cols), pass: colsOk });+    if (withVideo) {+      var vr = panel.querySelector('.anp-video').getBoundingClientRect();+      var lr = panel.querySelector('.anp-left').getBoundingClientRect();+      var rr = panel.querySelector('.anp-right').getBoundingClientRect();+      var mediaOk = Math.abs(vr.width - lr.width) < 2 && vr.width >= Math.min(300, lr.width) &&+                    Math.abs(vr.height - vr.width * 9 / 16) < 2 &&+                    (expectedCols === 1 ? rr.top >= lr.bottom - 1 : rr.left >= vr.right);+      if (!mediaOk) ok = false;+      rows.push({what:'video size and placement', want:'16:9, fills its column, no prompt overlap',+        got:Math.round(vr.width)+' × '+Math.round(vr.height)+'px', pass:mediaOk});+    }     /* THE GUTTER ROW. Four apps measured at the SAME 744px pane reported panel widths of      * 734, 735, 702 and 694, because each page put a different amount of its own padding      * around the mount point. 694 is under the 700 threshold, so that app rendered ONE@@ -601,7 +643,12 @@      * remeasured with this probe, neither had less than 141px of slack. A metric that can only      * return one value on success is not evidence of success. */     var spans = [].slice.call(panel.querySelectorAll('.anp-phrase span'));-    if (spans.length) {+    if (withVideo && spans.length) {+      var wrapOk = spans.every(function (sp) { return sp.scrollWidth <= sp.clientWidth + 1 &&+        getComputedStyle(sp).whiteSpace === 'normal'; });+      if (!wrapOk) ok = false;+      rows.push({what:'readable video-panel prompts',want:'wrap without horizontal clipping',got:wrapOk?'all readable':'clipped or nowrap',pass:wrapOk});+    } else if (spans.length) {       var probe = document.createElement('span');       probe.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;font:' +                             getComputedStyle(spans[0]).font;@@ -686,6 +733,6 @@   }    root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText,-                           checkSend: checkSend, version: '2.22.0',+                           checkSend: checkSend, version: '2.23.0',                            TWO_COL_MIN: TWO_COL_MIN, PHRASE_BUDGET: PHRASE_BUDGET }; })(typeof window !== 'undefined' ? window : this);
package.json+1−1
@@ -4,7 +4,7 @@   "type": "app",   "title": "Codex",   "brief": "Codex in Adom Hydrogen: ecosystem setup, dock dashboard and live engineering demos.",-  "version": "0.1.14",+  "version": "0.1.15",   "description": "Codex in Adom Hydrogen with reusable CAD routing, electrical review, copper-ablation and narrated video skills, plus verified KiCad and Fusion demo progressions.",   "org": "adom",   "needs_sudo": false,
page.json+2−2
@@ -4,7 +4,7 @@   "type": "app",   "title": "Codex",   "brief": "Codex in Adom Hydrogen: ecosystem setup, dock dashboard and live engineering demos.",-  "version": "0.1.14",+  "version": "0.1.15",   "hero": {     "type": "image",     "path": "screenshots/hero.png"@@ -95,4 +95,4 @@     "videos/04-public-adom-solenoid-full-routing-narrated.mp4",     "videos/04-public-adom-solenoid-full-routing.mp4"   ]-}\ No newline at end of file+}