diff --git a/nvsim/assets/index-CjC_xGBQ.js b/nvsim/assets/index-CjC_xGBQ.js
new file mode 100644
index 00000000..5259f72e
--- /dev/null
+++ b/nvsim/assets/index-CjC_xGBQ.js
@@ -0,0 +1,2073 @@
+import{f as tt,u as at,i as y,a as w,b as p,w as G}from"./lit-BS7WqYd5.js";import{y as c,g as st,j as f}from"./signals-SG45zFCj.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function a(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(s){if(s.ep)return;s.ep=!0;const i=a(s);fetch(s.href,i)}})();/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const k=e=>(t,a)=>{a!==void 0?a.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const rt={attribute:!0,type:String,converter:at,reflect:!1,hasChanged:tt},it=(e=rt,t,a)=>{const{kind:r,metadata:s}=a;let i=globalThis.litPropertyMetadata.get(s);if(i===void 0&&globalThis.litPropertyMetadata.set(s,i=new Map),r==="setter"&&((e=Object.create(e)).wrapped=!0),i.set(a.name,e),r==="accessor"){const{name:o}=a;return{set(n){const l=t.get.call(this);t.set.call(this,n),this.requestUpdate(o,l,e,!0,n)},init(n){return n!==void 0&&this.C(o,void 0,e,n),n}}}if(r==="setter"){const{name:o}=a;return function(n){const l=this[o];t.call(this,n),this.requestUpdate(o,l,e,!0,n)}}throw Error("Unsupported decorator location: "+r)};function Fe(e){return(t,a)=>typeof a=="object"?it(e,t,a):((r,s,i)=>{const o=s.hasOwnProperty(i);return s.constructor.createProperty(i,r),o?Object.getOwnPropertyDescriptor(s,i):void 0})(e,t,a)}/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function u(e){return Fe({...e,state:!0,attribute:!1})}/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const ot=(e,t,a)=>(a.configurable=!0,a.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,a),a);/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function We(e,t){return(a,r,s)=>{const i=o=>o.renderRoot?.querySelector(e)??null;return ot(a,r,{get(){return i(this)}})}}var nt=Object.defineProperty,lt=Object.getOwnPropertyDescriptor,Ue=(e,t,a,r)=>{for(var s=r>1?void 0:r?lt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&nt(t,a,s),s};let he=class extends w{constructor(){super(...arguments),this.view="scene"}navigate(e){this.dispatchEvent(new CustomEvent("navigate",{detail:e}))}render(){return p`
+
NV
+
+ this.navigate("scene")}>
+
+
+ this.navigate("apps")}>
+
+
+ this.navigate("inspector")}>
+
+
+ this.navigate("witness")}>
+
+
+ this.navigate("ghost-murmur")}>
+
+
+
+
+
+
+
+
+ this.dispatchEvent(new CustomEvent("open-settings",{bubbles:!0,composed:!0}))}>
+
+
+ `}};he.styles=y`
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 10px 0;
+ gap: 4px;
+ background: var(--bg-1);
+ border-right: 1px solid var(--line);
+ }
+ .logo {
+ width: 36px; height: 36px;
+ border-radius: 10px;
+ background: linear-gradient(135deg, oklch(0.78 0.14 70) 0%, oklch(0.55 0.16 30) 100%);
+ display: grid; place-items: center;
+ color: #1a0f00;
+ font-weight: 700;
+ font-family: var(--mono);
+ font-size: 11px;
+ margin-bottom: 14px;
+ box-shadow: 0 4px 12px -2px oklch(0.55 0.16 30 / 0.35);
+ }
+ .btn {
+ width: 36px; height: 36px;
+ border-radius: 8px;
+ background: transparent;
+ border: 1px solid transparent;
+ color: var(--ink-3);
+ display: grid; place-items: center;
+ transition: all 0.15s;
+ position: relative;
+ cursor: pointer;
+ }
+ .btn:hover { color: var(--ink); background: var(--bg-2); }
+ .btn.active {
+ color: var(--ink);
+ background: var(--bg-3);
+ border-color: var(--line-2);
+ }
+ .btn.active::before {
+ content: ''; position: absolute; left: -10px; top: 8px; bottom: 8px;
+ width: 2px; background: var(--accent); border-radius: 2px;
+ }
+ .btn.ghost.active::before { background: var(--accent-3); }
+ .spacer { flex: 1; }
+ svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }
+ `;Ue([Fe()],he.prototype,"view",2);he=Ue([k("nv-rail")],he);const P=c("wasm"),Pe=c("");c(!1);c(null);const g=c(!1);c(!0);const ue=c(1),dt=c(0),Re=c(0n),L=c(0xCAFEBABEn),j=c(1e4),W=c(1e3),U=c(1),q=c(!0),x=c("dark"),_=c("default"),z=c(!1),ve=c(!0),fe=c([0,0,0]),K=c(0),H=c(0),M=c(0),A=c(""),$=c("idle"),Y=c(""),oe=c(null),xe=c([]),ye=c([]),we=c([]),ke=c([]),He=c("rebar-walkby-01"),ct=c(""),ae=c(!1),Te=c("all"),N=c([]);function pt(e){const t=N.value.slice();for(t.push(e);t.length>200;)t.shift();N.value=t}const ie=c([]),Ne=st(()=>P.value==="wasm"?"wasm":"ws");let qe=null;function ut(e){qe=e}function h(){return qe}const T=c([]),vt=200;function d(e,t){if(ae.value)return;const a=T.value.slice();for(a.push({ts:Date.now(),level:e,msg:t});a.length>vt;)a.shift();T.value=a}function gt(e){const a=xe.value.slice();a.push(e[0]),a.length>200&&a.shift();const r=ye.value.slice();r.push(e[1]),r.length>200&&r.shift();const s=we.value.slice();s.push(e[2]),s.length>200&&s.shift(),xe.value=a,ye.value=r,we.value=s}function mt(e){const a=ke.value.slice();for(a.push(Math.max(0,Math.min(1,e)));a.length>48;)a.shift();ke.value=a}var bt=Object.defineProperty,ht=Object.getOwnPropertyDescriptor,ce=(e,t,a,r)=>{for(var s=r>1?void 0:r?ht(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&bt(t,a,s),s};let B=class extends w{constructor(){super(...arguments),this.open=!1,this.mTitle="",this.mBody="",this.buttons=[],this.onModal=e=>{const t=e.detail;this.mTitle=t.title,this.mBody=t.body,this.buttons=t.buttons??[{label:"Close",variant:"primary"}],this.open=!0,this.setAttribute("open",""),requestAnimationFrame(()=>{const a=this.shadowRoot;if(!a)return;a.querySelector("input, select, textarea, button:not(.close)")?.focus()})},this.onKey=e=>{e.key==="Escape"&&this.open&&this.close()}}connectedCallback(){super.connectedCallback(),window.addEventListener("nv-modal",this.onModal),window.addEventListener("keydown",this.onKey)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-modal",this.onModal),window.removeEventListener("keydown",this.onKey)}updated(){if(!this.open)return;const e=this.shadowRoot;if(!e)return;const t=a=>{if(a.key!=="Tab")return;const r=Array.from(e.querySelectorAll("input, select, textarea, button, [href]")).filter(n=>!n.hasAttribute("disabled"));if(r.length===0)return;const s=r[0],i=r[r.length-1],o=e.activeElement??null;a.shiftKey&&o===s?(a.preventDefault(),i.focus()):!a.shiftKey&&o===i&&(a.preventDefault(),s.focus())};e.removeEventListener("keydown",t),e.addEventListener("keydown",t)}close(){this.open=!1,this.removeAttribute("open")}clickBtn(e){e.onClick?.(),this.close()}render(){return p`
+
+
+
${this.mTitle}
+
this.close()}>×
+
+
+
+ ${this.buttons.map(e=>p`
+ this.clickBtn(e)}>${e.label}
+ `)}
+
+
+ `}};B.styles=y`
+ :host {
+ position: fixed; inset: 0;
+ background: rgba(0,0,0,0.55);
+ backdrop-filter: blur(4px);
+ z-index: 200;
+ display: grid; place-items: center;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.18s;
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .modal {
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ width: min(520px, 92vw);
+ max-height: 86vh;
+ display: flex; flex-direction: column;
+ transform: translateY(12px) scale(0.98);
+ transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);
+ }
+ :host([open]) .modal { transform: translateY(0) scale(1); }
+ .h {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ display: flex; align-items: center; justify-content: space-between;
+ }
+ .h .ttl { font-size: 14px; font-weight: 600; }
+ .body { padding: 16px; overflow-y: auto; font-size: 13px; color: var(--ink-2); line-height: 1.55; }
+ .f {
+ padding: 12px 16px;
+ border-top: 1px solid var(--line);
+ display: flex; gap: 8px; justify-content: flex-end;
+ }
+ button {
+ padding: 6px 12px;
+ border-radius: 8px;
+ font-size: 12.5px;
+ cursor: pointer;
+ font-family: inherit;
+ border: 1px solid var(--line);
+ background: var(--bg-2); color: var(--ink);
+ }
+ button.ghost { background: transparent; }
+ button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }
+ button.danger { background: var(--bad); border-color: var(--bad); color: #fff; }
+ .close {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-2);
+ }
+ `;ce([u()],B.prototype,"open",2);ce([u()],B.prototype,"mTitle",2);ce([u()],B.prototype,"mBody",2);ce([u()],B.prototype,"buttons",2);B=ce([k("nv-modal")],B);function se(e){window.dispatchEvent(new CustomEvent("nv-modal",{detail:e}))}var ft=Object.defineProperty,xt=Object.getOwnPropertyDescriptor,ze=(e,t,a,r)=>{for(var s=r>1?void 0:r?xt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&ft(t,a,s),s};let X=class extends w{constructor(){super(...arguments),this.visible=!1,this.msg="",this.icon="✓",this.timer=null,this.onToast=e=>{const t=e.detail;this.msg=t.msg??"Done",this.icon=t.icon??"✓",this.visible=!0,this.setAttribute("visible",""),this.timer!==null&&window.clearTimeout(this.timer),this.timer=window.setTimeout(()=>{this.visible=!1,this.removeAttribute("visible")},1800)}}connectedCallback(){super.connectedCallback(),window.addEventListener("nv-toast",this.onToast)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-toast",this.onToast)}render(){return p`${this.icon} ${this.msg} `}};X.styles=y`
+ :host {
+ position: fixed; bottom: 24px; left: 50%;
+ transform: translateX(-50%) translateY(80px);
+ background: var(--bg-2);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ padding: 10px 14px;
+ font-size: 12.5px;
+ box-shadow: var(--shadow);
+ z-index: 100;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.2s, transform 0.2s;
+ display: flex; align-items: center; gap: 8px;
+ }
+ :host([visible]) {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+ pointer-events: auto;
+ }
+ .icon { color: var(--accent); }
+ `;ze([u()],X.prototype,"visible",2);ze([u()],X.prototype,"msg",2);ze([u()],X.prototype,"icon",2);X=ze([k("nv-toast")],X);function C(e,t="✓"){window.dispatchEvent(new CustomEvent("nv-toast",{detail:{msg:e,icon:t}}))}var yt=Object.getOwnPropertyDescriptor,wt=(e,t,a,r)=>{for(var s=r>1?void 0:r?yt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=o(s)||s);return s};let De=class extends w{connectedCallback(){super.connectedCallback(),f(()=>{M.value,Ne.value,L.value,x.value,He.value,g.value,this.requestUpdate()})}async toggleRun(){const e=h();e&&(g.value?(await e.pause(),g.value=!1):(await e.run(),g.value=!0))}async reset(){const e=h();e&&await e.reset()}toggleTheme(){x.value=x.value==="dark"?"light":"dark"}async openSeedModal(){const e=`0x${L.value.toString(16).toUpperCase().padStart(8,"0")}`;se({title:"Set seed",body:`Set the 32-bit hex seed for the shot-noise PRNG. Same (scene, config, seed) → byte-identical witness.
+ Hex seed
+ `,buttons:[{label:"Cancel",variant:"ghost"},{label:"Apply",variant:"primary",onClick:async()=>{const t=document.querySelector("nv-modal")?.shadowRoot?.querySelector("#seed-input");if(!t)return;const a=t.value.trim().replace(/^0x/i,""),r=BigInt("0x"+a);L.value=r,await h()?.setSeed(r),d("ok",`seed → 0x${r.toString(16).toUpperCase()}`),C(`Seed → 0x${r.toString(16).toUpperCase().slice(0,8)}`,"⟳")}}]})}openTransportSettings(){window.dispatchEvent(new CustomEvent("open-settings"))}render(){const e=L.value.toString(16).toUpperCase().padStart(8,"0");return p`
+
+ RuView /
+ nvsim /
+ ${He.value}
+
+
+
+
+ ${M.value>0?(M.value/1e3).toFixed(2)+" kHz":"idle"}
+
+
+ ${Ne.value}
+
+
+ seed: 0x${e}
+
+
+ ${x.value==="dark"?"☼":"☾"}
+
+ ↺ Reset
+
+ ${g.value?"❚❚ Pause":"▶ Run"}
+
+ `}};De.styles=y`
+ :host {
+ display: flex; align-items: center;
+ padding: 0 16px; gap: 12px;
+ background: var(--bg-1);
+ border-bottom: 1px solid var(--line);
+ z-index: 10;
+ }
+ .crumbs { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-3); }
+ .crumbs .sep { color: var(--ink-4); }
+ .crumbs .cur { color: var(--ink); font-weight: 500; }
+ .spacer { flex: 1; }
+ .pill {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 5px 10px;
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 12px; color: var(--ink-2);
+ font-family: var(--mono); font-weight: 500;
+ }
+ .pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 6px var(--ok); animation: pulse 2s infinite; }
+ .pill.wasm .dot { background: var(--accent-2); box-shadow: 0 0 6px var(--accent-2); }
+ .pill.seed { color: var(--ink-3); cursor: pointer; }
+ .pill.seed:hover { border-color: var(--line-2); }
+ .pill.seed b { color: var(--accent); font-weight: 600; }
+ .pill.wasm { cursor: pointer; }
+ .pill.wasm:hover { border-color: var(--line-2); }
+ button {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 6px 12px;
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: 8px;
+ font-size: 12.5px; font-weight: 500; color: var(--ink);
+ cursor: pointer;
+ transition: all 0.15s;
+ }
+ button:hover { border-color: var(--line-2); background: var(--bg-3); }
+ button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }
+ button.primary:hover { filter: brightness(1.08); }
+ button.ghost { background: transparent; }
+ `;De=wt([k("nv-topbar")],De);var kt=Object.getOwnPropertyDescriptor,$t=(e,t,a,r)=>{for(var s=r>1?void 0:r?kt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=o(s)||s);return s};let Ae=null;function ge(){Ae!==null&&window.clearTimeout(Ae),Ae=window.setTimeout(async()=>{const e=h();if(e)try{await e.setConfig({digitiser:{f_s_hz:j.value,f_mod_hz:W.value},sensor:{gamma_fwhm_hz:1e6,t1_s:.005,t2_s:1e-6,t2_star_s:2e-7,contrast:.03,n_spins:1e12,shot_noise_disabled:!q.value},dt_s:U.value*.001}),d("dbg",`config pushed · fs=${j.value} f_mod=${W.value} dt=${U.value.toFixed(1)}ms noise=${q.value?"on":"off"}`)}catch(t){d("warn",`config push failed: ${t.message}`)}},300)}let Ee=class extends w{connectedCallback(){super.connectedCallback(),f(()=>{j.value,W.value,U.value,q.value,g.value,this.requestUpdate()})}render(){return p`
+
+
Scene 4 sources
+
+
+ rebar.steel.coil
+ χ=5000
+
+
+
+ heart_proxy
+ 1e-6 A·m²
+
+
+
+ mains_60Hz
+ 2 A · 60 Hz
+
+
+
+ door.steel
+ eddy
+
+
+
+
+
NV sensor COTS
+
V 1 mm³
+
N 1e12 NV
+
C 0.030
+
T₂* 200 ns
+
δB 1.18 pT/√Hz
+
+
+
+
Tunables
+
+
Sample rate ${(j.value/1e3).toFixed(1)} kHz
+
{j.value=+e.target.value,ge()}} />
+
+
+
Lockin f_mod ${(W.value/1e3).toFixed(3)} kHz
+
{W.value=+e.target.value,ge()}} />
+
+
+
Integration t ${U.value.toFixed(1)} ms
+
{U.value=+e.target.value,ge()}} />
+
+
+
Shot noise ${q.value?"ON":"OFF"}
+
{q.value=e.target.value==="1",ge()}} />
+
+
+
+
+
Pipeline
+
+ scene
+ →
+ B-S
+ →
+ prop
+ →
+ NV
+ →
+ ADC
+ →
+ frame
+
+
+ `}};Ee.styles=y`
+ :host {
+ display: flex; flex-direction: column; gap: 14px;
+ padding: 14px; overflow-y: auto;
+ background: var(--bg-1); border-right: 1px solid var(--line);
+ }
+ .panel {
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: var(--radius); padding: 12px;
+ }
+ .panel-h {
+ display: flex; align-items: center; justify-content: space-between;
+ font-size: 11px; font-weight: 600; color: var(--ink-3);
+ text-transform: uppercase; letter-spacing: 0.08em;
+ margin-bottom: 10px;
+ }
+ .count {
+ background: var(--bg-3); color: var(--ink-2);
+ padding: 1px 6px; border-radius: 999px;
+ font-family: var(--mono); font-size: 10px;
+ text-transform: none; letter-spacing: 0;
+ }
+ .scene-item {
+ display: flex; align-items: center; gap: 10px;
+ padding: 8px 10px;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ transition: background 0.15s;
+ border: 1px solid transparent;
+ }
+ .scene-item:hover { background: var(--bg-3); }
+ .scene-item .swatch { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
+ .scene-item .name { font-size: 13px; flex: 1; }
+ .scene-item .meta { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }
+ .field-row {
+ display: flex; align-items: center; justify-content: space-between;
+ padding: 6px 0; font-size: 12.5px;
+ border-bottom: 1px solid var(--line);
+ }
+ .field-row:last-child { border-bottom: 0; }
+ .field-row .lbl { color: var(--ink-3); }
+ .field-row .val { font-family: var(--mono); color: var(--ink); font-size: 12px; }
+ .slider-row { padding: 8px 0; border-bottom: 1px solid var(--line); }
+ .slider-row:last-child { border-bottom: 0; padding-bottom: 0; }
+ .slider-row .top { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 12px; }
+ .slider-row .top .lbl { color: var(--ink-3); }
+ .slider-row .top .val { font-family: var(--mono); color: var(--ink); }
+ input[type="range"] {
+ -webkit-appearance: none; appearance: none;
+ width: 100%; height: 4px;
+ background: var(--bg-3); border-radius: 2px; outline: none;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none; appearance: none;
+ width: 14px; height: 14px; border-radius: 50%;
+ background: var(--accent); cursor: pointer;
+ border: 2px solid var(--bg-2);
+ box-shadow: 0 0 0 1px var(--line-2);
+ }
+ .pipeline { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
+ .stage {
+ flex: 1; min-width: 50px;
+ padding: 4px 6px;
+ background: var(--bg-3); border: 1px solid var(--line);
+ border-radius: 6px; font-size: 9.5px; text-align: center;
+ color: var(--ink-2); font-family: var(--mono);
+ }
+ .stage.live { border-color: var(--accent-2); color: var(--accent-2); }
+ .stage-arrow { color: var(--ink-4); font-size: 10px; }
+ `;Ee=$t([k("nv-sidebar")],Ee);var St=Object.defineProperty,_t=Object.getOwnPropertyDescriptor,Q=(e,t,a,r)=>{for(var s=r>1?void 0:r?_t(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&St(t,a,s),s};let R=class extends w{constructor(){super(...arguments),this.zoom=1,this.layerVisible={source:!0,field:!0,label:!0},this.items=[{id:"rebar",x:740,y:240,color:"oklch(0.72 0.18 330)",name:"rebar.steel"},{id:"heart",x:220,y:180,color:"oklch(0.78 0.14 195)",name:"heart_proxy"},{id:"mains",x:180,y:380,color:"oklch(0.72 0.18 330)",name:"mains_60Hz"},{id:"door",x:800,y:470,color:"oklch(0.78 0.14 145)",name:"door.steel"}],this.dragging=null,this.selected=null,this.dragOffset={dx:0,dy:0},this.onDown=(e,t)=>{t.preventDefault(),this.dragging=e,this.selected=e;const a=this.items.find(i=>i.id===e);if(!a)return;const r=this.renderRoot.querySelector("svg");if(!r)return;const s=this.toSvg(t,r);this.dragOffset={dx:s.x-a.x,dy:s.y-a.y}},this.onPointerMove=e=>{if(!this.dragging)return;const t=this.renderRoot.querySelector("svg");if(!t)return;const a=this.toSvg(e,t);this.items=this.items.map(r=>r.id===this.dragging?{...r,x:a.x-this.dragOffset.dx,y:a.y-this.dragOffset.dy}:r)},this.onPointerUp=()=>{this.dragging&&(ie.value=this.items.map(({id:e,x:t,y:a})=>({id:e,x:t,y:a}))),this.dragging=null}}connectedCallback(){super.connectedCallback(),ie.value.length>0&&(this.items=this.items.map(e=>{const t=ie.value.find(a=>a.id===e.id);return t?{...e,x:t.x,y:t.y}:e})),f(()=>{fe.value,K.value,M.value,H.value,z.value,g.value,ue.value,oe.value,this.requestUpdate()}),f(()=>{const e=oe.value;if(!e)return;const t=Math.sqrt(e.bPt[0]**2+e.bPt[1]**2+e.bPt[2]**2),a=Math.max(Math.abs(e.sigmaPt[0]),Math.abs(e.sigmaPt[1]),Math.abs(e.sigmaPt[2]),.001),r=t/a;Number.isFinite(r)&&(H.value=r)}),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}async toggleRun(){const e=h();e&&(g.value?(await e.pause(),g.value=!1):(await e.run(),g.value=!0))}async stepFwd(){const e=h();e&&(await e.step("fwd",10),d("dbg","sim step → +1 frame"))}async stepBack(){const e=h();e&&(await e.step("back",10),d("dbg","sim step ← -1 frame"))}cycleSpeed(){const e=[.25,.5,1,2,4],t=e.indexOf(ue.value);ue.value=e[(t+1)%e.length]}zoomIn(){this.zoom=Math.min(2.5,this.zoom*1.2)}zoomOut(){this.zoom=Math.max(.5,this.zoom/1.2)}fitView(){this.zoom=1}toggleLayer(e){this.layerVisible={...this.layerVisible,[e]:!this.layerVisible[e]}}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp)}toSvg(e,t){const a=t.getBoundingClientRect(),r=(e.clientX-a.left)/a.width*1e3,s=(e.clientY-a.top)/a.height*600;return{x:r,y:s}}render(){const e=fe.value,t=[e[0]*1e9,e[1]*1e9,e[2]*1e9],a=K.value*1e9,r=z.value?"":"anim",s=1e3/this.zoom,i=600/this.zoom,o=(1e3-s)/2,n=(600-i)/2;return p`
+
+
+
+
+
+
+
+
+
+
+
+ ${this.layerVisible.field?this.items.map(l=>G`
+
+ `):""}
+
+
+ ${this.layerVisible.source?this.items.map(l=>G`
+ this.onDown(l.id,v)}>
+
+
+ ${this.layerVisible.label?G`${l.name} `:""}
+
+ `):""}
+
+
+
+
+
+
+
+
+
+ sensor · 〈111〉 NV
+
+
+ B_in: [${t[0].toFixed(2)}, ${t[1].toFixed(2)}, ${t[2].toFixed(2)}] nT
+
+
+
+
+
+ +
+ −
+ ⊡
+ this.toggleLayer("source")}>●
+ this.toggleLayer("field")}>≈
+ this.toggleLayer("label")}>T
+
+
+
+ ⏮
+
+ ${g.value?"❚❚":"▶"}
+
+ ⏭
+ ${ue.value}×
+
+
+
+
+
|B|
+
${a.toFixed(3)} nT
+
+
+
FPS
+
${M.value>0?Math.round(M.value):"—"}
+
+
+
SNR
+
${H.value>0?H.value.toFixed(1):"—"}
+
+
+ `}};R.styles=y`
+ :host {
+ display: block; height: 100%; width: 100%;
+ background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);
+ position: relative; overflow: hidden;
+ border-bottom: 1px solid var(--line);
+ }
+ .grid {
+ position: absolute; inset: 0;
+ background-image:
+ linear-gradient(var(--grid) 1px, transparent 1px),
+ linear-gradient(90deg, var(--grid) 1px, transparent 1px);
+ background-size: 32px 32px;
+ pointer-events: none;
+ mask-image: radial-gradient(ellipse at center, black 40%, transparent 100%);
+ }
+ svg { position: absolute; inset: 0; width: 100%; height: 100%; }
+ .stat-card {
+ background: rgba(13,17,23,0.7);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 8px 12px;
+ font-size: 11px;
+ min-width: 96px;
+ }
+ [data-theme="light"] .stat-card { background: rgba(255,255,255,0.85); }
+ .stat-card .lbl {
+ color: var(--ink-3);
+ text-transform: uppercase; font-weight: 600; letter-spacing: 0.06em; font-size: 9.5px;
+ }
+ .stat-card .val { font-family: var(--mono); font-size: 16px; font-weight: 600; margin-top: 2px; }
+ .stat-card .val.amber { color: var(--accent); }
+ .stat-card .val.cyan { color: var(--accent-2); }
+ .stat-card .val.mint { color: var(--accent-4); }
+ .scene-readout {
+ position: absolute; top: 14px; right: 14px;
+ display: flex; gap: 8px; z-index: 5;
+ }
+ .draggable { cursor: grab; transition: filter 0.15s; }
+ .draggable:hover { filter: brightness(1.15) drop-shadow(0 0 6px currentColor); }
+ .draggable.dragging { cursor: grabbing; filter: brightness(1.25) drop-shadow(0 0 10px currentColor); }
+ .field-line { stroke-dasharray: 4 6; }
+ @keyframes dash { to { stroke-dashoffset: -200; } }
+ .field-line.anim { animation: dash 4s linear infinite; }
+ @keyframes spin {
+ 0% { transform: rotateY(0) rotateX(8deg); }
+ 100% { transform: rotateY(360deg) rotateX(8deg); }
+ }
+ .crystal { transform-origin: center; transform-box: fill-box; }
+ .crystal.anim { animation: spin 12s linear infinite; }
+ .label {
+ font-family: var(--mono); font-size: 11px; fill: var(--ink-2);
+ pointer-events: none;
+ }
+ .scene-toolbar {
+ position: absolute; top: 14px; left: 14px;
+ display: flex; gap: 6px; z-index: 5;
+ background: rgba(13,17,23,0.85);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 4px;
+ }
+ [data-theme="light"] .scene-toolbar { background: rgba(255,255,255,0.85); }
+ .scene-toolbar button {
+ width: 28px; height: 28px;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: 6px;
+ color: var(--ink-2);
+ cursor: pointer;
+ display: grid; place-items: center;
+ font-size: 13px;
+ }
+ .scene-toolbar button:hover { color: var(--ink); background: var(--bg-2); }
+ .scene-toolbar button.on { background: var(--bg-3); color: var(--accent); border-color: var(--line-2); }
+
+ .sim-controls {
+ position: absolute; bottom: 14px; right: 14px;
+ display: flex; gap: 6px; align-items: center;
+ background: rgba(13,17,23,0.85);
+ backdrop-filter: blur(12px);
+ border: 1px solid var(--line-2);
+ border-radius: 999px;
+ padding: 6px 10px;
+ z-index: 5;
+ }
+ [data-theme="light"] .sim-controls { background: rgba(255,255,255,0.92); }
+ .sim-controls .play {
+ width: 32px; height: 32px;
+ background: var(--accent);
+ border: none;
+ border-radius: 50%;
+ color: #1a0f00;
+ cursor: pointer;
+ display: grid; place-items: center;
+ font-size: 13px;
+ }
+ .sim-controls .play:hover { filter: brightness(1.08); }
+ .sim-controls .step {
+ width: 26px; height: 26px;
+ border-radius: 6px;
+ background: transparent;
+ color: var(--ink-2);
+ border: 1px solid var(--line);
+ cursor: pointer;
+ font-size: 11px;
+ }
+ .sim-controls .step:hover { color: var(--ink); border-color: var(--line-2); }
+ .sim-controls .speed {
+ font-family: var(--mono); font-size: 11px;
+ color: var(--ink-2);
+ padding: 0 6px;
+ min-width: 36px;
+ text-align: center;
+ cursor: pointer;
+ }
+ `;Q([u()],R.prototype,"zoom",2);Q([u()],R.prototype,"layerVisible",2);Q([u()],R.prototype,"items",2);Q([u()],R.prototype,"dragging",2);Q([u()],R.prototype,"selected",2);R=Q([k("nv-scene")],R);var Mt=Object.defineProperty,zt=Object.getOwnPropertyDescriptor,Oe=(e,t,a,r)=>{for(var s=r>1?void 0:r?zt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Mt(t,a,s),s};let ne=class extends w{constructor(){super(...arguments),this.tab="signal",this.pinTab=null}connectedCallback(){super.connectedCallback(),f(()=>{xe.value,ye.value,we.value,ke.value,oe.value,A.value,$.value,fe.value,K.value,this.requestUpdate()})}willUpdate(e){e.has("pinTab")&&this.pinTab&&this.tab!==this.pinTab&&(this.tab=this.pinTab)}async verify(){const e=h();if(e){$.value="pending",d("info","verifying witness over 256 frames…");try{const t=Y.value,a=new Uint8Array(32);for(let s=0;s<32;s++)a[s]=parseInt(t.slice(s*2,s*2+2),16);const r=await e.verifyWitness(a);if(r.ok)$.value="ok",A.value=t,d("ok",`witness ${t.slice(0,16)}… matches · determinism gate ✓`);else{$.value="fail";const s=Array.from(r.actual).map(i=>i.toString(16).padStart(2,"0")).join("");A.value=s,d("err",`WITNESS MISMATCH actual=${s.slice(0,16)}…`)}}catch(t){$.value="fail",d("err",`verify failed: ${t.message}`)}}}renderSignalTab(){const i=o=>{let n="";return o.forEach((l,v)=>{const m=v/Math.max(1,199)*320,b=65-l*22;n+=(v===0?"M":"L")+` ${m.toFixed(1)} ${b.toFixed(1)} `}),n};return p`
+
+
+ B-vector trace
+ 3-axis · nT
+
+
+
+ ${G` `}
+ ${G` `}
+ ${G` `}
+
+
+
+
+
+ Frame stream
+ live
+
+
+ ${ke.value.map(o=>p`
`)}
+
+
+ `}renderFrameTab(){const e=oe.value,t=e?.raw;let a="";return t&&(a=Array.from(t).map(s=>s.toString(16).padStart(2,"0")).slice(0,60).join(" ")),p`
+
+
+ MagFrame v1 fields
+ 60 B
+
+
+ magic ${e?"0x"+e.magic.toString(16).toUpperCase():"—"}
+ version ${e?.version??"—"}
+ flags 0x${(e?.flags??0).toString(16).padStart(4,"0")}
+ sensor_id ${e?.sensorId??"—"}
+ t_us ${e?e.tUs.toString():"—"}
+ b_pT[0] ${e?e.bPt[0].toFixed(1):"—"}
+ b_pT[1] ${e?e.bPt[1].toFixed(1):"—"}
+ b_pT[2] ${e?e.bPt[2].toFixed(1):"—"}
+ noise_floor ${e?e.noiseFloorPtSqrtHz.toFixed(2):"—"}
+ temp_K ${e?e.temperatureK.toFixed(1):"—"}
+
+
+
+
+ Hex dump
+ LE
+
+
${a||"—"}
+
+ `}renderWitnessTab(){const e=$.value,t=e==="ok"?"ok":e==="fail"?"fail":"",a=e==="pending"?"Verifying…":e==="ok"?"✓ Witness verified · determinism gate":e==="fail"?"✗ Witness mismatch · audit required":"Verify witness";return p`
+
+
+ Expected (Proof::EXPECTED_WITNESS_HEX)
+ SHA-256
+
+
${Y.value||"(loading…)"}
+
+
+
+ Actual (last verify)
+ SHA-256
+
+
${A.value||"(not verified yet)"}
+
${a}
+
+ `}render(){return p`
+
+ this.tab="signal"}>Signal
+ this.tab="frame"}>Frame
+ this.tab="witness"}>Witness
+
+
+ ${this.tab==="signal"?this.renderSignalTab():this.tab==="frame"?this.renderFrameTab():this.renderWitnessTab()}
+
+ `}};ne.styles=y`
+ :host {
+ display: flex; flex-direction: column;
+ background: var(--bg-1);
+ border-left: 1px solid var(--line);
+ overflow: hidden;
+ height: 100%;
+ }
+ .tabs {
+ display: flex; border-bottom: 1px solid var(--line);
+ }
+ .tab {
+ flex: 1;
+ padding: 11px 8px;
+ background: transparent; border: none;
+ font-size: 11.5px; font-weight: 500;
+ color: var(--ink-3);
+ border-bottom: 2px solid transparent;
+ cursor: pointer; transition: color 0.15s, border-color 0.15s;
+ }
+ .tab.active { color: var(--ink); border-bottom-color: var(--accent); }
+ .tab:hover { color: var(--ink-2); }
+ .body { padding: 14px; flex: 1; overflow-y: auto; }
+
+ .card {
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: var(--radius); padding: 12px;
+ margin-bottom: 12px;
+ }
+ .card-h {
+ display: flex; justify-content: space-between; align-items: center;
+ margin-bottom: 8px;
+ }
+ .card-h .ttl { font-size: 12px; font-weight: 600; }
+ .badge {
+ font-family: var(--mono); font-size: 10px;
+ padding: 2px 6px;
+ background: oklch(0.78 0.14 195 / 0.12);
+ color: var(--accent-2);
+ border-radius: 4px;
+ border: 1px solid oklch(0.78 0.14 195 / 0.3);
+ }
+ svg { width: 100%; height: 130px; }
+ .frame-strip {
+ height: 28px;
+ display: flex; align-items: flex-end; gap: 1px;
+ padding: 4px 0;
+ }
+ .bar {
+ flex: 1;
+ background: linear-gradient(to top, var(--accent-2), var(--accent));
+ border-radius: 1px;
+ min-height: 2px;
+ }
+ table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 10.5px; }
+ td { padding: 4px 0; border-bottom: 1px solid var(--line); }
+ td:first-child { color: var(--ink-3); }
+ td:last-child { text-align: right; color: var(--ink); }
+ .hex {
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 10px;
+ font-family: var(--mono);
+ font-size: 10.5px;
+ color: var(--ink-2);
+ line-height: 1.6;
+ overflow-x: auto;
+ white-space: nowrap;
+ }
+ .hex .magic { color: var(--accent); font-weight: 600; }
+ .witness-box {
+ font-family: var(--mono);
+ font-size: 11px;
+ color: var(--ink-2);
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 8px 10px;
+ word-break: break-all;
+ line-height: 1.5;
+ }
+ .verify-btn {
+ margin-top: 10px;
+ width: 100%;
+ padding: 8px;
+ border: 1px solid var(--line);
+ background: var(--bg-3);
+ color: var(--ink);
+ border-radius: 8px;
+ cursor: pointer;
+ font-family: var(--mono);
+ font-size: 12px;
+ }
+ .verify-btn:hover { border-color: var(--accent); }
+ .verify-btn.ok { border-color: var(--ok); color: var(--ok); }
+ .verify-btn.fail { border-color: var(--bad); color: var(--bad); }
+ `;Oe([u()],ne.prototype,"tab",2);Oe([Fe({attribute:!1})],ne.prototype,"pinTab",2);ne=Oe([k("nv-inspector")],ne);var Ct=Object.defineProperty,Pt=Object.getOwnPropertyDescriptor,Ge=(e,t,a,r)=>{for(var s=r>1?void 0:r?Pt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Ct(t,a,s),s};let $e=class extends w{constructor(){super(...arguments),this.hIdx=-1,this.onKey=e=>{if(e.key==="Enter")this.exec(this.inputEl.value),this.inputEl.value="";else if(e.key==="ArrowUp"){const t=N.value;t.length&&(this.hIdx=Math.max(0,this.hIdx-1),this.inputEl.value=t[this.hIdx]??"",e.preventDefault())}else if(e.key==="ArrowDown"){const t=N.value;t.length&&(this.hIdx=Math.min(t.length,this.hIdx+1),this.inputEl.value=t[this.hIdx]??"",e.preventDefault())}}}connectedCallback(){super.connectedCallback(),f(()=>{T.value,Te.value,ae.value,this.requestUpdate()})}updated(){const e=this.renderRoot.querySelector(".body");e&&(e.scrollTop=e.scrollHeight)}counts(){const e={info:0,warn:0,err:0,dbg:0,ok:0};for(const t of T.value)e[t.level]=(e[t.level]??0)+1;return e.all=T.value.length,e}async exec(e){if(e=e.trim(),!e)return;d("info",`nvsim> ${e}`),pt(e),this.hIdx=N.value.length;const[t,...a]=e.split(/\s+/),r=a.join(" "),s=h();switch(t){case"help":d("info","commands: help · scene.list · sensor.config · run · pause · reset · seed · proof.verify · proof.export · clear · theme · status");break;case"scene.list":d("info","scene rebar-walkby-01:"),d("info"," rebar.steel.coil @ [+2.7, 0.0, +0.3] m χ=5000"),d("info"," dipole.heart_proxy @ [-1.4, +0.2, +0.4] m m=1.0e-6 A·m²"),d("info"," loop.mains_60Hz @ [-1.6, -0.4, 0.0] m I=2 A"),d("info"," eddy.door_steel @ [+0.0, +1.8, +0.4] m σ=1e6 S/m");break;case"sensor.config":d("info","NvSensor::cots_defaults() {"),d("info"," pos=[0,0,0], V=1mm³, N=1e12, C=0.03, T2*=200ns"),d("info"," D=2.870 GHz, γe=28 GHz/T, Γ=1.0 MHz, axes=4×〈111〉"),d("info"," δB ≈ 1.18 pT/√Hz (Barry 2020 §III.A) }");break;case"run":s&&(await s.run(),g.value=!0,d("ok","pipeline RUN"));break;case"pause":s&&(await s.pause(),g.value=!1,d("warn","pipeline PAUSED"));break;case"reset":s&&(await s.reset(),d("info","pipeline reset · t=0"));break;case"seed":{if(!r){d("info",`current seed = 0x${L.value.toString(16).toUpperCase()}`);break}const i=BigInt(r.startsWith("0x")?r:"0x"+r);L.value=i,s&&await s.setSeed(i),d("ok",`seed → 0x${i.toString(16).toUpperCase()}`);break}case"proof.verify":{if(!s)break;d("dbg","computing SHA-256 over 256 frames…");try{const i=Y.value,o=new Uint8Array(32);for(let l=0;l<32;l++)o[l]=parseInt(i.slice(l*2,l*2+2),16);(await s.verifyWitness(o)).ok?($.value="ok",A.value=i,d("ok",`witness ${i.slice(0,16)}… matches · determinism gate ✓`)):($.value="fail",d("err","WITNESS MISMATCH"))}catch(i){d("err",`verify failed: ${i.message}`)}break}case"proof.export":{if(!s)break;d("dbg","building proof bundle…");try{const i=await s.exportProofBundle(),o=URL.createObjectURL(i),n=document.createElement("a");n.href=o,n.download=`nvsim-proof-${Date.now()}.json`,n.click(),URL.revokeObjectURL(o),d("ok",`proof bundle exported · ${i.size} bytes`)}catch(i){d("err",`export failed: ${i.message}`)}break}case"clear":T.value=[];break;case"theme":{const i=(r||"").toLowerCase();i==="light"||i==="dark"?(x.value=i,d("ok",`theme → ${i}`)):d("info","theme [light|dark]");break}case"status":d("info",`running=${g.value} seed=0x${L.value.toString(16).toUpperCase()} verified=${$.value}`);break;default:d("err",`unknown command: ${t} · try help`)}}render(){const e=this.counts(),t=Te.value,a=T.value.filter(r=>t==="all"||r.level===t);return p`
+
+ ${["all","info","warn","err","dbg"].map(r=>p`
+
Te.value=r}>
+ ${r} ${e[r]??0}
+
+ `)}
+
+
+ T.value=[]}>×
+ ae.value=!ae.value}>
+ ${ae.value?"▶":"❚❚"}
+
+
+
+
+ ${a.map(r=>{const s=new Date(r.ts),i=`${String(s.getSeconds()).padStart(2,"0")}.${String(s.getMilliseconds()).padStart(3,"0")}`;return p`
`})}
+
+
+ nvsim>
+
+
+ `}};$e.styles=y`
+ :host {
+ display: flex; flex-direction: column;
+ background: var(--bg-1);
+ overflow: hidden;
+ }
+ .tabs {
+ display: flex; align-items: center;
+ border-bottom: 1px solid var(--line);
+ padding: 0 10px;
+ gap: 2px;
+ }
+ .tab {
+ padding: 8px 12px;
+ background: transparent; border: none;
+ font-size: 11.5px; color: var(--ink-3);
+ font-family: var(--mono);
+ border-bottom: 2px solid transparent;
+ cursor: pointer;
+ margin-bottom: -1px;
+ }
+ .tab.active { color: var(--ink); border-bottom-color: var(--accent); }
+ .tab .cnt {
+ background: var(--bg-3); padding: 1px 5px; border-radius: 999px;
+ font-size: 9.5px; color: var(--ink-2); margin-left: 4px;
+ }
+ .spacer { flex: 1; }
+ .tools { display: flex; gap: 4px; padding: 4px 0; }
+ .tools button {
+ width: 24px; height: 24px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-3);
+ font-size: 11px; cursor: pointer;
+ }
+ .tools button:hover { color: var(--ink); border-color: var(--line-2); }
+
+ .body {
+ flex: 1; overflow-y: auto;
+ font-family: var(--mono);
+ font-size: 11.5px;
+ padding: 6px 0;
+ background: var(--bg-0);
+ }
+ .line {
+ display: grid;
+ grid-template-columns: 70px 60px 1fr;
+ gap: 12px;
+ padding: 2px 12px;
+ color: var(--ink-2);
+ border-left: 2px solid transparent;
+ }
+ .line:hover { background: var(--bg-1); }
+ .ts { color: var(--ink-4); font-size: 10.5px; padding-top: 1px; }
+ .lvl {
+ font-size: 10px; font-weight: 600;
+ text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px;
+ }
+ .line.info .lvl { color: var(--accent-2); }
+ .line.warn .lvl { color: var(--warn); }
+ .line.warn { border-left-color: var(--warn); background: oklch(0.7 0.18 35 / 0.04); }
+ .line.err .lvl { color: var(--bad); }
+ .line.err { border-left-color: var(--bad); background: oklch(0.65 0.22 25 / 0.05); }
+ .line.dbg .lvl { color: var(--ink-3); }
+ .line.ok .lvl { color: var(--ok); }
+ .msg { color: var(--ink); white-space: pre-wrap; word-break: break-word; }
+
+ .input {
+ display: flex; align-items: center;
+ border-top: 1px solid var(--line);
+ background: var(--bg-0);
+ padding: 0 10px;
+ height: 32px; gap: 8px;
+ }
+ .prompt { color: var(--accent); font-family: var(--mono); font-size: 12px; }
+ input[type="text"] {
+ flex: 1; background: transparent; border: none; outline: none;
+ color: var(--ink); font-family: var(--mono); font-size: 12px;
+ height: 100%;
+ }
+ input::placeholder { color: var(--ink-4); }
+ `;Ge([We("#console-input")],$e.prototype,"inputEl",2);$e=Ge([k("nv-console")],$e);const re=[{id:"nvsim",name:"nvsim — NV-diamond magnetometer",category:"sim",crate:"nvsim",summary:"Deterministic forward simulator: scene → Biot–Savart → NV ensemble → ADC → MagFrame stream + SHA-256 witness.",budget:"L",active:!0,status:"available",tags:["quantum","magnetometer","simulator","witness","wasm"],adr:"ADR-089"},{id:"gesture",name:"Gesture (DTW)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Dynamic-Time-Warping gesture classifier from CSI motion templates.",events:[1],budget:"M",status:"available",tags:["hci","csi","classifier","dtw"],adr:"ADR-014"},{id:"coherence",name:"Coherence gate",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Z-score coherence scoring + Accept/PredictOnly/Reject/Recalibrate gate.",events:[2],budget:"S",status:"available",tags:["gate","csi","coherence","drift"],adr:"ADR-029"},{id:"adversarial",name:"Adversarial-signal detector",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Physically-impossible-signal detector — multi-link consistency, used to flag spoofed CSI.",events:[3],budget:"M",status:"available",tags:["security","csi","spoofing","mesh"],adr:"ADR-032"},{id:"rvf",name:"RVF — Rust Verified Feature stream",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Verified-frame builder with SHA-256 hash + version metadata for the feature stream.",budget:"S",status:"available",tags:["witness","csi","hash"],adr:"ADR-040"},{id:"occupancy",name:"Occupancy estimator",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Through-wall presence + person-count via CSI amplitude perturbation.",events:[300,301,302],budget:"S",status:"available",tags:["csi","building","presence"]},{id:"vital_trend",name:"Vital-trend monitor",category:"med",crate:"wifi-densepose-wasm-edge",summary:"HR + BR trend tracking with bradycardia/tachycardia/apnea events.",events:[100,101,102,103,104,105],budget:"S",status:"available",tags:["medical","vitals","csi"],adr:"ADR-021"},{id:"intrusion",name:"Intrusion detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Zone-based intrusion alert from CSI motion patterns.",events:[200,201],budget:"S",status:"available",tags:["security","zone","csi"]},{id:"med_sleep_apnea",name:"Sleep-apnea detector",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Episodic respiratory pause detection during sleep cycles.",events:[105],budget:"S",status:"available",tags:["medical","sleep","breathing"]},{id:"med_cardiac_arrhythmia",name:"Cardiac arrhythmia",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Beat-to-beat irregularity classifier from cardiac micro-Doppler.",events:[103,104],budget:"M",status:"available",tags:["medical","cardiac","arrhythmia"]},{id:"med_respiratory_distress",name:"Respiratory distress",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Distress signature: rapid shallow breathing + accessory-muscle motion.",events:[101,102],budget:"S",status:"available",tags:["medical","breathing","icu"]},{id:"med_gait_analysis",name:"Gait analysis",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Stride length, cadence, asymmetry from through-wall CSI pose tracking.",budget:"M",status:"available",tags:["medical","gait","pose"]},{id:"med_seizure_detect",name:"Seizure detector",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Tonic-clonic seizure motion signature.",budget:"M",status:"beta",tags:["medical","neuro"]},{id:"sec_perimeter_breach",name:"Perimeter breach",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Approach/departure detection at user-defined boundary segments.",events:[210,211,212,213],budget:"S",status:"available",tags:["security","perimeter"]},{id:"sec_weapon_detect",name:"Metal anomaly / weapon",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Metal-perturbation flag in CSI; potential weapon presence (research).",events:[220,221,222],budget:"M",status:"research",tags:["security","metal","csi"]},{id:"sec_tailgating",name:"Tailgating detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Detect 2+ persons crossing a single-passage threshold.",events:[230,231,232],budget:"S",status:"available",tags:["security","access-control"]},{id:"sec_loitering",name:"Loitering detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Stationary occupancy past a configurable dwell threshold.",events:[240,241,242],budget:"S",status:"available",tags:["security","dwell"]},{id:"sec_panic_motion",name:"Panic motion",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"High-energy distress motion: struggle / fleeing pattern.",events:[250,251,252],budget:"S",status:"beta",tags:["security","distress"]},{id:"bld_hvac_presence",name:"HVAC presence",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Occupied/activity-level/departure-countdown for HVAC zones.",events:[310,311,312],budget:"S",status:"available",tags:["hvac","building","energy"]},{id:"bld_lighting_zones",name:"Lighting zones",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Per-zone light on/dim/off cues from occupancy.",events:[320,321,322],budget:"S",status:"available",tags:["lighting","building"]},{id:"bld_elevator_count",name:"Elevator count",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Person count inside elevator car from CSI.",events:[330],budget:"S",status:"available",tags:["elevator","building"]},{id:"bld_meeting_room",name:"Meeting-room utilization",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Meeting size + duration analytics for booking systems.",budget:"S",status:"available",tags:["meeting","analytics"]},{id:"bld_energy_audit",name:"Energy audit",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Continuous occupancy-vs-HVAC-state audit for energy savings.",budget:"M",status:"available",tags:["energy","audit"]},{id:"ret_queue_length",name:"Queue length",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Live queue-length tracking for checkout / kiosks.",budget:"S",status:"available",tags:["retail","queue"]},{id:"ret_dwell_heatmap",name:"Dwell heatmap",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Per-zone dwell time accumulation; analytics-only export.",budget:"M",status:"available",tags:["retail","heatmap"]},{id:"ret_customer_flow",name:"Customer flow",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Origin-destination flow graph through a store layout.",budget:"M",status:"available",tags:["retail","flow"]},{id:"ret_table_turnover",name:"Table turnover",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Restaurant table seat / vacate transitions.",budget:"S",status:"available",tags:["retail","restaurant"]},{id:"ret_shelf_engagement",name:"Shelf engagement",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Reach-to-shelf gestures and dwell at product zones.",budget:"M",status:"available",tags:["retail","shelf"]},{id:"ind_forklift_proximity",name:"Forklift proximity",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Worker-near-forklift safety alert.",budget:"S",status:"available",tags:["industrial","safety"]},{id:"ind_confined_space",name:"Confined-space monitor",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Last-person-out detection + presence audit for OSHA confined-space entries.",budget:"S",status:"available",tags:["industrial","osha"]},{id:"ind_clean_room",name:"Clean-room PPE / motion",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Motion patterns consistent with proper PPE-clad movement.",budget:"M",status:"beta",tags:["industrial","cleanroom"]},{id:"ind_livestock_monitor",name:"Livestock monitor",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Vital-sign + activity tracking for stall-bound livestock.",budget:"M",status:"beta",tags:["agriculture","livestock"]},{id:"ind_structural_vibration",name:"Structural vibration",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Building/equipment micro-vibration via CSI phase derivative.",budget:"M",status:"research",tags:["industrial","vibration"]},{id:"sig_coherence_gate",name:"Coherence gate (extended)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Hysteresis + multi-state coherence gate driving downstream apps.",budget:"S",status:"available",tags:["gate","csi"]},{id:"sig_flash_attention",name:"Flash attention (CSI)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Edge-friendly attention block for CSI subcarrier weighting.",budget:"M",status:"beta",tags:["attention","csi"]},{id:"sig_temporal_compress",name:"Temporal-tensor compress",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"RuVector temporal-tensor compression on the CSI buffer.",budget:"M",status:"available",tags:["compress","tensor"]},{id:"sig_sparse_recovery",name:"Sparse recovery",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"114→56 subcarrier sparse interpolation via L1 solver.",budget:"M",status:"available",tags:["sparse","csi"]},{id:"sig_mincut_person_match",name:"Mincut person-match",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Min-cut person assignment across multistatic frames.",budget:"M",status:"available",tags:["mincut","matching"]},{id:"sig_optimal_transport",name:"Optimal transport",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"OT-based feature alignment between mesh nodes.",budget:"M",status:"beta",tags:["ot","alignment"]},{id:"lrn_dtw_gesture_learn",name:"DTW gesture learn",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"On-device template learning for personalized gesture libraries.",budget:"M",status:"beta",tags:["lifelong","gesture"]},{id:"lrn_anomaly_attractor",name:"Anomaly attractor",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Novelty detector with dynamic-attractor recall.",budget:"M",status:"research",tags:["novelty","lifelong"]},{id:"lrn_meta_adapt",name:"Meta-adapt",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Meta-learning adapter for fast site-to-site transfer.",budget:"L",status:"research",tags:["meta-learning"]},{id:"lrn_ewc_lifelong",name:"EWC++ lifelong",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Elastic-weight-consolidation gate to avoid catastrophic forgetting.",budget:"M",status:"beta",tags:["lifelong","ewc"]},{id:"spt_pagerank_influence",name:"PageRank influence",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Graph-influence ranking on the multistatic mesh.",budget:"M",status:"beta",tags:["graph","pagerank"]},{id:"spt_micro_hnsw",name:"µHNSW vector index",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Tiny HNSW index for AETHER re-ID embeddings on-device.",budget:"M",status:"available",tags:["hnsw","reid"]},{id:"spt_spiking_tracker",name:"Spiking tracker",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Spiking-network multi-target tracker.",budget:"L",status:"research",tags:["snn","tracker"]},{id:"tmp_pattern_sequence",name:"Pattern sequence",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"Sequence-of-events pattern matcher (e.g. ingress→linger→egress).",budget:"M",status:"available",tags:["temporal","pattern"]},{id:"tmp_temporal_logic_guard",name:"Temporal logic guard",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"LTL/MTL safety-property guard over event streams.",budget:"M",status:"beta",tags:["ltl","safety"]},{id:"tmp_goap_autonomy",name:"GOAP autonomy",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"Goal-oriented action planning for adaptive routines.",budget:"L",status:"research",tags:["planning","autonomy"]},{id:"ais_prompt_shield",name:"Prompt shield",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Edge-side LLM prompt-injection guard for on-device assistants.",budget:"M",status:"beta",tags:["security","llm"]},{id:"ais_behavioral_profiler",name:"Behavioral profiler",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Anomalous-behaviour profiler (drift in motion habits).",budget:"M",status:"beta",tags:["anomaly","behaviour"]},{id:"qnt_quantum_coherence",name:"Quantum coherence",category:"qnt",crate:"wifi-densepose-wasm-edge",summary:"Coherence diagnostics adapted for quantum-sensor signals.",budget:"M",status:"research",tags:["quantum","coherence"]},{id:"qnt_interference_search",name:"Interference search",category:"qnt",crate:"wifi-densepose-wasm-edge",summary:"Interferometric anomaly search across mesh viewpoints.",budget:"L",status:"research",tags:["quantum","interference"]},{id:"aut_psycho_symbolic",name:"Psycho-symbolic agent",category:"aut",crate:"wifi-densepose-wasm-edge",summary:"Symbolic-rule + neural-feature hybrid for low-power autonomy loops.",budget:"L",status:"research",tags:["autonomy","symbolic"]},{id:"aut_self_healing_mesh",name:"Self-healing mesh",category:"aut",crate:"wifi-densepose-wasm-edge",summary:"Mesh-topology repair with per-node health gossip.",budget:"M",status:"beta",tags:["mesh","health"]},{id:"exo_ghost_hunter",name:"Ghost hunter (anomaly)",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Empty-room CSI anomaly detector — impulsive/periodic/drift/random + hidden-presence sub-detector.",events:[650,651,652,653],budget:"S",status:"available",tags:["anomaly","paranormal","csi"],adr:"ADR-041"},{id:"exo_breathing_sync",name:"Breathing sync",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Multi-person breathing synchrony analytics.",budget:"M",status:"beta",tags:["breathing","sync"]},{id:"exo_dream_stage",name:"Dream-stage classifier",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"NREM/REM stage classification from breathing + micro-motion.",budget:"M",status:"research",tags:["sleep","rem"]},{id:"exo_emotion_detect",name:"Emotion detector",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Coarse arousal/valence from breathing + heart-rate variability.",budget:"M",status:"research",tags:["affect"]},{id:"exo_gesture_language",name:"Gesture language",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Sign-language pattern recognition.",budget:"L",status:"research",tags:["hci","sign"]},{id:"exo_happiness_score",name:"Happiness score",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Aggregate well-being score from co-occupancy + activity dynamics.",budget:"M",status:"research",tags:["affect","wellbeing"]},{id:"exo_hyperbolic_space",name:"Hyperbolic space embed",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Hyperbolic embeddings for hierarchical scene structure.",budget:"L",status:"research",tags:["embedding","hyperbolic"]},{id:"exo_music_conductor",name:"Music conductor",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Map gesture energy to MIDI tempo/dynamics.",budget:"M",status:"research",tags:["midi","art"]},{id:"exo_plant_growth",name:"Plant-growth tracker",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Slow CSI drift tracking for greenhouse foliage growth.",budget:"L",status:"research",tags:["agriculture"]},{id:"exo_rain_detect",name:"Rain detector",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Outdoor CSI signature of rainfall.",budget:"M",status:"research",tags:["weather"]},{id:"exo_time_crystal",name:"Time-crystal periodicity",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Periodicity diagnostics with anti-aliasing harmonics.",budget:"M",status:"research",tags:["periodicity"]}],ee={sim:{label:"Simulators",color:"oklch(0.78 0.14 70)",range:"—"},med:{label:"Medical & Health",color:"oklch(0.65 0.22 25)",range:"100–199"},sec:{label:"Security & Safety",color:"oklch(0.7 0.18 35)",range:"200–299"},bld:{label:"Smart Building",color:"oklch(0.78 0.12 195)",range:"300–399"},ret:{label:"Retail & Hospitality",color:"oklch(0.78 0.14 145)",range:"400–499"},ind:{label:"Industrial",color:"oklch(0.72 0.18 330)",range:"500–599"},sig:{label:"Signal Processing",color:"oklch(0.78 0.14 70)",range:"600–619"},lrn:{label:"Online Learning",color:"oklch(0.78 0.12 260)",range:"620–639"},spt:{label:"Spatial / Graph",color:"oklch(0.7 0.18 100)",range:"640–659"},tmp:{label:"Temporal / Planning",color:"oklch(0.7 0.16 50)",range:"660–679"},ais:{label:"AI Safety",color:"oklch(0.65 0.22 25)",range:"700–719"},qnt:{label:"Quantum",color:"oklch(0.72 0.18 290)",range:"720–739"},aut:{label:"Autonomy",color:"oklch(0.78 0.14 145)",range:"740–759"},exo:{label:"Exotic / Research",color:"oklch(0.72 0.18 330)",range:"650–699"}};function Tt(){return re.map(e=>({id:e.id,active:e.active===!0,eventCount:0}))}function At(e,t){if(!e)return 1;const a=e.toLowerCase();let r=0;return t.id.toLowerCase().includes(a)&&(r+=3),t.name.toLowerCase().includes(a)&&(r+=3),t.summary.toLowerCase().includes(a)&&(r+=1),t.tags?.some(s=>s.toLowerCase().includes(a))&&(r+=2),t.category===a&&(r+=5),r}const Rt="nvsim",Dt=1,J="kv";let me=null;function Ke(){return me||(me=new Promise((e,t)=>{const a=indexedDB.open(Rt,Dt);a.onupgradeneeded=()=>{const r=a.result;r.objectStoreNames.contains(J)||r.createObjectStore(J)},a.onsuccess=()=>e(a.result),a.onerror=()=>t(a.error)}),me)}async function F(e){const t=await Ke();return await new Promise((a,r)=>{const i=t.transaction(J,"readonly").objectStore(J).get(e);i.onsuccess=()=>a(i.result),i.onerror=()=>r(i.error)})}async function O(e,t){const a=await Ke();return await new Promise((r,s)=>{const i=a.transaction(J,"readwrite");i.objectStore(J).put(t,e),i.oncomplete=()=>r(),i.onerror=()=>s(i.error)})}var Et=Object.defineProperty,Ft=Object.getOwnPropertyDescriptor,Ye=(e,t,a,r)=>{for(var s=r>1?void 0:r?Ft(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Et(t,a,s),s};const I=c(Tt()),te=c(""),E=c("all"),S=c("all");(async()=>{const e=await F("app-activations");e&&(I.value=e)})();f(()=>{const e=I.value;e.length>0&&O("app-activations",e)});let Se=class extends w{constructor(){super(...arguments),this.renderTick=0}connectedCallback(){super.connectedCallback(),f(()=>{I.value,te.value,E.value,S.value,this.renderTick++})}isActive(e){return I.value.find(t=>t.id===e)?.active===!0}toggle(e){const t=I.value.map(a=>a.id===e.id?{...a,active:!a.active,lastActivatedAt:Date.now()}:a);I.value=t,d(this.isActive(e.id)?"ok":"info",`app ${e.id} deactivated`)}filtered(){let e=re;return E.value!=="all"&&(e=e.filter(t=>t.category===E.value)),S.value!=="all"&&(e=e.filter(t=>t.status===S.value)),te.value.trim()&&(e=e.map(t=>({a:t,s:At(te.value,t)})).filter(t=>t.s>0).sort((t,a)=>a.s-t.s).map(t=>t.a)),e}categoryCounts(){const e={all:re.length};for(const t of Object.keys(ee))e[t]=0;for(const t of re)e[t.category]=(e[t.category]??0)+1;return e}render(){const e=this.filtered(),t=this.categoryCounts(),a=I.value.filter(r=>r.active).length;return p`
+
+
+ App Store
+ ${re.length} edge apps · ${a} active
+
+
{te.value=r.target.value}} />
+
+
+
+ E.value="all"}>
+ All${t.all}
+
+ ${Object.keys(ee).map(r=>p`
+ E.value=r}>
+
+ ${ee[r].label}
+ ${t[r]??0}
+
+ `)}
+
+ S.value="all"}>any
+ S.value="available"}>available
+ S.value="beta"}>beta
+ S.value="research"}>research
+
+
+ ${e.length===0?p`No apps match the current filters.
`:p`${e.map(r=>this.card(r))}
`}
+ `}card(e){const t=this.isActive(e.id),a=ee[e.category];return p`
+
+
+
+ ${e.name}
+
+
${e.summary}
+
+ ${a.label}
+ ${e.status}
+ ${e.budget?p`budget ${e.budget} `:""}
+ ${e.adr?p`${e.adr} `:""}
+ ${e.events?.length?p`events ${e.events.join("·")} `:""}
+
+
+
+ `}};Se.styles=y`
+ :host {
+ display: block;
+ height: 100%;
+ overflow-y: auto;
+ background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);
+ padding: 24px;
+ }
+ .head {
+ display: flex; align-items: center; gap: 16px;
+ margin-bottom: 18px;
+ flex-wrap: wrap;
+ }
+ .ttl {
+ font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
+ color: var(--ink);
+ flex: 1; min-width: 200px;
+ }
+ .ttl small {
+ font-size: 12.5px; font-weight: 400;
+ color: var(--ink-3); margin-left: 8px;
+ }
+ .search {
+ width: 320px; max-width: 100%;
+ padding: 8px 12px;
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ font-family: var(--mono);
+ font-size: 12.5px;
+ color: var(--ink); outline: none;
+ }
+ .search:focus { border-color: var(--accent); }
+ .filters {
+ display: flex; flex-wrap: wrap; gap: 6px;
+ margin-bottom: 18px;
+ }
+ .chip {
+ padding: 4px 10px;
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 11.5px; color: var(--ink-3);
+ cursor: pointer;
+ font-family: var(--mono);
+ display: inline-flex; align-items: center; gap: 4px;
+ }
+ .chip:hover { color: var(--ink); border-color: var(--line-2); }
+ .chip.on { background: var(--bg-3); border-color: var(--accent); color: var(--ink); }
+ .chip .swatch {
+ width: 7px; height: 7px; border-radius: 50%;
+ }
+ .chip .count { color: var(--ink-3); font-size: 10px; }
+ .grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 12px;
+ }
+ .card {
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 12px 14px;
+ display: flex; flex-direction: column; gap: 6px;
+ transition: border-color 0.15s, transform 0.15s;
+ position: relative;
+ }
+ .card:hover { border-color: var(--line-2); transform: translateY(-1px); }
+ .card.active {
+ border-color: oklch(0.78 0.14 145 / 0.7);
+ background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 145 / 0.04) 100%);
+ }
+ .card-h {
+ display: flex; align-items: flex-start; gap: 8px;
+ margin-bottom: 2px;
+ }
+ .card-h .name {
+ font-size: 13.5px; font-weight: 600; color: var(--ink);
+ flex: 1; line-height: 1.3;
+ }
+ .card-h .swatch {
+ width: 10px; height: 10px; border-radius: 50%;
+ flex-shrink: 0; margin-top: 4px;
+ }
+ .summary {
+ font-size: 12px; color: var(--ink-2); line-height: 1.45;
+ flex: 1;
+ }
+ .meta {
+ display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;
+ font-family: var(--mono); font-size: 10px;
+ }
+ .badge {
+ padding: 1px 6px; border-radius: 4px;
+ background: var(--bg-3); color: var(--ink-3);
+ border: 1px solid var(--line);
+ }
+ .badge.cat { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.3); }
+ .badge.status-available { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }
+ .badge.status-beta { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }
+ .badge.status-research { color: var(--accent-3); border-color: oklch(0.72 0.18 330 / 0.4); }
+ .badge.budget { color: var(--accent-2); border-color: oklch(0.78 0.12 195 / 0.3); }
+ .card-foot {
+ display: flex; align-items: center; gap: 8px;
+ padding-top: 8px; margin-top: 4px;
+ border-top: 1px solid var(--line);
+ font-size: 11px; color: var(--ink-3);
+ }
+ .toggle {
+ position: relative;
+ width: 32px; height: 18px;
+ background: var(--bg-3); border: 1px solid var(--line-2);
+ border-radius: 999px; cursor: pointer;
+ transition: background 0.15s;
+ flex-shrink: 0;
+ }
+ .toggle::after {
+ content: ''; position: absolute;
+ top: 1px; left: 1px;
+ width: 12px; height: 12px;
+ background: var(--ink-3); border-radius: 50%;
+ transition: transform 0.15s, background 0.15s;
+ }
+ .toggle.on { background: var(--accent); border-color: var(--accent); }
+ .toggle.on::after { background: #1a0f00; transform: translateX(14px); }
+ .events {
+ font-family: var(--mono); font-size: 10px; color: var(--ink-3);
+ flex: 1;
+ }
+ .empty {
+ padding: 40px;
+ text-align: center; color: var(--ink-3);
+ font-size: 13px;
+ }
+ `;Ye([u()],Se.prototype,"renderTick",2);Se=Ye([k("nv-app-store")],Se);var Ot=Object.defineProperty,It=Object.getOwnPropertyDescriptor,pe=(e,t,a,r)=>{for(var s=r>1?void 0:r?It(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Ot(t,a,s),s};let V=class extends w{constructor(){super(...arguments),this.open=!1,this.filter="",this.idx=0,this.cmds=[{ico:"▶",label:"Run pipeline",kbd:"Space",run:async()=>{await h()?.run(),g.value=!0,C("Pipeline running","▶")}},{ico:"❚",label:"Pause pipeline",run:async()=>{await h()?.pause(),g.value=!1,C("Paused","❚❚")}},{ico:"+",label:"New scene…",kbd:"⌘N",run:()=>se({title:"New scene",body:`Build a fresh magnetic scene. The dashboard generates the JSON
+ and pushes it to the running pipeline (or you can copy the JSON
+ for offline use).
+ Name
+
+ Heart-proxy dipole moment (A·m²)
+
+ Distance heart → sensor (m)
+
+ Add ferrous distractor at +x = 1 m?
+
+ No
+ Yes (steel coil, χ=5000)
+
+ Add 60 Hz mains-current loop?
+
+ No
+ Yes (2 A loop, 5 cm radius, +y = 1 m)
+ `,buttons:[{label:"Cancel",variant:"ghost"},{label:"Create",variant:"primary",onClick:async()=>{const e=document.querySelector("nv-app")?.shadowRoot?.querySelector("nv-modal")?.shadowRoot;if(!e)return;const t=(e.querySelector("#ns-name")?.value??"custom").trim(),a=parseFloat(e.querySelector("#ns-moment")?.value??"1e-6"),r=parseFloat(e.querySelector("#ns-distance")?.value??"0.5"),s=e.querySelector("#ns-ferrous")?.value==="1",i=e.querySelector("#ns-mains")?.value==="1",o={dipoles:[{position:[0,0,r],moment:[0,0,a]}],loops:i?[{centre:[0,1,0],normal:[0,1,0],radius:.05,current:2,n_segments:64}]:[],ferrous:s?[{position:[1,0,0],volume:1e-4,susceptibility:5e3}]:[],eddy:[],sensors:[[0,0,0]],ambient_field:[1e-6,0,0]};await h()?.loadScene(o),d("ok",`scene ${t} loaded · 1 dipole · ${i?"1 loop · ":""}${s?"1 ferrous · ":""}1 sensor`),C(`Scene "${t}" loaded`,"+")}}]})},{ico:"📦",label:"Export proof bundle…",kbd:"⌘E",run:async()=>{const e=h();if(e){d("dbg","building proof bundle…");try{const t=await e.exportProofBundle(),a=URL.createObjectURL(t),r=document.createElement("a");r.href=a,r.download=`nvsim-proof-${Date.now()}.json`,r.click(),URL.revokeObjectURL(a),d("ok",`proof bundle exported · ${t.size} bytes`),C(`Proof bundle saved (${t.size} B)`,"📦")}catch(t){d("err",`export failed: ${t.message}`)}}}},{ico:"⟳",label:"Reset pipeline",kbd:"⌘R",run:()=>se({title:"Reset pipeline?",body:"Clears the frame stream and rewinds t to 0.
",buttons:[{label:"Cancel",variant:"ghost"},{label:"Reset",variant:"danger",onClick:async()=>{await h()?.reset(),d("warn","pipeline reset · t=0"),C("Pipeline reset","⟳")}}]})},{ico:"✓",label:"Verify witness",run:async()=>{const e=h();if(!e)return;$.value="pending";const t=Y.value,a=new Uint8Array(32);for(let s=0;s<32;s++)a[s]=parseInt(t.slice(s*2,s*2+2),16);(await e.verifyWitness(a)).ok?($.value="ok",A.value=t,C("Witness verified","✓")):($.value="fail",C("Witness mismatch!","✗"))}},{ico:"☼",label:"Toggle theme",kbd:"⌘/",run:()=>{x.value=x.value==="dark"?"light":"dark"}},{ico:"⚙",label:"Open settings",kbd:"⌘,",run:()=>window.dispatchEvent(new CustomEvent("open-settings"))},{ico:"?",label:"Keyboard shortcuts…",run:()=>se({title:"Keyboard shortcuts",body:`
+
⌘K / Ctrl K
Command palette
+
Space
Play / pause
+
⌘R
Reset
+
⌘,
Settings
+
⌘/
Toggle theme
+
\`
Debug HUD
+
1 · 2 · 3
Inspector tabs
+
Esc
Close modal/palette
+
/
Focus REPL
+
`,buttons:[{label:"Close",variant:"primary"}]})},{ico:"i",label:"About nvsim…",run:()=>se({title:"About nvsim",body:`nvsim is a deterministic, byte-reproducible forward simulator for nitrogen-vacancy diamond magnetometry.
+ This dashboard runs nvsim as WASM in a Web Worker. Same (scene, config, seed) → byte-identical SHA-256 witness across runs and machines.
+ License: MIT OR Apache-2.0 · See ADR-089, ADR-092.
`,buttons:[{label:"Close",variant:"primary"}]})}],this.onKey=e=>{(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="k"?(e.preventDefault(),this.openPal()):e.key==="Escape"&&this.open?this.closePal():this.open&&(e.key==="ArrowDown"?(this.idx=Math.min(this.cmds.length-1,this.idx+1),e.preventDefault()):e.key==="ArrowUp"?(this.idx=Math.max(0,this.idx-1),e.preventDefault()):e.key==="Enter"&&(this.runIdx(),e.preventDefault()))},this.onOpen=()=>this.openPal()}connectedCallback(){super.connectedCallback(),window.addEventListener("keydown",this.onKey),window.addEventListener("nv-palette",this.onOpen)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.onKey),window.removeEventListener("nv-palette",this.onOpen)}openPal(){this.open=!0,this.setAttribute("open",""),this.filter="",this.idx=0,setTimeout(()=>this.inputEl?.focus(),0)}closePal(){this.open=!1,this.removeAttribute("open")}filtered(){if(!this.filter.trim())return this.cmds;const e=this.filter.toLowerCase();return this.cmds.filter(t=>t.label.toLowerCase().includes(e))}runIdx(){const t=this.filtered()[this.idx];t&&(t.run(),this.closePal())}render(){const e=this.filtered();return p`
+
+
+ {this.filter=t.target.value,this.idx=0}} />
+
+
+ ${e.map((t,a)=>p`
+
{this.idx=a,this.runIdx()}}>
+ ${t.ico}
+ ${t.label}
+ ${t.kbd?p`${t.kbd} `:""}
+
+ `)}
+
+
+ `}};V.styles=y`
+ :host {
+ position: fixed; inset: 0; z-index: 220;
+ background: rgba(0,0,0,0.5);
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.15s;
+ display: flex; justify-content: center; padding-top: 12vh;
+ backdrop-filter: blur(4px);
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .palette {
+ width: min(560px, 92vw);
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ overflow: hidden;
+ display: flex; flex-direction: column;
+ max-height: 60vh;
+ }
+ .input {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ }
+ input {
+ width: 100%;
+ background: transparent; border: none; outline: none;
+ color: var(--ink); font-size: 14px;
+ font-family: inherit;
+ }
+ .list { flex: 1; overflow-y: auto; padding: 4px; }
+ .item {
+ display: flex; align-items: center; gap: 10px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 12.5px;
+ }
+ .item.active { background: var(--bg-3); }
+ .item .ico { width: 20px; text-align: center; color: var(--accent); }
+ .item .lbl { flex: 1; }
+ .item .kbd {
+ font-family: var(--mono); font-size: 10.5px;
+ color: var(--ink-3);
+ padding: 1px 5px; background: var(--bg-3); border-radius: 4px;
+ }
+ `;pe([u()],V.prototype,"open",2);pe([u()],V.prototype,"filter",2);pe([u()],V.prototype,"idx",2);pe([We("#palette-input")],V.prototype,"inputEl",2);V=pe([k("nv-palette")],V);var Lt=Object.defineProperty,Ht=Object.getOwnPropertyDescriptor,Ie=(e,t,a,r)=>{for(var s=r>1?void 0:r?Ht(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Lt(t,a,s),s};let le=class extends w{constructor(){super(...arguments),this.open=!1,this.renderFps=0,this.lastTs=performance.now(),this.frameCount=0,this.rafId=0,this.onKey=e=>{e.key==="`"&&!e.target.matches("input, textarea")&&(this.open=!this.open,this.toggleAttribute("open",this.open))},this.tick=()=>{this.rafId=requestAnimationFrame(this.tick);const e=performance.now();this.frameCount++,e-this.lastTs>=500&&(this.renderFps=this.frameCount*1e3/(e-this.lastTs),this.frameCount=0,this.lastTs=e,this.requestUpdate())}}connectedCallback(){super.connectedCallback(),window.addEventListener("keydown",this.onKey),f(()=>{M.value,Re.value,K.value,H.value,dt.value,this.requestUpdate()}),this.tick()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.onKey),cancelAnimationFrame(this.rafId)}render(){return p`
+ nvsim · debug {this.open=!1,this.removeAttribute("open")}}>✕
+ render fps ${this.renderFps.toFixed(1)}
+ sim fps ${M.value>0?Math.round(M.value):"—"}
+ frames ${Re.value.toString()}
+ |B| ${(K.value*1e9).toFixed(3)} nT
+ SNR ${H.value>0?H.value.toFixed(1):"—"}
+ DOM ${document.querySelectorAll("*").length}
+ `}};le.styles=y`
+ :host {
+ position: fixed; bottom: 8px; right: 8px;
+ width: 220px;
+ background: rgba(13,17,23,0.85);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--line-2);
+ border-radius: 8px;
+ padding: 8px 10px;
+ font-family: var(--mono); font-size: 11px;
+ color: var(--ink-2);
+ z-index: 99;
+ display: none;
+ box-shadow: var(--shadow);
+ }
+ :host([open]) { display: block; }
+ .h {
+ display: flex; justify-content: space-between;
+ font-weight: 600; color: var(--ink);
+ margin-bottom: 6px; padding-bottom: 4px;
+ border-bottom: 1px solid var(--line);
+ }
+ .x { cursor: pointer; color: var(--ink-3); }
+ .row {
+ display: flex; justify-content: space-between;
+ padding: 1px 0;
+ }
+ .k { color: var(--ink-3); }
+ .v { color: var(--ink); }
+ `;Ie([u()],le.prototype,"open",2);Ie([u()],le.prototype,"renderFps",2);le=Ie([k("nv-debug-hud")],le);var Nt=Object.defineProperty,Bt=Object.getOwnPropertyDescriptor,Xe=(e,t,a,r)=>{for(var s=r>1?void 0:r?Bt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Nt(t,a,s),s};let _e=class extends w{constructor(){super(...arguments),this.open=!1}connectedCallback(){super.connectedCallback(),f(()=>{x.value,_.value,z.value,ve.value,P.value,Pe.value,this.requestUpdate()}),window.addEventListener("open-settings",()=>{this.open=!0,this.setAttribute("open","")})}close(){this.open=!1,this.removeAttribute("open")}render(){return p`
+ this.close()}>
+
+
Settings
+
this.close()}>×
+
+
+
+
Appearance
+
+
+
+ x.value="dark"}>dark
+ x.value="light"}>light
+
+
+
+
+
Density
+
Affects panel padding and font scale.
+
+
+ _.value="comfy"}>comfy
+ _.value="default"}>default
+ _.value="compact"}>compact
+
+
+
+
+
Reduce motion
+
Disable rotating crystal & field-line animation.
+
+
z.value=!z.value}>
+
+
+
+
+
Pipeline
+
+
Auto-rerun on edit
+
Restart pipeline when scene/config changes.
+
ve.value=!ve.value}>
+
+
+
+
+
Transport
+
+
+
+ P.value="wasm"}>WASM
+ P.value="ws"}>WS
+
+
+ ${P.value==="ws"?p`
+
+
+
Pe.value=e.target.value} />
+
`:""}
+
+
+ `}};_e.styles=y`
+ :host {
+ position: fixed; top: 0; right: 0; bottom: 0;
+ width: 420px; max-width: 100vw;
+ background: var(--bg-1);
+ border-left: 1px solid var(--line);
+ z-index: 51;
+ transform: translateX(100%);
+ transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
+ display: flex; flex-direction: column;
+ box-shadow: -20px 0 60px -20px rgba(0,0,0,0.5);
+ }
+ :host([open]) { transform: translateX(0); }
+ .scrim {
+ position: fixed; inset: 0;
+ background: rgba(0,0,0,0.5);
+ z-index: 50;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.2s;
+ }
+ :host([open]) .scrim { opacity: 1; pointer-events: auto; }
+ .h {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ display: flex; align-items: center; justify-content: space-between;
+ }
+ .h .ttl { font-size: 14px; font-weight: 600; }
+ .body { flex: 1; overflow-y: auto; padding: 16px; }
+ .group { margin-bottom: 22px; }
+ .group h4 {
+ margin: 0 0 10px;
+ font-size: 11px; font-weight: 600;
+ text-transform: uppercase; letter-spacing: 0.08em;
+ color: var(--ink-3);
+ }
+ .row {
+ display: flex; justify-content: space-between; align-items: center;
+ padding: 10px 0;
+ border-bottom: 1px solid var(--line);
+ }
+ .row:last-child { border-bottom: 0; }
+ .row .lbl { font-size: 13px; }
+ .row .desc { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
+ .row > div:first-child { flex: 1; padding-right: 12px; }
+ .seg {
+ display: inline-flex;
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 2px;
+ }
+ .seg button {
+ padding: 4px 10px;
+ background: transparent; border: none;
+ border-radius: 6px;
+ font-size: 11.5px; color: var(--ink-3);
+ font-family: var(--mono);
+ cursor: pointer;
+ }
+ .seg button.on { background: var(--bg-1); color: var(--ink); }
+ .toggle {
+ position: relative;
+ width: 36px; height: 20px;
+ background: var(--bg-3);
+ border: 1px solid var(--line-2);
+ border-radius: 999px;
+ cursor: pointer;
+ flex-shrink: 0;
+ }
+ .toggle::after {
+ content: ''; position: absolute;
+ top: 2px; left: 2px;
+ width: 14px; height: 14px;
+ background: var(--ink-3);
+ border-radius: 50%;
+ transition: transform 0.15s, background 0.15s;
+ }
+ .toggle.on { background: var(--accent); border-color: var(--accent); }
+ .toggle.on::after { background: #1a0f00; transform: translateX(16px); }
+ .close {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-2);
+ }
+ input[type="text"] {
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 6px 10px;
+ color: var(--ink); font-family: var(--mono); font-size: 12px;
+ outline: none;
+ }
+ `;Xe([u()],_e.prototype,"open",2);_e=Xe([k("nv-settings-drawer")],_e);var Vt=Object.defineProperty,jt=Object.getOwnPropertyDescriptor,Le=(e,t,a,r)=>{for(var s=r>1?void 0:r?jt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Vt(t,a,s),s};const be=[{title:"Welcome to nvsim",body:`nvsim is an open-source, deterministic forward simulator for
+ nitrogen-vacancy diamond magnetometry — a real Rust crate compiled to
+ WASM and running in your browser, right now.
+ This 30-second tour highlights the four panels you'll use most.
`,cta:"Start tour"},{title:"1. Scene canvas",body:`The middle panel shows your magnetic scene — sources you can
+ drag (rebar, heart proxy, mains hum, ferrous door) and a single NV-diamond
+ sensor in the centre. Field lines from each source connect to the sensor
+ and animate while the pipeline runs.
+ Click 2 on your keyboard any time to jump to the Frame inspector.
`},{title:"2. Run the pipeline",body:`Click the ▶ Run button (top-right) to start streaming
+ MagFrame records at the digitiser's sample rate. The B-vector
+ trace and Frame stream sparkline update live, and the FPS pill in the
+ topbar shows the simulator's throughput in kHz.
+ Space toggles run/pause from anywhere.
`},{title:"3. Witness panel",body:`The Witness tab is the heart of nvsim's determinism contract.
+ Click Verify and the pipeline re-derives the SHA-256 over a 256-frame
+ reference run and asserts it matches the constant pinned in the Rust crate.
+ Same input → same hash → byte-for-byte across browsers, OSes, transports.
+ If the hash drifts, your build is non-canonical.
`},{title:"4. App Store",body:`The grid icon on the left rail opens the App Store — every
+ hot-loadable WASM edge module RuView ships, plus the simulators. 66 apps
+ across 13 categories: medical, security, building, retail, industrial,
+ signal, learning, autonomy, and more.
+ Toggle any card to mark it active in this session; the WS transport
+ will push the activation set to a connected ESP32 mesh.
`},{title:"You are ready",body:`Press ⌘K (or Ctrl K ) any time for the command
+ palette, ? for the full shortcuts list, or just start clicking.
+ Source on GitHub:
+ github.com/ruvnet/RuView · ADR-089, ADR-092 · MIT/Apache-2.0.
`,cta:"Get started"}];let de=class extends w{constructor(){super(...arguments),this.open=!1,this.step=0,this.show=()=>{this.step=0,this.open=!0,this.setAttribute("open","")}}async connectedCallback(){super.connectedCallback(),window.addEventListener("nv-show-tour",this.show),await F("onboarding-seen")||(this.open=!0,this.setAttribute("open",""))}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-show-tour",this.show)}async dismiss(){this.open=!1,this.removeAttribute("open"),await O("onboarding-seen",!0)}next(){this.step0&&this.step--}render(){const e=be[this.step];return p`
+
+
+
${e.title}
+ this.dismiss()} aria-label="Skip tour">×
+
+
+
+
+ `}};de.styles=y`
+ :host {
+ position: fixed; inset: 0;
+ background: rgba(0, 0, 0, 0.55);
+ backdrop-filter: blur(4px);
+ z-index: 240;
+ display: grid; place-items: center;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.18s;
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .card {
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ width: min(560px, 92vw);
+ max-height: 86vh;
+ display: flex; flex-direction: column;
+ transform: translateY(12px) scale(0.98);
+ transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);
+ }
+ :host([open]) .card { transform: translateY(0) scale(1); }
+ .h {
+ padding: 20px 22px 8px;
+ display: flex; justify-content: space-between; align-items: flex-start;
+ }
+ .h h2 { margin: 0; font-size: 18px; letter-spacing: -0.01em; }
+ .body {
+ padding: 8px 22px 16px;
+ font-size: 13px; color: var(--ink-2); line-height: 1.55;
+ overflow-y: auto;
+ }
+ .body p { margin: 0 0 12px; }
+ .body code, .body kbd {
+ font-family: var(--mono); font-size: 11.5px;
+ padding: 1px 5px; background: var(--bg-3);
+ border: 1px solid var(--line); border-radius: 4px;
+ color: var(--accent);
+ }
+ .footer {
+ display: flex; align-items: center; gap: 12px;
+ padding: 12px 22px;
+ border-top: 1px solid var(--line);
+ }
+ .dots { display: flex; gap: 6px; flex: 1; }
+ .dot {
+ width: 6px; height: 6px; border-radius: 50%;
+ background: var(--bg-3); border: 1px solid var(--line-2);
+ }
+ .dot.active { background: var(--accent); border-color: var(--accent); }
+ button {
+ padding: 8px 14px;
+ border-radius: 8px;
+ font-size: 12.5px; font-weight: 500;
+ border: 1px solid var(--line);
+ background: var(--bg-2); color: var(--ink);
+ cursor: pointer;
+ font-family: inherit;
+ }
+ button.primary {
+ background: var(--accent); border-color: var(--accent);
+ color: #1a0f00;
+ }
+ button.ghost { background: transparent; }
+ .skip {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px; color: var(--ink-2);
+ }
+ `;Le([u()],de.prototype,"open",2);Le([u()],de.prototype,"step",2);de=Le([k("nv-onboarding")],de);var Wt=Object.defineProperty,Ut=Object.getOwnPropertyDescriptor,Z=(e,t,a,r)=>{for(var s=r>1?void 0:r?Ut(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Wt(t,a,s),s};const qt=[{id:"nvBest",label:"NV-ensemble (best lab)",floorT:1e-12,color:"oklch(0.78 0.14 70)"},{id:"nvCots",label:"NV-DNV-B1 (COTS)",floorT:3e-10,color:"oklch(0.72 0.18 50)"},{id:"squid",label:"SQUID (shielded room)",floorT:1e-15,color:"oklch(0.78 0.12 195)"},{id:"mmw",label:"60 GHz mmWave (μ-Doppler)",floorT:0,color:"oklch(0.78 0.14 145)"},{id:"csi",label:"WiFi CSI (presence)",floorT:0,color:"oklch(0.72 0.18 330)"}];let D=class extends w{constructor(){super(...arguments),this.distanceM=.1,this.momentLog10=-8.3,this.result=null,this.running=!1,this.err=null}predictedDipoleFieldT(e,t){return 4*Math.PI*1e-7*t/(4*Math.PI*Math.pow(Math.max(e,1e-6),3))}async runDemo(){const e=h();if(!e){this.err="WASM client not ready";return}this.err=null,this.running=!0,this.requestUpdate();try{const t=this.distanceM,a=Math.pow(10,this.momentLog10),r={dipoles:[{position:[0,0,t],moment:[0,0,a]}],loops:[],ferrous:[],eddy:[],sensors:[[0,0,0]],ambient_field:[0,0,0]},s={digitiser:{f_s_hz:1e4,f_mod_hz:1e3},sensor:{gamma_fwhm_hz:1e6,t1_s:.005,t2_s:1e-6,t2_star_s:2e-7,contrast:.03,n_spins:1e12,shot_noise_disabled:!1},dt_s:null};this.result=await e.runTransient(r,s,42n,64),d("ok",`ghost-demo · r=${t.toFixed(3)} m · |B| recovered = ${(this.result.bMagT*1e12).toExponential(2)} pT`)}catch(t){this.err=t.message,d("err",`ghost-demo failed: ${this.err}`)}finally{this.running=!1,this.requestUpdate()}}formatField(e){if(e===0)return"0 T";const t=Math.abs(e);return t>=.001?`${(e*1e3).toFixed(2)} mT`:t>=1e-6?`${(e*1e6).toFixed(2)} µT`:t>=1e-9?`${(e*1e9).toFixed(3)} nT`:t>=1e-12?`${(e*1e12).toFixed(2)} pT`:t>=1e-15?`${(e*1e15).toFixed(2)} fT`:t>=1e-18?`${(e*1e18).toFixed(2)} aT`:`${e.toExponential(2)} T`}formatDistance(e){return e<1?`${(e*100).toFixed(1)} cm`:e<1e3?`${e.toFixed(2)} m`:e<1e5?`${(e/1e3).toFixed(2)} km`:`${(e/1609).toFixed(0)} mi`}renderDemo(){const e=Math.pow(10,this.momentLog10),t=this.predictedDipoleFieldT(this.distanceM,e),a=this.result?.bMagT??0,r=(this.result?.noiseFloorPtSqrtHz??0)*1e-12,s=qt.map(n=>{let l="bad",v="below floor";if(n.id==="mmw")this.distanceM<=5?(l="ok",v="µ-Doppler @ chest"):this.distanceM<=15?(l="warn",v="edge of range"):(l="bad",v="out of range");else if(n.id==="csi")this.distanceM<=30?(l=this.distanceM<=10?"ok":"warn",v="presence/breathing"):(l="bad",v="out of range");else if(n.floorT>0){const b=t/n.floorT;b>100?(l="ok",v=`${b.toExponential(1)}× floor`):b>1?(l="warn",v=`${b.toFixed(1)}× floor`):(l="bad",v=`${(1/b).toExponential(1)}× too weak`)}const m=n.floorT>0?Math.max(2,Math.min(100,100+12*Math.log10(t/n.floorT))):n.id==="mmw"?Math.max(2,100-this.distanceM*7):Math.max(2,100-this.distanceM*2);return p`
+
+
+
+ ${n.label}
+ ${v}
+
+
+ `}),i=t>1e-12?"ok":t>1e-15?"warn":"bad",o=i==="ok"?`Above NV-ensemble lab floor — close-range MCG plausible at ${this.formatDistance(this.distanceM)}.`:i==="warn"?`Below NV ensemble best, above SQUID — research-grade only at ${this.formatDistance(this.distanceM)}.`:`Below every published instrument's noise floor at ${this.formatDistance(this.distanceM)}. Press-release physics.`;return p`
+
+
Try it yourself
+
+ Place a cardiac dipole at variable distance from the NV sensor. The
+ dashboard runs the real nvsim Rust pipeline (compiled to WASM)
+ end-to-end and reports what each tier would actually detect. Same
+ determinism contract as the rest of the dashboard.
+
+
+
+
+
+ Distance from sensor
+ ${this.formatDistance(this.distanceM)}
+
+
{this.distanceM=Math.pow(10,+n.target.value)}} />
+
+ 10 cm → 100 km log scale
+
+
+
+
+ Heart dipole moment
+ ${e.toExponential(2)} A·m²
+
+
{this.momentLog10=+n.target.value}} />
+
+ published cardiac MCG ≈ 5×10⁻⁹ A·m²
+
+
+
this.runDemo()}>
+ ${this.running?"Running nvsim…":"▶ Run nvsim at this distance"}
+
+ ${this.err?p`
Error: ${this.err}
`:""}
+
+
+
+
+
+ Predicted |B| (1/r³)
+ ${this.formatField(t)}
+
+
+ Recovered |B| (nvsim)
+ ${this.result?this.formatField(a):"—"}
+
+
+ Sensor noise floor
+ ${this.result?this.formatField(r)+"/√Hz":"—"}
+
+
+ Frames run
+ ${this.result?.nFrames??"—"}
+
+
+ Witness (this run)
+ ${this.result?.witnessHex.slice(0,16)??"—"}…
+
+
+
+
+ Per-tier detectability
+
+ ${s}
+
+
+
+
${o}
+
+ The predicted value uses the closed-form magnetic-dipole
+ far field |B| = μ₀·m / (4π·r³). The recovered
+ value comes from the same Rust pipeline that drives the Witness panel —
+ scene → Biot-Savart → NV ensemble → ADC → MagFrame. Use the moment
+ slider to ask "what if the heart were stronger?". Use the distance
+ slider to walk through 10 cm (clinical MCG), 1 m (close approach),
+ 10 m (room-scale), 1 km (skeptic's range), and 65 km (the press claim).
+
+
+ `}render(){return p`
+ Ghost Murmur — open-source reality check
+
+ The physics-vs-press audit for the publicly-reported April 2026
+ CIA NV-diamond heartbeat detector, and how RuView's existing
+ stack maps onto an honest, civilian version of the same idea.
+
+
+
+
+ What the press reported
+
+
+
The story
+
3 Apr 2026: USAF F-15E pilot "Dude 44 Bravo" goes down in southern Iran during the regional exchange and evades for ~2 days.
+
President Trump publicly suggests detection from 40 miles away on a mountainside at night; CIA Director Ratcliffe says "invisible to the enemy, but not to the CIA."
+
+
+
The named tech
+
"Ghost Murmur" — Lockheed Skunk Works system using NV defects in synthetic diamond + AI to extract a heartbeat from environmental noise.
+
Outlets: Newsweek, Scientific American, Military.com, WION, Open The Magazine, Yahoo, Calcalist + HN thread #47679241.
+
+
+
What physicists said
+
Wikswo (Vanderbilt), Orzel (Union College), Roth (Oakland) — all pushing back hard.
+
"At 1 km, the heartbeat field drops to ~10⁻¹² of its 10 cm value." MCG-only at multi-mile range is not consistent with published physics .
+
+
+
+ Live demo — nvsim WASM
+ ${this.renderDemo()}
+
+ Physics reality check
+
+
+
+ Distance Cardiac MCG (peak QRS) vs Earth field (~50 µT)
+
+
+ 10 cm 50 pT 10⁹× weaker
+ 1 m 50 fT 10¹²× weaker
+ 10 m 50 aT 10¹⁵× weaker
+ 1 km 5 × 10⁻²³ T 10²⁷× weaker
+ 40 mi (65 km) ~10⁻²⁸ T 10³³× weaker
+
+
+
+ Best published NV-ensemble lab record: 0.9 pT/√Hz [Wolf 2015].
+ Best SQUID in a shielded room: ~1 fT/√Hz . To detect a single heartbeat at 10 m
+ you'd need ~2 billion× more sensitivity than any published ensemble has ever shown,
+ in a magnetically silent environment. 40 miles is press-release physics.
+
+
+
+ RuView's three-tier mesh — what is actually buildable
+ ┌──────────────────────────┐
+ │ Tier 3 — NV-diamond │ Range: 0.1–2 m (lab)
+ │ magnetometer ring │ Status: nvsim simulator only
+ │ (close-confirm) │ Hardware: $$$ (≥$8k DNV-B1)
+ └──────────┬───────────────┘
+ │
+ ┌──────────┴───────────────┐
+ │ Tier 2 — 60 GHz FMCW │ Range: 1–10 m HR/BR
+ │ mmWave radar mesh │ Status: shipping (ADR-021)
+ │ (vital signs, posture) │ Hardware: $15 (MR60BHA2 + ESP32-C6)
+ └──────────┬───────────────┘
+ │
+ ┌──────────┴───────────────┐
+ │ Tier 1 — WiFi CSI mesh │ Range: 10–30 m through-wall
+ │ (presence, breathing, │ Status: shipping (ADR-014, ADR-029)
+ │ pose, intention) │ Hardware: $9 (ESP32-S3 8MB)
+ └──────────┬───────────────┘
+ │
+ ▼
+ ┌────────────────────────────────┐
+ │ RuvSense multistatic fusion │
+ │ + cross-viewpoint attention │
+ │ + AETHER re-ID embeddings │
+ │ + Cramer-Rao gating │
+ └────────────────────────────────┘
+
+ Press claim → RuView equivalent
+
+
+
+ Press claim RuView equivalent today Crate / ADR Honest range
+
+
+
+ NV-diamond magnetometry
+ Deterministic NV pipeline simulator
+ nvsim · ADR-089
+ Simulator only
+
+
+ "AI strips environmental noise"
+ RuvSense multistatic fusion + AETHER
+ signal/ruvsense/ · ADR-029
+ Mature
+
+
+ Heartbeat at distance
+ 60 GHz FMCW HR/BR + WiFi CSI breathing
+ vitals · ADR-021
+ 1–5 m HR · 10–30 m presence
+
+
+ Long-range localisation
+ Multistatic time-of-flight + CRLB
+ ruvector/viewpoint/
+ Limited by node spacing
+
+
+ 40-mile single-heartbeat detection
+ Not feasible at any tier
+ —
+ Press-release physics
+
+
+
+
+
+ Build today on $165
+
+
+
Bill of materials
+
+ 3 × ESP32-S3 8 MB ($9 ea)
+ 3 × PoE injector + cat6 ($6 ea)
+ 1 × ESP32-C6 + Seeed MR60BHA2 ($15)
+ 1 × Raspberry Pi 5 8 GB ($80)
+ 1 × unmanaged GbE switch ($25)
+
+
Total: $165
+
+
+
Honest performance
+ 95% TPR (LOS, 0–15 m)
+ ±2 bpm HR (LOS 0–3 m)
+ ±1 br/min BR (any mode)
+ ~10 cm pose error
+ 80–150 ms end-to-end latency
+
+
+
Determinism
+
Same (scene, config, seed) → byte-identical SHA-256 witness across browsers, OSes, transports.
+
Reference: cc8de9b01b0ff5bd…
+
Try the Witness tab on the right — it re-derives the hash live in this browser and compares against the published reference.
+
+
+
+ Privacy, ethics, legal
+
+
This is the open-source version. Same physics, opposite governance.
+
+ Civilian opt-in only — search-and-rescue, elder-care, occupancy, ICU vitals. Not surveillance.
+ No directional pursuit — no beam-steering, target-following, or remote person-of-interest tracking.
+ Data minimisation — fused output is (presence, HR, BR, pose, p_alive); raw streams discarded at the edge.
+ PII gates (ADR-040) block identifying biometric streams from leaving the local mesh without consent.
+ Adversarial-signal detection flags physically-impossible signal patterns from compromised mesh nodes.
+ No export-controlled hardware — RuView targets < $50 COTS. ITAR/EAR sub-THz coherent radars and shielded NV ensembles are out of scope.
+
+
+ RuView is not affiliated with the United States government, the CIA, Lockheed Martin,
+ or any classified program. References to "Ghost Murmur" in this view refer
+ exclusively to the publicly-reported program of that name as covered in the open
+ press in April 2026.
+
+
+
+ Cross-references
+
+
+ ADRs: 014 (signal) · 021 (vitals) · 024 (AETHER) · 027 (MERIDIAN) ·
+ 028 (witness audit) · 029 (RuvSense) · 040 (PII gates) · 086 (ESP32 RaBitQ) ·
+ 089 (nvsim, Accepted) · 090 (Lindblad, Proposed-conditional) ·
+ 091 (sub-THz radar research) · 092 (this dashboard) .
+ Primary physics: Cohen 1970 · Bison 2009 · Wolf 2015 · Barry RMP 2020 · Doherty 2013 · Jackson 3e §5.6/§5.8.
+
+
+ `}};D.styles=y`
+ :host {
+ display: block;
+ height: 100%;
+ overflow-y: auto;
+ background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);
+ padding: 24px 28px 60px;
+ }
+ h1 {
+ margin: 0 0 4px;
+ font-size: 22px;
+ letter-spacing: -0.02em;
+ color: var(--ink);
+ }
+ .subtitle {
+ color: var(--ink-3);
+ font-size: 13px;
+ margin-bottom: 22px;
+ }
+ .links {
+ display: flex; flex-wrap: wrap; gap: 6px;
+ margin-bottom: 22px;
+ }
+ .links a {
+ padding: 5px 10px;
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 11.5px;
+ font-family: var(--mono);
+ color: var(--accent-2);
+ text-decoration: none;
+ }
+ .links a:hover { border-color: var(--accent-2); }
+ h2 {
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: var(--ink-3);
+ margin: 28px 0 10px;
+ }
+ .grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+ gap: 12px;
+ }
+ .card {
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 14px;
+ }
+ .card h3 {
+ margin: 0 0 8px;
+ font-size: 13.5px; font-weight: 600;
+ color: var(--ink);
+ }
+ .card p {
+ font-size: 12.5px; color: var(--ink-2);
+ margin: 0 0 8px;
+ line-height: 1.5;
+ }
+ .card p:last-child { margin-bottom: 0; }
+ .stat {
+ display: inline-flex; align-items: baseline; gap: 6px;
+ margin-right: 10px;
+ }
+ .stat .v {
+ font-family: var(--mono); font-size: 16px; font-weight: 600;
+ color: var(--accent);
+ }
+ .stat .l {
+ font-size: 10px; color: var(--ink-3);
+ text-transform: uppercase; letter-spacing: 0.04em;
+ }
+ table {
+ width: 100%; border-collapse: collapse;
+ font-size: 12.5px;
+ }
+ th, td {
+ padding: 8px 10px;
+ text-align: left;
+ border-bottom: 1px solid var(--line);
+ }
+ th {
+ color: var(--ink-3);
+ font-weight: 600;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ }
+ td.amber { color: var(--accent); font-family: var(--mono); }
+ td.cyan { color: var(--accent-2); font-family: var(--mono); }
+ td.bad { color: var(--bad); font-family: var(--mono); }
+ .pill {
+ display: inline-block;
+ padding: 1px 6px;
+ border-radius: 4px;
+ font-family: var(--mono);
+ font-size: 10px;
+ border: 1px solid var(--line);
+ }
+ .pill.ok { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }
+ .pill.skeptical { color: var(--bad); border-color: oklch(0.65 0.22 25 / 0.4); }
+ .pill.partial { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }
+ .architecture {
+ font-family: var(--mono);
+ font-size: 11px;
+ color: var(--ink-2);
+ background: var(--bg-3);
+ padding: 16px;
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--line);
+ white-space: pre;
+ overflow-x: auto;
+ line-height: 1.4;
+ }
+ .ethics {
+ background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.65 0.22 25 / 0.04) 100%);
+ border: 1px solid oklch(0.65 0.22 25 / 0.25);
+ border-radius: var(--radius);
+ padding: 16px;
+ }
+ .ethics h3 { color: var(--bad); margin-top: 0; }
+ .ethics ul { padding-left: 18px; margin: 8px 0; }
+ .ethics li { font-size: 12.5px; color: var(--ink-2); margin-bottom: 4px; }
+
+ /* Demo */
+ .demo {
+ background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 70 / 0.04) 100%);
+ border: 1px solid oklch(0.78 0.14 70 / 0.3);
+ border-radius: var(--radius);
+ padding: 18px;
+ }
+ .demo-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 18px;
+ margin-top: 12px;
+ }
+ @media (max-width: 720px) { .demo-grid { grid-template-columns: 1fr; } }
+ .control { margin-bottom: 14px; }
+ .control .top {
+ display: flex; justify-content: space-between;
+ font-size: 12px; margin-bottom: 6px;
+ }
+ .control .top .lbl { color: var(--ink-3); }
+ .control .top .val {
+ font-family: var(--mono); color: var(--ink);
+ }
+ .control input[type="range"] {
+ -webkit-appearance: none; appearance: none;
+ width: 100%; height: 4px;
+ background: var(--bg-3); border-radius: 2px; outline: none;
+ }
+ .control input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none; appearance: none;
+ width: 14px; height: 14px; border-radius: 50%;
+ background: var(--accent); cursor: pointer;
+ border: 2px solid var(--bg-2);
+ }
+ .demo-btn {
+ width: 100%;
+ padding: 10px;
+ border: 1px solid var(--accent);
+ background: var(--accent);
+ color: #1a0f00;
+ border-radius: 8px;
+ font-size: 13px; font-weight: 600;
+ cursor: pointer;
+ }
+ .demo-btn:hover { filter: brightness(1.08); }
+ .demo-btn:disabled { opacity: 0.6; cursor: progress; }
+ .readout {
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 12px;
+ }
+ .readout-row {
+ display: flex; justify-content: space-between;
+ padding: 4px 0;
+ font-family: var(--mono); font-size: 12px;
+ }
+ .readout-row .l { color: var(--ink-3); }
+ .readout-row .v { color: var(--ink); }
+ .readout-row .v.amber { color: var(--accent); }
+ .tier-bar {
+ position: relative;
+ margin: 6px 0;
+ height: 22px;
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 4px;
+ overflow: hidden;
+ }
+ .tier-bar .fill {
+ position: absolute; top: 0; bottom: 0; left: 0;
+ transition: width 0.2s ease-out;
+ border-right: 2px solid;
+ }
+ .tier-bar .lbl {
+ position: relative; z-index: 1;
+ font-family: var(--mono); font-size: 11px;
+ padding: 3px 8px;
+ color: var(--ink);
+ display: flex; justify-content: space-between;
+ pointer-events: none;
+ }
+ .verdict {
+ margin-top: 10px;
+ padding: 10px 12px;
+ border-radius: 8px;
+ font-size: 12.5px; font-weight: 500;
+ border: 1px solid;
+ }
+ .verdict.ok { background: oklch(0.78 0.14 145 / 0.08); border-color: oklch(0.78 0.14 145 / 0.4); color: var(--ok); }
+ .verdict.warn { background: oklch(0.7 0.18 35 / 0.08); border-color: oklch(0.7 0.18 35 / 0.4); color: var(--warn); }
+ .verdict.bad { background: oklch(0.65 0.22 25 / 0.08); border-color: oklch(0.65 0.22 25 / 0.4); color: var(--bad); }
+ .demo-notes {
+ font-size: 11.5px; color: var(--ink-3);
+ margin-top: 10px; line-height: 1.5;
+ }
+ `;Z([u()],D.prototype,"distanceM",2);Z([u()],D.prototype,"momentLog10",2);Z([u()],D.prototype,"result",2);Z([u()],D.prototype,"running",2);Z([u()],D.prototype,"err",2);D=Z([k("nv-ghost-murmur")],D);var Gt=Object.defineProperty,Kt=Object.getOwnPropertyDescriptor,Je=(e,t,a,r)=>{for(var s=r>1?void 0:r?Kt(t,a):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(s=(r?o(t,a,s):o(s))||s);return r&&s&&Gt(t,a,s),s};let Me=class extends w{constructor(){super(...arguments),this.view="scene"}render(){return p`
+ {e.preventDefault(),this.shadowRoot?.querySelector(".main")?.focus()}}>
+ Skip to main content
+
+
+ this.view=e.detail}>
+
+
+
+ ${this.view==="apps"?p` `:this.view==="ghost-murmur"?p` `:p` `}
+
+
+
+
+
+
+
+
+
+
+
+ `}};Me.styles=y`
+ :host {
+ display: block;
+ height: 100vh;
+ width: 100vw;
+ background: var(--bg-0);
+ }
+ .skip-link {
+ position: absolute;
+ top: -40px;
+ left: 8px;
+ padding: 6px 12px;
+ background: var(--accent);
+ color: #1a0f00;
+ border-radius: 6px;
+ font-size: 12.5px;
+ font-weight: 600;
+ text-decoration: none;
+ z-index: 1000;
+ transition: top 0.15s;
+ }
+ .skip-link:focus { top: 8px; }
+ .app {
+ display: grid;
+ grid-template-columns: 56px 280px 1fr 340px;
+ grid-template-rows: 48px 1fr 220px;
+ grid-template-areas:
+ 'rail topbar topbar topbar'
+ 'rail sidebar main inspector'
+ 'rail sidebar console inspector';
+ height: 100vh;
+ width: 100vw;
+ }
+ nv-rail { grid-area: rail; }
+ nv-topbar { grid-area: topbar; }
+ nv-sidebar { grid-area: sidebar; }
+ .main { grid-area: main; min-width: 0; min-height: 0; position: relative; overflow: hidden; }
+ nv-inspector { grid-area: inspector; }
+ nv-console { grid-area: console; min-height: 0; }
+ @media (max-width: 1180px) {
+ .app {
+ grid-template-columns: 56px 1fr 320px;
+ grid-template-areas:
+ 'rail topbar topbar'
+ 'rail main inspector'
+ 'rail console console';
+ }
+ nv-sidebar { display: none; }
+ }
+ @media (max-width: 860px) {
+ .app {
+ grid-template-columns: 1fr;
+ grid-template-rows: 52px 1fr 200px;
+ grid-template-areas:
+ 'topbar'
+ 'main'
+ 'console';
+ }
+ nv-rail, nv-sidebar, nv-inspector { display: none; }
+ }
+ `;Je([u()],Me.prototype,"view",2);Me=Je([k("nv-app")],Me);function Yt(e,t,a){const r=e.getUint32(t+0,!0),s=e.getUint16(t+4,!0),i=e.getUint16(t+6,!0),o=e.getUint16(t+8,!0),n=e.getBigUint64(t+12,!0),l=e.getFloat32(t+20,!0),v=e.getFloat32(t+24,!0),m=e.getFloat32(t+28,!0),b=e.getFloat32(t+32,!0),Ce=e.getFloat32(t+36,!0),Qe=e.getFloat32(t+40,!0),Ze=e.getFloat32(t+44,!0),et=e.getFloat32(t+48,!0);return{magic:r,version:s,flags:i,sensorId:o,tUs:n,bPt:[l,v,m],sigmaPt:[b,Ce,Qe],noiseFloorPtSqrtHz:Ze,temperatureK:et,raw:a.subarray(t,t+60)}}function Xt(e){const a=new DataView(e.buffer,e.byteOffset,e.byteLength),r=[];for(let s=0;s+60<=e.byteLength;s+=60)r.push(Yt(a,s,e));return r}class Jt{constructor(){this.nextId=1,this.pending=new Map,this.frameSubs=new Set,this.eventSubs=new Set,this.bootInfo=null,this.worker=new Worker(new URL("/RuView/nvsim/assets/worker-C19MRcXs.js",import.meta.url),{type:"module"}),this.worker.addEventListener("message",t=>this.onMessage(t)),this.worker.addEventListener("error",t=>this.eventSubs.forEach(a=>a({type:"log",level:"err",msg:String(t.message)})))}onMessage(t){const a=t.data;if(a.type==="frames"){const r=a.batch,s=new Uint8Array(r),o={frames:Xt(s),bytes:s};this.frameSubs.forEach(l=>l(o));const n=a.fps;n>0&&this.eventSubs.forEach(l=>l({type:"fps",value:n}));return}if(a.type==="state"){this.eventSubs.forEach(r=>r({type:"state",running:!!a.running,t:0,framesEmitted:Number(a.framesEmitted??0)}));return}if(a.type!=="ready"){if(a.type==="err"&&a.id==null){this.eventSubs.forEach(r=>r({type:"log",level:"err",msg:String(a.msg)}));return}if(typeof a.id=="number"&&this.pending.has(a.id)){const r=this.pending.get(a.id);this.pending.delete(a.id),a.type==="err"?r.reject(new Error(String(a.msg))):r.resolve(a)}}}rpc(t,a=[]){const r=this.nextId++;return new Promise((s,i)=>{this.pending.set(r,{resolve:s,reject:i}),this.worker.postMessage({...t,id:r},a)})}async boot(){if(this.bootInfo)return this.bootInfo;const a=await this.rpc({type:"boot",base:"/RuView/nvsim/"});return this.bootInfo={buildVersion:a.buildVersion,frameMagic:a.frameMagic,frameBytes:a.frameBytes,expectedWitnessHex:a.expectedWitnessHex},this.bootInfo}async loadScene(t){await this.rpc({type:"setScene",json:JSON.stringify(t)})}async setConfig(t){await this.rpc({type:"setConfig",json:JSON.stringify(t)})}async setSeed(t){await this.rpc({type:"setSeed",seed:Number(t&0xFFFFFFFFn)})}async reset(){await this.rpc({type:"reset"})}async run(t){await this.rpc({type:"run"})}async pause(){await this.rpc({type:"pause"})}async step(t,a){await this.rpc({type:"step"})}onFrames(t){this.frameSubs.add(t)}onEvent(t){this.eventSubs.add(t)}async generateWitness(t){const a=await this.rpc({type:"witnessGenerate",samples:t});return new Uint8Array(a.witness)}async verifyWitness(t){const a=t.slice().buffer,r=await this.rpc({type:"witnessVerify",samples:256,expected:a},[a]);return r.ok?{ok:!0}:{ok:!1,actual:new Uint8Array(r.actual)}}async runTransient(t,a,r,s){const i=await this.rpc({type:"runTransient",scene:JSON.stringify(t),config:JSON.stringify(a),seed:Number(r&0xFFFFFFFFn),samples:s});return{bRecoveredT:[i.bRecoveredT[0],i.bRecoveredT[1],i.bRecoveredT[2]],bMagT:i.bMagT,noiseFloorPtSqrtHz:i.noiseFloorPtSqrtHz,sigmaPt:[i.sigmaPt[0],i.sigmaPt[1],i.sigmaPt[2]],nFrames:i.nFrames,witnessHex:i.witnessHex}}async exportProofBundle(){const t=await this.generateWitness(256),a=Array.from(t).map(i=>i.toString(16).padStart(2,"0")).join(""),r=this.bootInfo??await this.boot(),s=JSON.stringify({kind:"nvsim-proof-bundle",version:r.buildVersion,seed:"0x0000002A",nSamples:256,witness:a,expected:r.expectedWitnessHex,ok:a===r.expectedWitnessHex,ts:new Date().toISOString()},null,2);return new Blob([s],{type:"application/json"})}async buildId(){return(await this.rpc({type:"buildId"})).buildId}async close(){this.worker.terminate()}}function Be(e){document.documentElement.setAttribute("data-theme",e)}function Ve(e){document.body.classList.remove("density-comfy","density-default","density-compact"),document.body.classList.add(`density-${e}`)}function je(e){document.body.classList.toggle("reduce-motion",e)}(async()=>{const e=await F("theme")??"dark",t=await F("density")??"default",a=window.matchMedia?.("(prefers-reduced-motion: reduce)").matches??!1,r=await F("motionReduced")??a;x.value=e,Be(e),_.value=t,Ve(t),z.value=r,je(r),f(()=>{Be(x.value),O("theme",x.value)}),f(()=>{Ve(_.value),O("density",_.value)}),f(()=>{je(z.value),O("motionReduced",z.value)});const s=await F("repl-history");s&&Array.isArray(s)&&(N.value=s),f(()=>{O("repl-history",N.value)});const i=await F("scene-positions");i&&Array.isArray(i)&&(ie.value=i),f(()=>{O("scene-positions",ie.value)});const o=new Jt;ut(o),d("info","nvsim — booting WASM runtime"),o.onEvent(n=>{n.type==="log"&&d(n.level,n.msg),n.type==="fps"&&(M.value=n.value),n.type==="state"&&(Re.value=BigInt(n.framesEmitted))}),o.onFrames(n=>{if(n.frames.length===0)return;const l=n.frames[n.frames.length-1];oe.value=l;const v=l.bPt[0]*1e-12,m=l.bPt[1]*1e-12,b=l.bPt[2]*1e-12;fe.value=[v,m,b],K.value=Math.sqrt(v*v+m*m+b*b),gt([v*1e9,m*1e9,b*1e9]);const Ce=Math.min(1,Math.abs(b*1e9)/5+.3);mt(Ce)});try{const n=await o.boot();Y.value=n.expectedWitnessHex,d("ok",`WASM module ready · nvsim@${n.buildVersion} · magic=0x${n.frameMagic.toString(16).toUpperCase()}`),d("info",`expected witness · ${n.expectedWitnessHex.slice(0,16)}…`),ct.value="(reference scene)",P.value="wasm"}catch(n){d("err",`boot failed: ${n.message}`)}try{const n=Y.value;if(n){const l=new Uint8Array(32);for(let m=0;m<32;m++)l[m]=parseInt(n.slice(m*2,m*2+2),16);const v=await o.verifyWitness(l);if(v.ok)A.value=n,d("ok","witness verified · determinism gate ✓");else{const m=Array.from(v.actual).map(b=>b.toString(16).padStart(2,"0")).join("");A.value=m,d("err",`WITNESS MISMATCH · expected ${n.slice(0,16)}… got ${m.slice(0,16)}…`)}}}catch(n){d("warn",`witness verify skipped: ${n.message}`)}})();
+//# sourceMappingURL=index-CjC_xGBQ.js.map
diff --git a/nvsim/assets/index-CjC_xGBQ.js.map b/nvsim/assets/index-CjC_xGBQ.js.map
new file mode 100644
index 00000000..6e1b75da
--- /dev/null
+++ b/nvsim/assets/index-CjC_xGBQ.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index-CjC_xGBQ.js","sources":["../../node_modules/@lit/reactive-element/decorators/custom-element.js","../../node_modules/@lit/reactive-element/decorators/property.js","../../node_modules/@lit/reactive-element/decorators/state.js","../../node_modules/@lit/reactive-element/decorators/base.js","../../node_modules/@lit/reactive-element/decorators/query.js","../../src/components/nv-rail.ts","../../src/store/appStore.ts","../../src/components/nv-modal.ts","../../src/components/nv-toast.ts","../../src/components/nv-topbar.ts","../../src/components/nv-sidebar.ts","../../src/components/nv-scene.ts","../../src/components/nv-inspector.ts","../../src/components/nv-console.ts","../../src/store/apps.ts","../../src/store/persistence.ts","../../src/components/nv-app-store.ts","../../src/components/nv-palette.ts","../../src/components/nv-debug-hud.ts","../../src/components/nv-settings-drawer.ts","../../src/components/nv-onboarding.ts","../../src/components/nv-ghost-murmur.ts","../../src/components/nv-app.ts","../../src/transport/NvsimClient.ts","../../src/transport/WasmClient.ts","../../src/main.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=t=>(e,o)=>{void 0!==o?o.addInitializer(()=>{customElements.define(t,e)}):customElements.define(t,e)};export{t as customElement};\n//# sourceMappingURL=custom-element.js.map\n","import{notEqual as t,defaultConverter as e}from\"../reactive-element.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const o={attribute:!0,type:String,converter:e,reflect:!1,hasChanged:t},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),\"setter\"===n&&((t=Object.create(t)).wrapped=!0),s.set(r.name,t),\"accessor\"===n){const{name:o}=r;return{set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t,!0,r)},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if(\"setter\"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t,!0,r)}}throw Error(\"Unsupported decorator location: \"+n)};function n(t){return(e,o)=>\"object\"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}export{n as property,r as standardProperty};\n//# sourceMappingURL=property.js.map\n","import{property as t}from\"./property.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function r(r){return t({...r,state:!0,attribute:!1})}export{r as state};\n//# sourceMappingURL=state.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst e=(e,t,c)=>(c.configurable=!0,c.enumerable=!0,Reflect.decorate&&\"object\"!=typeof t&&Object.defineProperty(e,t,c),c);export{e as desc};\n//# sourceMappingURL=base.js.map\n","import{desc as t}from\"./base.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function e(e,r){return(n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;if(r){const{get:e,set:r}=\"object\"==typeof s?n:i??(()=>{const t=Symbol();return{get(){return this[t]},set(e){this[t]=e}}})();return t(n,s,{get(){let t=e.call(this);return void 0===t&&(t=o(this),(null!==t||this.hasUpdated)&&r.call(this,t)),t}})}return t(n,s,{get(){return o(this)}})}}export{e as query};\n//# sourceMappingURL=query.js.map\n","/* Left rail navigation. Emits `navigate` events for view switching. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { View } from './nv-app';\n\n@customElement('nv-rail')\nexport class NvRail extends LitElement {\n @property() view: View = 'scene';\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 10px 0;\n gap: 4px;\n background: var(--bg-1);\n border-right: 1px solid var(--line);\n }\n .logo {\n width: 36px; height: 36px;\n border-radius: 10px;\n background: linear-gradient(135deg, oklch(0.78 0.14 70) 0%, oklch(0.55 0.16 30) 100%);\n display: grid; place-items: center;\n color: #1a0f00;\n font-weight: 700;\n font-family: var(--mono);\n font-size: 11px;\n margin-bottom: 14px;\n box-shadow: 0 4px 12px -2px oklch(0.55 0.16 30 / 0.35);\n }\n .btn {\n width: 36px; height: 36px;\n border-radius: 8px;\n background: transparent;\n border: 1px solid transparent;\n color: var(--ink-3);\n display: grid; place-items: center;\n transition: all 0.15s;\n position: relative;\n cursor: pointer;\n }\n .btn:hover { color: var(--ink); background: var(--bg-2); }\n .btn.active {\n color: var(--ink);\n background: var(--bg-3);\n border-color: var(--line-2);\n }\n .btn.active::before {\n content: ''; position: absolute; left: -10px; top: 8px; bottom: 8px;\n width: 2px; background: var(--accent); border-radius: 2px;\n }\n .btn.ghost.active::before { background: var(--accent-3); }\n .spacer { flex: 1; }\n svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }\n `;\n\n private navigate(v: View): void {\n this.dispatchEvent(new CustomEvent('navigate', { detail: v }));\n }\n\n override render() {\n return html`\n NV
\n \n this.navigate('scene')}>\n \n \n this.navigate('apps')}>\n \n \n this.navigate('inspector')}>\n \n \n this.navigate('witness')}>\n \n \n this.navigate('ghost-murmur')}>\n \n \n \n \n \n \n \n
\n this.dispatchEvent(new CustomEvent('open-settings', { bubbles: true, composed: true }))}>\n \n \n `;\n }\n}\n","/* Application-wide reactive state.\n *\n * One signal per logical observable; components subscribe to only the\n * signals they read. Keeps re-renders surgical even at 1 kHz frame rates.\n * Persistence lives in `persistence.ts`; this module is pure state.\n */\nimport { signal, computed } from '@preact/signals-core';\nimport type { NvsimClient, MagFrameRecord, NvsimEvent } from '../transport/NvsimClient';\n\nexport type Theme = 'dark' | 'light';\nexport type Density = 'comfy' | 'default' | 'compact';\nexport type TransportMode = 'wasm' | 'ws';\n\nexport const transport = signal('wasm');\nexport const wsUrl = signal('');\nexport const connected = signal(false);\nexport const transportError = signal(null);\n\nexport const running = signal(false);\nexport const paused = signal(true);\nexport const speed = signal(1.0);\nexport const t = signal(0); // sim time (s)\nexport const framesEmitted = signal(0n);\n\nexport const seed = signal(0xCAFEBABEn);\n\nexport const fs = signal(10000); // sample rate Hz\nexport const fmod = signal(1000); // lockin Hz\nexport const dtMs = signal(1.0);\nexport const noiseEnabled = signal(true);\n\nexport const theme = signal('dark');\nexport const density = signal('default');\nexport const motionReduced = signal(false);\nexport const autoUpdate = signal(true);\n\nexport const lastB = signal<[number, number, number]>([0, 0, 0]); // T\nexport const bMag = signal(0);\nexport const snr = signal(0);\nexport const fps = signal(0);\n\nexport const witnessHex = signal('');\nexport const witnessVerified = signal<'pending' | 'ok' | 'fail' | 'idle'>('idle');\nexport const expectedWitness = signal('');\n\nexport const lastFrame = signal(null);\nexport const traceX = signal([]);\nexport const traceY = signal([]);\nexport const traceZ = signal([]);\nexport const stripBars = signal([]);\n\nexport const sceneName = signal('rebar-walkby-01');\nexport const sceneJson = signal('');\n\nexport const consolePaused = signal(false);\nexport const consoleFilter = signal<'all' | 'info' | 'warn' | 'err' | 'dbg' | 'ok'>('all');\n\n/** REPL command history, persisted via persistence.ts (kvSet 'repl-history'). */\nexport const replHistory = signal([]);\nexport function pushReplHistory(cmd: string): void {\n const next = replHistory.value.slice();\n next.push(cmd);\n while (next.length > 200) next.shift();\n replHistory.value = next;\n}\n\n/** Scene drag positions, persisted via persistence.ts (kvSet 'scene-positions'). */\nexport interface SceneItemPos { id: string; x: number; y: number }\nexport const scenePositions = signal([]);\n\nexport const transportLabel = computed(() =>\n transport.value === 'wasm' ? 'wasm' : 'ws',\n);\n\nlet _client: NvsimClient | null = null;\nexport function setClient(c: NvsimClient): void { _client = c; }\nexport function getClient(): NvsimClient | null { return _client; }\n\nexport interface ConsoleLine {\n ts: number;\n level: 'info' | 'warn' | 'err' | 'dbg' | 'ok';\n msg: string;\n}\nexport const consoleLines = signal([]);\nconst MAX_LINES = 200;\n\nexport function pushLog(level: ConsoleLine['level'], msg: string): void {\n if (consolePaused.value) return;\n const next = consoleLines.value.slice();\n next.push({ ts: Date.now(), level, msg });\n while (next.length > MAX_LINES) next.shift();\n consoleLines.value = next;\n}\n\nexport function pushTrace(b: [number, number, number]): void {\n const cap = 200;\n const x = traceX.value.slice(); x.push(b[0]); if (x.length > cap) x.shift();\n const y = traceY.value.slice(); y.push(b[1]); if (y.length > cap) y.shift();\n const z = traceZ.value.slice(); z.push(b[2]); if (z.length > cap) z.shift();\n traceX.value = x;\n traceY.value = y;\n traceZ.value = z;\n}\n\nexport function pushStripBar(amp: number): void {\n const cap = 48;\n const next = stripBars.value.slice();\n next.push(Math.max(0, Math.min(1, amp)));\n while (next.length > cap) next.shift();\n stripBars.value = next;\n}\n\nexport function recordEvent(_ev: NvsimEvent): void {\n // future: route NvsimEvent into store updates per type. For V1 the\n // worker pushes B-vector / frame data directly via the data plane.\n}\n","/* Modal dialog — opened via window.dispatchEvent('nv-modal', { title, body, buttons }). */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\ninterface ModalButton {\n label: string;\n variant?: 'ghost' | 'primary' | 'danger';\n onClick?: () => void;\n}\ninterface ModalReq {\n title: string;\n body: string;\n buttons?: ModalButton[];\n}\n\n@customElement('nv-modal')\nexport class NvModal extends LitElement {\n @state() private open = false;\n @state() private mTitle = '';\n @state() private mBody = '';\n @state() private buttons: ModalButton[] = [];\n\n static styles = css`\n :host {\n position: fixed; inset: 0;\n background: rgba(0,0,0,0.55);\n backdrop-filter: blur(4px);\n z-index: 200;\n display: grid; place-items: center;\n opacity: 0; pointer-events: none;\n transition: opacity 0.18s;\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .modal {\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n width: min(520px, 92vw);\n max-height: 86vh;\n display: flex; flex-direction: column;\n transform: translateY(12px) scale(0.98);\n transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);\n }\n :host([open]) .modal { transform: translateY(0) scale(1); }\n .h {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n display: flex; align-items: center; justify-content: space-between;\n }\n .h .ttl { font-size: 14px; font-weight: 600; }\n .body { padding: 16px; overflow-y: auto; font-size: 13px; color: var(--ink-2); line-height: 1.55; }\n .f {\n padding: 12px 16px;\n border-top: 1px solid var(--line);\n display: flex; gap: 8px; justify-content: flex-end;\n }\n button {\n padding: 6px 12px;\n border-radius: 8px;\n font-size: 12.5px;\n cursor: pointer;\n font-family: inherit;\n border: 1px solid var(--line);\n background: var(--bg-2); color: var(--ink);\n }\n button.ghost { background: transparent; }\n button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }\n button.danger { background: var(--bad); border-color: var(--bad); color: #fff; }\n .close {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-2);\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('nv-modal', this.onModal as EventListener);\n window.addEventListener('keydown', this.onKey);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-modal', this.onModal as EventListener);\n window.removeEventListener('keydown', this.onKey);\n }\n\n private onModal = (e: Event): void => {\n const r = (e as CustomEvent).detail as ModalReq;\n this.mTitle = r.title; this.mBody = r.body;\n this.buttons = r.buttons ?? [{ label: 'Close', variant: 'primary' }];\n this.open = true; this.setAttribute('open', '');\n // a11y: focus the first interactive element inside the modal so keyboard\n // users land in the dialog rather than behind it. Light focus trap via\n // the keydown handler below catches Tab cycling.\n requestAnimationFrame(() => {\n const root = this.shadowRoot;\n if (!root) return;\n const first = root.querySelector('input, select, textarea, button:not(.close)');\n first?.focus();\n });\n };\n\n override updated(): void {\n if (!this.open) return;\n const root = this.shadowRoot;\n if (!root) return;\n // Trap Tab inside the modal while open.\n const trap = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab') return;\n const focusables = Array.from(\n root.querySelectorAll('input, select, textarea, button, [href]'),\n ).filter((el) => !el.hasAttribute('disabled'));\n if (focusables.length === 0) return;\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = (root.activeElement as HTMLElement | null) ?? null;\n if (e.shiftKey && active === first) { e.preventDefault(); last.focus(); }\n else if (!e.shiftKey && active === last) { e.preventDefault(); first.focus(); }\n };\n root.removeEventListener('keydown', trap as EventListener);\n root.addEventListener('keydown', trap as EventListener);\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) this.close();\n };\n\n private close(): void { this.open = false; this.removeAttribute('open'); }\n private clickBtn(b: ModalButton): void { b.onClick?.(); this.close(); }\n\n override render() {\n return html`\n \n
\n
${this.mTitle}
\n
this.close()}>× \n
\n
\n
\n ${this.buttons.map((b) => html`\n this.clickBtn(b)}>${b.label} \n `)}\n
\n
\n `;\n }\n}\n\nexport function openModal(req: ModalReq): void {\n window.dispatchEvent(new CustomEvent('nv-modal', { detail: req }));\n}\n","/* Toast notification — shown briefly via window.dispatchEvent('nv-toast', detail). */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\n@customElement('nv-toast')\nexport class NvToast extends LitElement {\n @state() private visible = false;\n @state() private msg = '';\n @state() private icon = '✓';\n private timer: number | null = null;\n\n static styles = css`\n :host {\n position: fixed; bottom: 24px; left: 50%;\n transform: translateX(-50%) translateY(80px);\n background: var(--bg-2);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n padding: 10px 14px;\n font-size: 12.5px;\n box-shadow: var(--shadow);\n z-index: 100;\n opacity: 0; pointer-events: none;\n transition: opacity 0.2s, transform 0.2s;\n display: flex; align-items: center; gap: 8px;\n }\n :host([visible]) {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n pointer-events: auto;\n }\n .icon { color: var(--accent); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('nv-toast', this.onToast as EventListener);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-toast', this.onToast as EventListener);\n }\n\n private onToast = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { msg?: string; icon?: string };\n this.msg = detail.msg ?? 'Done';\n this.icon = detail.icon ?? '✓';\n this.visible = true;\n this.setAttribute('visible', '');\n if (this.timer !== null) window.clearTimeout(this.timer);\n this.timer = window.setTimeout(() => {\n this.visible = false;\n this.removeAttribute('visible');\n }, 1800);\n };\n\n override render() {\n return html`${this.icon} ${this.msg} `;\n }\n}\n\nexport function toast(msg: string, icon = '✓'): void {\n window.dispatchEvent(new CustomEvent('nv-toast', { detail: { msg, icon } }));\n}\n","/* Topbar — breadcrumbs, transport pill, FPS pill, seed pill, controls. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n fps, transportLabel, seed, theme, sceneName,\n running, getClient, pushLog,\n} from '../store/appStore';\nimport { openModal } from './nv-modal';\nimport { toast } from './nv-toast';\n\n@customElement('nv-topbar')\nexport class NvTopbar extends LitElement {\n static styles = css`\n :host {\n display: flex; align-items: center;\n padding: 0 16px; gap: 12px;\n background: var(--bg-1);\n border-bottom: 1px solid var(--line);\n z-index: 10;\n }\n .crumbs { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-3); }\n .crumbs .sep { color: var(--ink-4); }\n .crumbs .cur { color: var(--ink); font-weight: 500; }\n .spacer { flex: 1; }\n .pill {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 5px 10px;\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 12px; color: var(--ink-2);\n font-family: var(--mono); font-weight: 500;\n }\n .pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 6px var(--ok); animation: pulse 2s infinite; }\n .pill.wasm .dot { background: var(--accent-2); box-shadow: 0 0 6px var(--accent-2); }\n .pill.seed { color: var(--ink-3); cursor: pointer; }\n .pill.seed:hover { border-color: var(--line-2); }\n .pill.seed b { color: var(--accent); font-weight: 600; }\n .pill.wasm { cursor: pointer; }\n .pill.wasm:hover { border-color: var(--line-2); }\n button {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 6px 12px;\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 8px;\n font-size: 12.5px; font-weight: 500; color: var(--ink);\n cursor: pointer;\n transition: all 0.15s;\n }\n button:hover { border-color: var(--line-2); background: var(--bg-3); }\n button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }\n button.primary:hover { filter: brightness(1.08); }\n button.ghost { background: transparent; }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { fps.value; transportLabel.value; seed.value; theme.value; sceneName.value; running.value; this.requestUpdate(); });\n }\n\n private async toggleRun(): Promise {\n const c = getClient(); if (!c) return;\n if (running.value) { await c.pause(); running.value = false; }\n else { await c.run(); running.value = true; }\n }\n private async reset(): Promise {\n const c = getClient(); if (!c) return;\n await c.reset();\n }\n private toggleTheme(): void {\n theme.value = theme.value === 'dark' ? 'light' : 'dark';\n }\n private async openSeedModal(): Promise {\n const cur = `0x${seed.value.toString(16).toUpperCase().padStart(8, '0')}`;\n openModal({\n title: 'Set seed',\n body: `Set the 32-bit hex seed for the shot-noise PRNG. Same (scene, config, seed) → byte-identical witness.
\n Hex seed \n `,\n buttons: [\n { label: 'Cancel', variant: 'ghost' },\n { label: 'Apply', variant: 'primary', onClick: async () => {\n const inp = document.querySelector('nv-modal')?.shadowRoot?.querySelector('#seed-input');\n if (!inp) return;\n const raw = inp.value.trim().replace(/^0x/i, '');\n const v = BigInt('0x' + raw);\n seed.value = v;\n await getClient()?.setSeed(v);\n pushLog('ok', `seed → 0x${v.toString(16).toUpperCase()}`);\n toast(`Seed → 0x${v.toString(16).toUpperCase().slice(0, 8)}`, '⟳');\n } },\n ],\n });\n }\n private openTransportSettings(): void {\n window.dispatchEvent(new CustomEvent('open-settings'));\n }\n\n override render() {\n const seedHex = seed.value.toString(16).toUpperCase().padStart(8, '0');\n return html`\n \n RuView / \n nvsim / \n ${sceneName.value} \n
\n
\n \n \n ${fps.value > 0 ? (fps.value / 1000).toFixed(2) + ' kHz' : 'idle'} \n \n \n ${transportLabel.value}\n \n \n seed: 0x${seedHex} \n \n \n ${theme.value === 'dark' ? '☼' : '☾'}\n \n ↺ Reset \n \n ${running.value ? '❚❚ Pause' : '▶ Run'}\n \n `;\n }\n}\n","/* Sidebar — Scene panel, NV sensor panel, Tunables, Pipeline diagram. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { fs, fmod, dtMs, noiseEnabled, running, getClient, pushLog } from '../store/appStore';\n\nlet configPushTimer: number | null = null;\nfunction pushConfigDebounced(): void {\n if (configPushTimer !== null) window.clearTimeout(configPushTimer);\n configPushTimer = window.setTimeout(async () => {\n const c = getClient();\n if (!c) return;\n try {\n await c.setConfig({\n digitiser: { f_s_hz: fs.value, f_mod_hz: fmod.value },\n sensor: {\n gamma_fwhm_hz: 1.0e6,\n t1_s: 5.0e-3,\n t2_s: 1.0e-6,\n t2_star_s: 200e-9,\n contrast: 0.03,\n n_spins: 1.0e12,\n shot_noise_disabled: !noiseEnabled.value,\n },\n dt_s: dtMs.value * 1e-3,\n });\n pushLog('dbg', `config pushed · fs=${fs.value} f_mod=${fmod.value} dt=${dtMs.value.toFixed(1)}ms noise=${noiseEnabled.value ? 'on' : 'off'}`);\n } catch (e) {\n pushLog('warn', `config push failed: ${(e as Error).message}`);\n }\n }, 300);\n}\n\n@customElement('nv-sidebar')\nexport class NvSidebar extends LitElement {\n static styles = css`\n :host {\n display: flex; flex-direction: column; gap: 14px;\n padding: 14px; overflow-y: auto;\n background: var(--bg-1); border-right: 1px solid var(--line);\n }\n .panel {\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 12px;\n }\n .panel-h {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; font-weight: 600; color: var(--ink-3);\n text-transform: uppercase; letter-spacing: 0.08em;\n margin-bottom: 10px;\n }\n .count {\n background: var(--bg-3); color: var(--ink-2);\n padding: 1px 6px; border-radius: 999px;\n font-family: var(--mono); font-size: 10px;\n text-transform: none; letter-spacing: 0;\n }\n .scene-item {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 10px;\n border-radius: var(--radius-sm);\n cursor: pointer;\n transition: background 0.15s;\n border: 1px solid transparent;\n }\n .scene-item:hover { background: var(--bg-3); }\n .scene-item .swatch { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n .scene-item .name { font-size: 13px; flex: 1; }\n .scene-item .meta { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }\n .field-row {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 0; font-size: 12.5px;\n border-bottom: 1px solid var(--line);\n }\n .field-row:last-child { border-bottom: 0; }\n .field-row .lbl { color: var(--ink-3); }\n .field-row .val { font-family: var(--mono); color: var(--ink); font-size: 12px; }\n .slider-row { padding: 8px 0; border-bottom: 1px solid var(--line); }\n .slider-row:last-child { border-bottom: 0; padding-bottom: 0; }\n .slider-row .top { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 12px; }\n .slider-row .top .lbl { color: var(--ink-3); }\n .slider-row .top .val { font-family: var(--mono); color: var(--ink); }\n input[type=\"range\"] {\n -webkit-appearance: none; appearance: none;\n width: 100%; height: 4px;\n background: var(--bg-3); border-radius: 2px; outline: none;\n }\n input[type=\"range\"]::-webkit-slider-thumb {\n -webkit-appearance: none; appearance: none;\n width: 14px; height: 14px; border-radius: 50%;\n background: var(--accent); cursor: pointer;\n border: 2px solid var(--bg-2);\n box-shadow: 0 0 0 1px var(--line-2);\n }\n .pipeline { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-top: 6px; }\n .stage {\n flex: 1; min-width: 50px;\n padding: 4px 6px;\n background: var(--bg-3); border: 1px solid var(--line);\n border-radius: 6px; font-size: 9.5px; text-align: center;\n color: var(--ink-2); font-family: var(--mono);\n }\n .stage.live { border-color: var(--accent-2); color: var(--accent-2); }\n .stage-arrow { color: var(--ink-4); font-size: 10px; }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { fs.value; fmod.value; dtMs.value; noiseEnabled.value; running.value; this.requestUpdate(); });\n }\n\n override render() {\n return html`\n \n
Scene 4 sources
\n
\n \n rebar.steel.coil \n χ=5000 \n
\n
\n \n heart_proxy \n 1e-6 A·m² \n
\n
\n \n mains_60Hz \n 2 A · 60 Hz \n
\n
\n \n door.steel \n eddy \n
\n
\n\n \n
NV sensor COTS
\n
V 1 mm³
\n
N 1e12 NV
\n
C 0.030
\n
T₂* 200 ns
\n
δB 1.18 pT/√Hz
\n
\n\n \n
Tunables
\n
\n
Sample rate ${(fs.value / 1000).toFixed(1)} kHz
\n
{ fs.value = +(e.target as HTMLInputElement).value; pushConfigDebounced(); }} />\n
\n
\n
Lockin f_mod ${(fmod.value / 1000).toFixed(3)} kHz
\n
{ fmod.value = +(e.target as HTMLInputElement).value; pushConfigDebounced(); }} />\n
\n
\n
Integration t ${dtMs.value.toFixed(1)} ms
\n
{ dtMs.value = +(e.target as HTMLInputElement).value; pushConfigDebounced(); }} />\n
\n
\n
Shot noise ${noiseEnabled.value ? 'ON' : 'OFF'}
\n
{ noiseEnabled.value = (e.target as HTMLInputElement).value === '1'; pushConfigDebounced(); }} />\n
\n
\n\n \n
Pipeline
\n
\n scene \n → \n B-S \n → \n prop \n → \n NV \n → \n ADC \n → \n frame \n
\n
\n `;\n }\n}\n","/* Scene canvas — SVG with draggable sources, NV crystal sensor, field lines, mini ODMR. */\nimport { LitElement, html, css, svg } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { lastB, bMag, fps, snr, motionReduced, running, getClient, speed, pushLog, lastFrame, scenePositions } from '../store/appStore';\n\ninterface SceneItem { id: string; x: number; y: number; color: string; name: string; }\n\n@customElement('nv-scene')\nexport class NvScene extends LitElement {\n @state() private zoom = 1.0;\n @state() private layerVisible = { source: true, field: true, label: true };\n @state() private items: SceneItem[] = [\n { id: 'rebar', x: 740, y: 240, color: 'oklch(0.72 0.18 330)', name: 'rebar.steel' },\n { id: 'heart', x: 220, y: 180, color: 'oklch(0.78 0.14 195)', name: 'heart_proxy' },\n { id: 'mains', x: 180, y: 380, color: 'oklch(0.72 0.18 330)', name: 'mains_60Hz' },\n { id: 'door', x: 800, y: 470, color: 'oklch(0.78 0.14 145)', name: 'door.steel' },\n ];\n @state() private dragging: string | null = null;\n @state() private selected: string | null = null;\n private dragOffset = { dx: 0, dy: 0 };\n\n static styles = css`\n :host {\n display: block; height: 100%; width: 100%;\n background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);\n position: relative; overflow: hidden;\n border-bottom: 1px solid var(--line);\n }\n .grid {\n position: absolute; inset: 0;\n background-image:\n linear-gradient(var(--grid) 1px, transparent 1px),\n linear-gradient(90deg, var(--grid) 1px, transparent 1px);\n background-size: 32px 32px;\n pointer-events: none;\n mask-image: radial-gradient(ellipse at center, black 40%, transparent 100%);\n }\n svg { position: absolute; inset: 0; width: 100%; height: 100%; }\n .stat-card {\n background: rgba(13,17,23,0.7);\n backdrop-filter: blur(8px);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 8px 12px;\n font-size: 11px;\n min-width: 96px;\n }\n [data-theme=\"light\"] .stat-card { background: rgba(255,255,255,0.85); }\n .stat-card .lbl {\n color: var(--ink-3);\n text-transform: uppercase; font-weight: 600; letter-spacing: 0.06em; font-size: 9.5px;\n }\n .stat-card .val { font-family: var(--mono); font-size: 16px; font-weight: 600; margin-top: 2px; }\n .stat-card .val.amber { color: var(--accent); }\n .stat-card .val.cyan { color: var(--accent-2); }\n .stat-card .val.mint { color: var(--accent-4); }\n .scene-readout {\n position: absolute; top: 14px; right: 14px;\n display: flex; gap: 8px; z-index: 5;\n }\n .draggable { cursor: grab; transition: filter 0.15s; }\n .draggable:hover { filter: brightness(1.15) drop-shadow(0 0 6px currentColor); }\n .draggable.dragging { cursor: grabbing; filter: brightness(1.25) drop-shadow(0 0 10px currentColor); }\n .field-line { stroke-dasharray: 4 6; }\n @keyframes dash { to { stroke-dashoffset: -200; } }\n .field-line.anim { animation: dash 4s linear infinite; }\n @keyframes spin {\n 0% { transform: rotateY(0) rotateX(8deg); }\n 100% { transform: rotateY(360deg) rotateX(8deg); }\n }\n .crystal { transform-origin: center; transform-box: fill-box; }\n .crystal.anim { animation: spin 12s linear infinite; }\n .label {\n font-family: var(--mono); font-size: 11px; fill: var(--ink-2);\n pointer-events: none;\n }\n .scene-toolbar {\n position: absolute; top: 14px; left: 14px;\n display: flex; gap: 6px; z-index: 5;\n background: rgba(13,17,23,0.85);\n backdrop-filter: blur(8px);\n border: 1px solid var(--line);\n border-radius: 8px;\n padding: 4px;\n }\n [data-theme=\"light\"] .scene-toolbar { background: rgba(255,255,255,0.85); }\n .scene-toolbar button {\n width: 28px; height: 28px;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 6px;\n color: var(--ink-2);\n cursor: pointer;\n display: grid; place-items: center;\n font-size: 13px;\n }\n .scene-toolbar button:hover { color: var(--ink); background: var(--bg-2); }\n .scene-toolbar button.on { background: var(--bg-3); color: var(--accent); border-color: var(--line-2); }\n\n .sim-controls {\n position: absolute; bottom: 14px; right: 14px;\n display: flex; gap: 6px; align-items: center;\n background: rgba(13,17,23,0.85);\n backdrop-filter: blur(12px);\n border: 1px solid var(--line-2);\n border-radius: 999px;\n padding: 6px 10px;\n z-index: 5;\n }\n [data-theme=\"light\"] .sim-controls { background: rgba(255,255,255,0.92); }\n .sim-controls .play {\n width: 32px; height: 32px;\n background: var(--accent);\n border: none;\n border-radius: 50%;\n color: #1a0f00;\n cursor: pointer;\n display: grid; place-items: center;\n font-size: 13px;\n }\n .sim-controls .play:hover { filter: brightness(1.08); }\n .sim-controls .step {\n width: 26px; height: 26px;\n border-radius: 6px;\n background: transparent;\n color: var(--ink-2);\n border: 1px solid var(--line);\n cursor: pointer;\n font-size: 11px;\n }\n .sim-controls .step:hover { color: var(--ink); border-color: var(--line-2); }\n .sim-controls .speed {\n font-family: var(--mono); font-size: 11px;\n color: var(--ink-2);\n padding: 0 6px;\n min-width: 36px;\n text-align: center;\n cursor: pointer;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Restore drag positions if any are persisted.\n if (scenePositions.value.length > 0) {\n this.items = this.items.map((it) => {\n const saved = scenePositions.value.find((p) => p.id === it.id);\n return saved ? { ...it, x: saved.x, y: saved.y } : it;\n });\n }\n effect(() => {\n lastB.value; bMag.value; fps.value; snr.value; motionReduced.value;\n running.value; speed.value; lastFrame.value;\n this.requestUpdate();\n });\n // Compute SNR from the last frame: |B_pT| / max(σ_pT[k]) per ADR-093 P1.4.\n effect(() => {\n const f = lastFrame.value;\n if (!f) return;\n const bmag = Math.sqrt(f.bPt[0] ** 2 + f.bPt[1] ** 2 + f.bPt[2] ** 2);\n const sigmaMax = Math.max(Math.abs(f.sigmaPt[0]), Math.abs(f.sigmaPt[1]), Math.abs(f.sigmaPt[2]), 0.001);\n const snrVal = bmag / sigmaMax;\n if (Number.isFinite(snrVal)) snr.value = snrVal;\n });\n window.addEventListener('pointermove', this.onPointerMove);\n window.addEventListener('pointerup', this.onPointerUp);\n }\n\n private async toggleRun(): Promise {\n const c = getClient(); if (!c) return;\n if (running.value) { await c.pause(); running.value = false; }\n else { await c.run(); running.value = true; }\n }\n private async stepFwd(): Promise {\n const c = getClient(); if (!c) return;\n await c.step('fwd', 10);\n pushLog('dbg', 'sim step → +1 frame');\n }\n private async stepBack(): Promise {\n const c = getClient(); if (!c) return;\n await c.step('back', 10);\n pushLog('dbg', 'sim step ← -1 frame');\n }\n private cycleSpeed(): void {\n const speeds = [0.25, 0.5, 1.0, 2.0, 4.0];\n const idx = speeds.indexOf(speed.value);\n speed.value = speeds[(idx + 1) % speeds.length];\n }\n private zoomIn(): void { this.zoom = Math.min(2.5, this.zoom * 1.2); }\n private zoomOut(): void { this.zoom = Math.max(0.5, this.zoom / 1.2); }\n private fitView(): void { this.zoom = 1.0; }\n private toggleLayer(k: 'source' | 'field' | 'label'): void {\n this.layerVisible = { ...this.layerVisible, [k]: !this.layerVisible[k] };\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('pointermove', this.onPointerMove);\n window.removeEventListener('pointerup', this.onPointerUp);\n }\n\n private onDown = (id: string, e: PointerEvent): void => {\n e.preventDefault();\n this.dragging = id;\n this.selected = id;\n const item = this.items.find((i) => i.id === id);\n if (!item) return;\n const svgEl = this.renderRoot.querySelector('svg') as SVGSVGElement | null;\n if (!svgEl) return;\n const pt = this.toSvg(e, svgEl);\n this.dragOffset = { dx: pt.x - item.x, dy: pt.y - item.y };\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.dragging) return;\n const svgEl = this.renderRoot.querySelector('svg') as SVGSVGElement | null;\n if (!svgEl) return;\n const pt = this.toSvg(e, svgEl);\n this.items = this.items.map((it) =>\n it.id === this.dragging\n ? { ...it, x: pt.x - this.dragOffset.dx, y: pt.y - this.dragOffset.dy }\n : it,\n );\n };\n\n private onPointerUp = (): void => {\n if (this.dragging) {\n // Persist all positions on drop.\n scenePositions.value = this.items.map(({ id, x, y }) => ({ id, x, y }));\n }\n this.dragging = null;\n };\n\n private toSvg(e: PointerEvent, svgEl: SVGSVGElement): { x: number; y: number } {\n const r = svgEl.getBoundingClientRect();\n const vbX = ((e.clientX - r.left) / r.width) * 1000;\n const vbY = ((e.clientY - r.top) / r.height) * 600;\n return { x: vbX, y: vbY };\n }\n\n override render() {\n const b = lastB.value;\n const bnT = [b[0] * 1e9, b[1] * 1e9, b[2] * 1e9];\n const bMagNT = bMag.value * 1e9;\n const animClass = motionReduced.value ? '' : 'anim';\n\n const vbW = 1000 / this.zoom;\n const vbH = 600 / this.zoom;\n const vbX = (1000 - vbW) / 2;\n const vbY = (600 - vbH) / 2;\n\n return html`\n
\n \n \n \n \n \n \n \n \n\n \n ${this.layerVisible.field ? this.items.map((it) => svg`\n \n `) : ''}\n\n \n ${this.layerVisible.source ? this.items.map((it) => svg`\n this.onDown(it.id, e)}>\n \n \n ${this.layerVisible.label ? svg`${it.name} ` : ''}\n \n `) : ''}\n\n \n \n \n \n \n \n \n \n sensor · 〈111〉 NV\n \n \n B_in: [${bnT[0].toFixed(2)}, ${bnT[1].toFixed(2)}, ${bnT[2].toFixed(2)}] nT \n \n \n \n\n \n + \n − \n ⊡ \n this.toggleLayer('source')}>● \n this.toggleLayer('field')}>≈ \n this.toggleLayer('label')}>T \n
\n\n \n ⏮ \n \n ${running.value ? '❚❚' : '▶'}\n \n ⏭ \n ${speed.value}× \n
\n\n \n
\n
|B|
\n
${bMagNT.toFixed(3)} nT
\n
\n
\n
FPS
\n
${fps.value > 0 ? Math.round(fps.value) : '—'}
\n
\n
\n
SNR
\n
${snr.value > 0 ? snr.value.toFixed(1) : '—'}
\n
\n
\n `;\n }\n}\n","/* Inspector — tabbed: Signal / Frame / Witness. */\nimport { LitElement, html, css, svg, type PropertyValues } from 'lit';\nimport { customElement, state, property } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n traceX, traceY, traceZ, stripBars, lastFrame,\n witnessHex, expectedWitness, witnessVerified, getClient,\n pushLog, lastB, bMag,\n} from '../store/appStore';\n\ntype Tab = 'signal' | 'frame' | 'witness';\n\n@customElement('nv-inspector')\nexport class NvInspector extends LitElement {\n @state() private tab: Tab = 'signal';\n /** When set by the parent, force the tab and pulse-highlight it. */\n @property({ attribute: false }) pinTab: Tab | null = null;\n\n static styles = css`\n :host {\n display: flex; flex-direction: column;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n overflow: hidden;\n height: 100%;\n }\n .tabs {\n display: flex; border-bottom: 1px solid var(--line);\n }\n .tab {\n flex: 1;\n padding: 11px 8px;\n background: transparent; border: none;\n font-size: 11.5px; font-weight: 500;\n color: var(--ink-3);\n border-bottom: 2px solid transparent;\n cursor: pointer; transition: color 0.15s, border-color 0.15s;\n }\n .tab.active { color: var(--ink); border-bottom-color: var(--accent); }\n .tab:hover { color: var(--ink-2); }\n .body { padding: 14px; flex: 1; overflow-y: auto; }\n\n .card {\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 12px;\n margin-bottom: 12px;\n }\n .card-h {\n display: flex; justify-content: space-between; align-items: center;\n margin-bottom: 8px;\n }\n .card-h .ttl { font-size: 12px; font-weight: 600; }\n .badge {\n font-family: var(--mono); font-size: 10px;\n padding: 2px 6px;\n background: oklch(0.78 0.14 195 / 0.12);\n color: var(--accent-2);\n border-radius: 4px;\n border: 1px solid oklch(0.78 0.14 195 / 0.3);\n }\n svg { width: 100%; height: 130px; }\n .frame-strip {\n height: 28px;\n display: flex; align-items: flex-end; gap: 1px;\n padding: 4px 0;\n }\n .bar {\n flex: 1;\n background: linear-gradient(to top, var(--accent-2), var(--accent));\n border-radius: 1px;\n min-height: 2px;\n }\n table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 10.5px; }\n td { padding: 4px 0; border-bottom: 1px solid var(--line); }\n td:first-child { color: var(--ink-3); }\n td:last-child { text-align: right; color: var(--ink); }\n .hex {\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 10px;\n font-family: var(--mono);\n font-size: 10.5px;\n color: var(--ink-2);\n line-height: 1.6;\n overflow-x: auto;\n white-space: nowrap;\n }\n .hex .magic { color: var(--accent); font-weight: 600; }\n .witness-box {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--ink-2);\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 6px;\n padding: 8px 10px;\n word-break: break-all;\n line-height: 1.5;\n }\n .verify-btn {\n margin-top: 10px;\n width: 100%;\n padding: 8px;\n border: 1px solid var(--line);\n background: var(--bg-3);\n color: var(--ink);\n border-radius: 8px;\n cursor: pointer;\n font-family: var(--mono);\n font-size: 12px;\n }\n .verify-btn:hover { border-color: var(--accent); }\n .verify-btn.ok { border-color: var(--ok); color: var(--ok); }\n .verify-btn.fail { border-color: var(--bad); color: var(--bad); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => {\n traceX.value; traceY.value; traceZ.value; stripBars.value;\n lastFrame.value; witnessHex.value; witnessVerified.value;\n lastB.value; bMag.value;\n this.requestUpdate();\n });\n }\n\n override willUpdate(changed: PropertyValues): void {\n // Apply parent-driven tab pin during willUpdate so the new tab value\n // participates in this same render pass — avoids the \"update after\n // update completed\" Lit warning that would fire if we did this in\n // updated().\n if (changed.has('pinTab') && this.pinTab && this.tab !== this.pinTab) {\n this.tab = this.pinTab;\n }\n }\n\n private async verify(): Promise {\n const c = getClient(); if (!c) return;\n witnessVerified.value = 'pending';\n pushLog('info', 'verifying witness over 256 frames…');\n try {\n const exp = expectedWitness.value;\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(expBytes);\n if (r.ok) {\n witnessVerified.value = 'ok';\n witnessHex.value = exp;\n pushLog('ok', `witness ${exp.slice(0, 16)}… matches · determinism gate ✓`);\n } else {\n witnessVerified.value = 'fail';\n const actual = Array.from(r.actual).map((b) => b.toString(16).padStart(2, '0')).join('');\n witnessHex.value = actual;\n pushLog('err', `WITNESS MISMATCH actual=${actual.slice(0, 16)}…`);\n }\n } catch (e) {\n witnessVerified.value = 'fail';\n pushLog('err', `verify failed: ${(e as Error).message}`);\n }\n }\n\n private renderSignalTab() {\n const W = 320, H = 130, cy = 65, scale = 22;\n const cap = 200;\n const make = (arr: number[]) => {\n let p = '';\n arr.forEach((v, i) => {\n const x = (i / Math.max(1, cap - 1)) * W;\n const y = cy - v * scale;\n p += (i === 0 ? 'M' : 'L') + ` ${x.toFixed(1)} ${y.toFixed(1)} `;\n });\n return p;\n };\n\n return html`\n \n
\n B-vector trace \n 3-axis · nT \n
\n
\n \n ${svg``}\n ${svg``}\n ${svg``}\n \n
\n\n \n
\n Frame stream \n live \n
\n
\n ${stripBars.value.map((v) => html`
`)}\n
\n
\n `;\n }\n\n private renderFrameTab() {\n const f = lastFrame.value;\n const bytes = f?.raw;\n let hex = '';\n if (bytes) {\n const arr = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0'));\n hex = arr.slice(0, 60).join(' ');\n }\n return html`\n \n
\n MagFrame v1 fields \n 60 B \n
\n
\n magic ${f ? '0x' + f.magic.toString(16).toUpperCase() : '—'} \n version ${f?.version ?? '—'} \n flags 0x${(f?.flags ?? 0).toString(16).padStart(4, '0')} \n sensor_id ${f?.sensorId ?? '—'} \n t_us ${f ? f.tUs.toString() : '—'} \n b_pT[0] ${f ? f.bPt[0].toFixed(1) : '—'} \n b_pT[1] ${f ? f.bPt[1].toFixed(1) : '—'} \n b_pT[2] ${f ? f.bPt[2].toFixed(1) : '—'} \n noise_floor ${f ? f.noiseFloorPtSqrtHz.toFixed(2) : '—'} \n temp_K ${f ? f.temperatureK.toFixed(1) : '—'} \n
\n
\n \n
\n Hex dump \n LE \n
\n
${hex || '—'}
\n
\n `;\n }\n\n private renderWitnessTab() {\n const status = witnessVerified.value;\n const cls = status === 'ok' ? 'ok' : status === 'fail' ? 'fail' : '';\n const label =\n status === 'pending' ? 'Verifying…' :\n status === 'ok' ? '✓ Witness verified · determinism gate' :\n status === 'fail' ? '✗ Witness mismatch · audit required' :\n 'Verify witness';\n return html`\n \n
\n Expected (Proof::EXPECTED_WITNESS_HEX) \n SHA-256 \n
\n
${expectedWitness.value || '(loading…)'}
\n
\n \n
\n Actual (last verify) \n SHA-256 \n
\n
${witnessHex.value || '(not verified yet)'}
\n
${label} \n
\n `;\n }\n\n override render() {\n return html`\n \n this.tab = 'signal'}>Signal \n this.tab = 'frame'}>Frame \n this.tab = 'witness'}>Witness \n
\n \n ${this.tab === 'signal' ? this.renderSignalTab()\n : this.tab === 'frame' ? this.renderFrameTab()\n : this.renderWitnessTab()}\n
\n `;\n }\n}\n","/* Console — log stream + REPL. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, query } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n consoleLines, consoleFilter, consolePaused, pushLog,\n getClient, seed, theme, expectedWitness, witnessHex, witnessVerified,\n running, replHistory, pushReplHistory,\n} from '../store/appStore';\n\n@customElement('nv-console')\nexport class NvConsole extends LitElement {\n @query('#console-input') private inputEl!: HTMLInputElement;\n private hIdx = -1;\n\n static styles = css`\n :host {\n display: flex; flex-direction: column;\n background: var(--bg-1);\n overflow: hidden;\n }\n .tabs {\n display: flex; align-items: center;\n border-bottom: 1px solid var(--line);\n padding: 0 10px;\n gap: 2px;\n }\n .tab {\n padding: 8px 12px;\n background: transparent; border: none;\n font-size: 11.5px; color: var(--ink-3);\n font-family: var(--mono);\n border-bottom: 2px solid transparent;\n cursor: pointer;\n margin-bottom: -1px;\n }\n .tab.active { color: var(--ink); border-bottom-color: var(--accent); }\n .tab .cnt {\n background: var(--bg-3); padding: 1px 5px; border-radius: 999px;\n font-size: 9.5px; color: var(--ink-2); margin-left: 4px;\n }\n .spacer { flex: 1; }\n .tools { display: flex; gap: 4px; padding: 4px 0; }\n .tools button {\n width: 24px; height: 24px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-3);\n font-size: 11px; cursor: pointer;\n }\n .tools button:hover { color: var(--ink); border-color: var(--line-2); }\n\n .body {\n flex: 1; overflow-y: auto;\n font-family: var(--mono);\n font-size: 11.5px;\n padding: 6px 0;\n background: var(--bg-0);\n }\n .line {\n display: grid;\n grid-template-columns: 70px 60px 1fr;\n gap: 12px;\n padding: 2px 12px;\n color: var(--ink-2);\n border-left: 2px solid transparent;\n }\n .line:hover { background: var(--bg-1); }\n .ts { color: var(--ink-4); font-size: 10.5px; padding-top: 1px; }\n .lvl {\n font-size: 10px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px;\n }\n .line.info .lvl { color: var(--accent-2); }\n .line.warn .lvl { color: var(--warn); }\n .line.warn { border-left-color: var(--warn); background: oklch(0.7 0.18 35 / 0.04); }\n .line.err .lvl { color: var(--bad); }\n .line.err { border-left-color: var(--bad); background: oklch(0.65 0.22 25 / 0.05); }\n .line.dbg .lvl { color: var(--ink-3); }\n .line.ok .lvl { color: var(--ok); }\n .msg { color: var(--ink); white-space: pre-wrap; word-break: break-word; }\n\n .input {\n display: flex; align-items: center;\n border-top: 1px solid var(--line);\n background: var(--bg-0);\n padding: 0 10px;\n height: 32px; gap: 8px;\n }\n .prompt { color: var(--accent); font-family: var(--mono); font-size: 12px; }\n input[type=\"text\"] {\n flex: 1; background: transparent; border: none; outline: none;\n color: var(--ink); font-family: var(--mono); font-size: 12px;\n height: 100%;\n }\n input::placeholder { color: var(--ink-4); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => {\n consoleLines.value; consoleFilter.value; consolePaused.value;\n this.requestUpdate();\n });\n }\n\n override updated(): void {\n const body = this.renderRoot.querySelector('.body') as HTMLElement | null;\n if (body) body.scrollTop = body.scrollHeight;\n }\n\n private counts(): Record {\n const c: Record = { info: 0, warn: 0, err: 0, dbg: 0, ok: 0 };\n for (const l of consoleLines.value) c[l.level] = (c[l.level] ?? 0) + 1;\n c.all = consoleLines.value.length;\n return c;\n }\n\n private async exec(line: string): Promise {\n line = line.trim();\n if (!line) return;\n pushLog('info', `nvsim> ${line}`);\n pushReplHistory(line);\n this.hIdx = replHistory.value.length;\n const [cmd, ...args] = line.split(/\\s+/);\n const arg = args.join(' ');\n const c = getClient();\n switch (cmd) {\n case 'help':\n pushLog('info', 'commands: help · scene.list · sensor.config · run · pause · reset · seed · proof.verify · proof.export · clear · theme · status');\n break;\n case 'scene.list':\n pushLog('info', 'scene rebar-walkby-01:');\n pushLog('info', ' rebar.steel.coil @ [+2.7, 0.0, +0.3] m χ=5000');\n pushLog('info', ' dipole.heart_proxy @ [-1.4, +0.2, +0.4] m m=1.0e-6 A·m²');\n pushLog('info', ' loop.mains_60Hz @ [-1.6, -0.4, 0.0] m I=2 A');\n pushLog('info', ' eddy.door_steel @ [+0.0, +1.8, +0.4] m σ=1e6 S/m');\n break;\n case 'sensor.config':\n pushLog('info', 'NvSensor::cots_defaults() {');\n pushLog('info', ' pos=[0,0,0], V=1mm³, N=1e12, C=0.03, T2*=200ns');\n pushLog('info', ' D=2.870 GHz, γe=28 GHz/T, Γ=1.0 MHz, axes=4×〈111〉');\n pushLog('info', ' δB ≈ 1.18 pT/√Hz (Barry 2020 §III.A) }');\n break;\n case 'run':\n if (c) { await c.run(); running.value = true; pushLog('ok', 'pipeline RUN'); }\n break;\n case 'pause':\n if (c) { await c.pause(); running.value = false; pushLog('warn', 'pipeline PAUSED'); }\n break;\n case 'reset':\n if (c) { await c.reset(); pushLog('info', 'pipeline reset · t=0'); }\n break;\n case 'seed': {\n if (!arg) { pushLog('info', `current seed = 0x${seed.value.toString(16).toUpperCase()}`); break; }\n const v = BigInt(arg.startsWith('0x') ? arg : '0x' + arg);\n seed.value = v;\n if (c) await c.setSeed(v);\n pushLog('ok', `seed → 0x${v.toString(16).toUpperCase()}`);\n break;\n }\n case 'proof.verify': {\n if (!c) break;\n pushLog('dbg', 'computing SHA-256 over 256 frames…');\n try {\n const exp = expectedWitness.value;\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(expBytes);\n if (r.ok) { witnessVerified.value = 'ok'; witnessHex.value = exp; pushLog('ok', `witness ${exp.slice(0, 16)}… matches · determinism gate ✓`); }\n else { witnessVerified.value = 'fail'; pushLog('err', 'WITNESS MISMATCH'); }\n } catch (e) { pushLog('err', `verify failed: ${(e as Error).message}`); }\n break;\n }\n case 'proof.export': {\n if (!c) break;\n pushLog('dbg', 'building proof bundle…');\n try {\n const blob = await c.exportProofBundle();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `nvsim-proof-${Date.now()}.json`;\n a.click();\n URL.revokeObjectURL(url);\n pushLog('ok', `proof bundle exported · ${blob.size} bytes`);\n } catch (e) { pushLog('err', `export failed: ${(e as Error).message}`); }\n break;\n }\n case 'clear':\n consoleLines.value = [];\n break;\n case 'theme': {\n const t = (arg || '').toLowerCase();\n if (t === 'light' || t === 'dark') { theme.value = t; pushLog('ok', `theme → ${t}`); }\n else pushLog('info', 'theme [light|dark]');\n break;\n }\n case 'status':\n pushLog('info', `running=${running.value} seed=0x${seed.value.toString(16).toUpperCase()} verified=${witnessVerified.value}`);\n break;\n default:\n pushLog('err', `unknown command: ${cmd} · try help`);\n }\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Enter') { void this.exec(this.inputEl.value); this.inputEl.value = ''; }\n else if (e.key === 'ArrowUp') {\n const h = replHistory.value;\n if (h.length) {\n this.hIdx = Math.max(0, this.hIdx - 1);\n this.inputEl.value = h[this.hIdx] ?? '';\n e.preventDefault();\n }\n } else if (e.key === 'ArrowDown') {\n const h = replHistory.value;\n if (h.length) {\n this.hIdx = Math.min(h.length, this.hIdx + 1);\n this.inputEl.value = h[this.hIdx] ?? '';\n e.preventDefault();\n }\n }\n };\n\n override render() {\n const c = this.counts();\n const filter = consoleFilter.value;\n const visible = consoleLines.value.filter((l) => filter === 'all' || l.level === filter);\n return html`\n \n ${(['all', 'info', 'warn', 'err', 'dbg'] as const).map((k) => html`\n
consoleFilter.value = k}>\n ${k} ${c[k] ?? 0} \n \n `)}\n
\n
\n consoleLines.value = []}>× \n consolePaused.value = !consolePaused.value}>\n ${consolePaused.value ? '▶' : '❚❚'}\n \n
\n
\n \n ${visible.map((l) => {\n const ts = new Date(l.ts);\n const tsStr = `${String(ts.getSeconds()).padStart(2, '0')}.${String(ts.getMilliseconds()).padStart(3, '0')}`;\n // Use innerHTML pass-through via unsafe-html alt: inject raw html via property\n return html`
\n
${tsStr}
\n
${l.level}
\n
\n
`;\n })}\n
\n \n nvsim> \n \n
\n `;\n }\n}\n","/* RuView Edge App Store registry.\n *\n * Catalog of every WASM edge module shipping in the workspace plus the\n * `nvsim` simulator itself. Each entry maps to a hot-loadable algorithm\n * the dashboard can run in-browser (WASM transport) or push to a real\n * ESP32-S3 mesh (WS transport, deployed via WASM3 — ADR-040 Tier 3).\n *\n * Categories (ADR-041 event-ID ranges):\n * med 100–199 Medical & health\n * sec 200–299 Security & safety\n * bld 300–399 Smart building\n * ret 400–499 Retail & hospitality\n * ind 500–599 Industrial\n * sig 600–619 Signal-processing primitives\n * lrn 620–639 Online learning\n * spt 640–659 Spatial / graph\n * tmp 640–660 Temporal logic / planning\n * ais 700–719 AI safety\n * qnt 720–739 Quantum-flavoured signal\n * aut 740–759 Autonomy / mesh\n * exo 650–699 Exotic / research\n * sim — Pipeline simulators (nvsim)\n *\n * The `crate` field names the Cargo crate that owns the implementation.\n * `wasmEdge` apps are compiled out of `wifi-densepose-wasm-edge`;\n * `nvsim` apps come from `nvsim`. Future apps may target other crates.\n */\n\nexport type AppCategory =\n | 'sim'\n | 'med'\n | 'sec'\n | 'bld'\n | 'ret'\n | 'ind'\n | 'sig'\n | 'lrn'\n | 'spt'\n | 'tmp'\n | 'ais'\n | 'qnt'\n | 'aut'\n | 'exo';\n\nexport interface AppManifest {\n /** Stable kebab-case id; matches the wasm-edge module name (e.g. `med_sleep_apnea`). */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Category short-code. */\n category: AppCategory;\n /** Cargo crate the implementation lives in. */\n crate: 'nvsim' | 'wifi-densepose-wasm-edge' | string;\n /** One-liner description. */\n summary: string;\n /** Optional longer markdown body. */\n body?: string;\n /** Numeric event IDs this app emits (i32 codes from `event_types` mod). */\n events?: number[];\n /** Compute budget tier the module advertises. S=<5ms, M=<15ms, L=<50ms. */\n budget?: 'S' | 'M' | 'L';\n /** Default activation state when listed. */\n active?: boolean;\n /** Tags for fuzzy search and filtering. */\n tags?: string[];\n /** \"Available\", \"Beta\", or \"Research\" maturity. */\n status: 'available' | 'beta' | 'research';\n /** ADR back-reference. */\n adr?: string;\n}\n\nexport const APPS: AppManifest[] = [\n // ── Pipeline simulators ──────────────────────────────────────────────────\n {\n id: 'nvsim',\n name: 'nvsim — NV-diamond magnetometer',\n category: 'sim',\n crate: 'nvsim',\n summary:\n 'Deterministic forward simulator: scene → Biot–Savart → NV ensemble → ADC → MagFrame stream + SHA-256 witness.',\n budget: 'L',\n active: true,\n status: 'available',\n tags: ['quantum', 'magnetometer', 'simulator', 'witness', 'wasm'],\n adr: 'ADR-089',\n },\n\n // ── Core sensing primitives (ADR-014/040 flagship modules) ───────────────\n {\n id: 'gesture',\n name: 'Gesture (DTW)',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Dynamic-Time-Warping gesture classifier from CSI motion templates.',\n events: [1],\n budget: 'M',\n status: 'available',\n tags: ['hci', 'csi', 'classifier', 'dtw'],\n adr: 'ADR-014',\n },\n {\n id: 'coherence',\n name: 'Coherence gate',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Z-score coherence scoring + Accept/PredictOnly/Reject/Recalibrate gate.',\n events: [2],\n budget: 'S',\n status: 'available',\n tags: ['gate', 'csi', 'coherence', 'drift'],\n adr: 'ADR-029',\n },\n {\n id: 'adversarial',\n name: 'Adversarial-signal detector',\n category: 'ais',\n crate: 'wifi-densepose-wasm-edge',\n summary:\n 'Physically-impossible-signal detector — multi-link consistency, used to flag spoofed CSI.',\n events: [3],\n budget: 'M',\n status: 'available',\n tags: ['security', 'csi', 'spoofing', 'mesh'],\n adr: 'ADR-032',\n },\n {\n id: 'rvf',\n name: 'RVF — Rust Verified Feature stream',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Verified-frame builder with SHA-256 hash + version metadata for the feature stream.',\n budget: 'S',\n status: 'available',\n tags: ['witness', 'csi', 'hash'],\n adr: 'ADR-040',\n },\n {\n id: 'occupancy',\n name: 'Occupancy estimator',\n category: 'bld',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Through-wall presence + person-count via CSI amplitude perturbation.',\n events: [300, 301, 302],\n budget: 'S',\n status: 'available',\n tags: ['csi', 'building', 'presence'],\n },\n {\n id: 'vital_trend',\n name: 'Vital-trend monitor',\n category: 'med',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'HR + BR trend tracking with bradycardia/tachycardia/apnea events.',\n events: [100, 101, 102, 103, 104, 105],\n budget: 'S',\n status: 'available',\n tags: ['medical', 'vitals', 'csi'],\n adr: 'ADR-021',\n },\n {\n id: 'intrusion',\n name: 'Intrusion detector',\n category: 'sec',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Zone-based intrusion alert from CSI motion patterns.',\n events: [200, 201],\n budget: 'S',\n status: 'available',\n tags: ['security', 'zone', 'csi'],\n },\n\n // ── Medical & Health (100-series) ────────────────────────────────────────\n { id: 'med_sleep_apnea', name: 'Sleep-apnea detector', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Episodic respiratory pause detection during sleep cycles.', events: [105], budget: 'S', status: 'available', tags: ['medical', 'sleep', 'breathing'] },\n { id: 'med_cardiac_arrhythmia', name: 'Cardiac arrhythmia', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Beat-to-beat irregularity classifier from cardiac micro-Doppler.', events: [103, 104], budget: 'M', status: 'available', tags: ['medical', 'cardiac', 'arrhythmia'] },\n { id: 'med_respiratory_distress', name: 'Respiratory distress', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Distress signature: rapid shallow breathing + accessory-muscle motion.', events: [101, 102], budget: 'S', status: 'available', tags: ['medical', 'breathing', 'icu'] },\n { id: 'med_gait_analysis', name: 'Gait analysis', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Stride length, cadence, asymmetry from through-wall CSI pose tracking.', budget: 'M', status: 'available', tags: ['medical', 'gait', 'pose'] },\n { id: 'med_seizure_detect', name: 'Seizure detector', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Tonic-clonic seizure motion signature.', budget: 'M', status: 'beta', tags: ['medical', 'neuro'] },\n\n // ── Security (200-series) ────────────────────────────────────────────────\n { id: 'sec_perimeter_breach', name: 'Perimeter breach', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Approach/departure detection at user-defined boundary segments.', events: [210, 211, 212, 213], budget: 'S', status: 'available', tags: ['security', 'perimeter'] },\n { id: 'sec_weapon_detect', name: 'Metal anomaly / weapon', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Metal-perturbation flag in CSI; potential weapon presence (research).', events: [220, 221, 222], budget: 'M', status: 'research', tags: ['security', 'metal', 'csi'] },\n { id: 'sec_tailgating', name: 'Tailgating detector', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Detect 2+ persons crossing a single-passage threshold.', events: [230, 231, 232], budget: 'S', status: 'available', tags: ['security', 'access-control'] },\n { id: 'sec_loitering', name: 'Loitering detector', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Stationary occupancy past a configurable dwell threshold.', events: [240, 241, 242], budget: 'S', status: 'available', tags: ['security', 'dwell'] },\n { id: 'sec_panic_motion', name: 'Panic motion', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'High-energy distress motion: struggle / fleeing pattern.', events: [250, 251, 252], budget: 'S', status: 'beta', tags: ['security', 'distress'] },\n\n // ── Smart Building (300-series) ──────────────────────────────────────────\n { id: 'bld_hvac_presence', name: 'HVAC presence', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Occupied/activity-level/departure-countdown for HVAC zones.', events: [310, 311, 312], budget: 'S', status: 'available', tags: ['hvac', 'building', 'energy'] },\n { id: 'bld_lighting_zones', name: 'Lighting zones', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Per-zone light on/dim/off cues from occupancy.', events: [320, 321, 322], budget: 'S', status: 'available', tags: ['lighting', 'building'] },\n { id: 'bld_elevator_count', name: 'Elevator count', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Person count inside elevator car from CSI.', events: [330], budget: 'S', status: 'available', tags: ['elevator', 'building'] },\n { id: 'bld_meeting_room', name: 'Meeting-room utilization', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Meeting size + duration analytics for booking systems.', budget: 'S', status: 'available', tags: ['meeting', 'analytics'] },\n { id: 'bld_energy_audit', name: 'Energy audit', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Continuous occupancy-vs-HVAC-state audit for energy savings.', budget: 'M', status: 'available', tags: ['energy', 'audit'] },\n\n // ── Retail (400-series) ──────────────────────────────────────────────────\n { id: 'ret_queue_length', name: 'Queue length', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Live queue-length tracking for checkout / kiosks.', budget: 'S', status: 'available', tags: ['retail', 'queue'] },\n { id: 'ret_dwell_heatmap', name: 'Dwell heatmap', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Per-zone dwell time accumulation; analytics-only export.', budget: 'M', status: 'available', tags: ['retail', 'heatmap'] },\n { id: 'ret_customer_flow', name: 'Customer flow', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Origin-destination flow graph through a store layout.', budget: 'M', status: 'available', tags: ['retail', 'flow'] },\n { id: 'ret_table_turnover', name: 'Table turnover', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Restaurant table seat / vacate transitions.', budget: 'S', status: 'available', tags: ['retail', 'restaurant'] },\n { id: 'ret_shelf_engagement', name: 'Shelf engagement', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Reach-to-shelf gestures and dwell at product zones.', budget: 'M', status: 'available', tags: ['retail', 'shelf'] },\n\n // ── Industrial (500-series) ──────────────────────────────────────────────\n { id: 'ind_forklift_proximity', name: 'Forklift proximity', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Worker-near-forklift safety alert.', budget: 'S', status: 'available', tags: ['industrial', 'safety'] },\n { id: 'ind_confined_space', name: 'Confined-space monitor', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Last-person-out detection + presence audit for OSHA confined-space entries.', budget: 'S', status: 'available', tags: ['industrial', 'osha'] },\n { id: 'ind_clean_room', name: 'Clean-room PPE / motion', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Motion patterns consistent with proper PPE-clad movement.', budget: 'M', status: 'beta', tags: ['industrial', 'cleanroom'] },\n { id: 'ind_livestock_monitor', name: 'Livestock monitor', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Vital-sign + activity tracking for stall-bound livestock.', budget: 'M', status: 'beta', tags: ['agriculture', 'livestock'] },\n { id: 'ind_structural_vibration', name: 'Structural vibration', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Building/equipment micro-vibration via CSI phase derivative.', budget: 'M', status: 'research', tags: ['industrial', 'vibration'] },\n\n // ── Signal primitives (600-series) ───────────────────────────────────────\n { id: 'sig_coherence_gate', name: 'Coherence gate (extended)', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Hysteresis + multi-state coherence gate driving downstream apps.', budget: 'S', status: 'available', tags: ['gate', 'csi'] },\n { id: 'sig_flash_attention', name: 'Flash attention (CSI)', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Edge-friendly attention block for CSI subcarrier weighting.', budget: 'M', status: 'beta', tags: ['attention', 'csi'] },\n { id: 'sig_temporal_compress', name: 'Temporal-tensor compress', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'RuVector temporal-tensor compression on the CSI buffer.', budget: 'M', status: 'available', tags: ['compress', 'tensor'] },\n { id: 'sig_sparse_recovery', name: 'Sparse recovery', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: '114→56 subcarrier sparse interpolation via L1 solver.', budget: 'M', status: 'available', tags: ['sparse', 'csi'] },\n { id: 'sig_mincut_person_match', name: 'Mincut person-match', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Min-cut person assignment across multistatic frames.', budget: 'M', status: 'available', tags: ['mincut', 'matching'] },\n { id: 'sig_optimal_transport', name: 'Optimal transport', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'OT-based feature alignment between mesh nodes.', budget: 'M', status: 'beta', tags: ['ot', 'alignment'] },\n\n // ── Online learning ──────────────────────────────────────────────────────\n { id: 'lrn_dtw_gesture_learn', name: 'DTW gesture learn', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'On-device template learning for personalized gesture libraries.', budget: 'M', status: 'beta', tags: ['lifelong', 'gesture'] },\n { id: 'lrn_anomaly_attractor', name: 'Anomaly attractor', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Novelty detector with dynamic-attractor recall.', budget: 'M', status: 'research', tags: ['novelty', 'lifelong'] },\n { id: 'lrn_meta_adapt', name: 'Meta-adapt', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Meta-learning adapter for fast site-to-site transfer.', budget: 'L', status: 'research', tags: ['meta-learning'] },\n { id: 'lrn_ewc_lifelong', name: 'EWC++ lifelong', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Elastic-weight-consolidation gate to avoid catastrophic forgetting.', budget: 'M', status: 'beta', tags: ['lifelong', 'ewc'] },\n\n // ── Spatial / graph ──────────────────────────────────────────────────────\n { id: 'spt_pagerank_influence', name: 'PageRank influence', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Graph-influence ranking on the multistatic mesh.', budget: 'M', status: 'beta', tags: ['graph', 'pagerank'] },\n { id: 'spt_micro_hnsw', name: 'µHNSW vector index', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Tiny HNSW index for AETHER re-ID embeddings on-device.', budget: 'M', status: 'available', tags: ['hnsw', 'reid'] },\n { id: 'spt_spiking_tracker', name: 'Spiking tracker', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Spiking-network multi-target tracker.', budget: 'L', status: 'research', tags: ['snn', 'tracker'] },\n\n // ── Temporal / planning ──────────────────────────────────────────────────\n { id: 'tmp_pattern_sequence', name: 'Pattern sequence', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'Sequence-of-events pattern matcher (e.g. ingress→linger→egress).', budget: 'M', status: 'available', tags: ['temporal', 'pattern'] },\n { id: 'tmp_temporal_logic_guard', name: 'Temporal logic guard', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'LTL/MTL safety-property guard over event streams.', budget: 'M', status: 'beta', tags: ['ltl', 'safety'] },\n { id: 'tmp_goap_autonomy', name: 'GOAP autonomy', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'Goal-oriented action planning for adaptive routines.', budget: 'L', status: 'research', tags: ['planning', 'autonomy'] },\n\n // ── AI safety ────────────────────────────────────────────────────────────\n { id: 'ais_prompt_shield', name: 'Prompt shield', category: 'ais', crate: 'wifi-densepose-wasm-edge', summary: 'Edge-side LLM prompt-injection guard for on-device assistants.', budget: 'M', status: 'beta', tags: ['security', 'llm'] },\n { id: 'ais_behavioral_profiler', name: 'Behavioral profiler', category: 'ais', crate: 'wifi-densepose-wasm-edge', summary: 'Anomalous-behaviour profiler (drift in motion habits).', budget: 'M', status: 'beta', tags: ['anomaly', 'behaviour'] },\n\n // ── Quantum-flavoured ────────────────────────────────────────────────────\n { id: 'qnt_quantum_coherence', name: 'Quantum coherence', category: 'qnt', crate: 'wifi-densepose-wasm-edge', summary: 'Coherence diagnostics adapted for quantum-sensor signals.', budget: 'M', status: 'research', tags: ['quantum', 'coherence'] },\n { id: 'qnt_interference_search', name: 'Interference search', category: 'qnt', crate: 'wifi-densepose-wasm-edge', summary: 'Interferometric anomaly search across mesh viewpoints.', budget: 'L', status: 'research', tags: ['quantum', 'interference'] },\n\n // ── Autonomy / mesh ──────────────────────────────────────────────────────\n { id: 'aut_psycho_symbolic', name: 'Psycho-symbolic agent', category: 'aut', crate: 'wifi-densepose-wasm-edge', summary: 'Symbolic-rule + neural-feature hybrid for low-power autonomy loops.', budget: 'L', status: 'research', tags: ['autonomy', 'symbolic'] },\n { id: 'aut_self_healing_mesh', name: 'Self-healing mesh', category: 'aut', crate: 'wifi-densepose-wasm-edge', summary: 'Mesh-topology repair with per-node health gossip.', budget: 'M', status: 'beta', tags: ['mesh', 'health'] },\n\n // ── Exotic / Research (650-series) ───────────────────────────────────────\n { id: 'exo_ghost_hunter', name: 'Ghost hunter (anomaly)', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Empty-room CSI anomaly detector — impulsive/periodic/drift/random + hidden-presence sub-detector.', events: [650, 651, 652, 653], budget: 'S', status: 'available', tags: ['anomaly', 'paranormal', 'csi'], adr: 'ADR-041' },\n { id: 'exo_breathing_sync', name: 'Breathing sync', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Multi-person breathing synchrony analytics.', budget: 'M', status: 'beta', tags: ['breathing', 'sync'] },\n { id: 'exo_dream_stage', name: 'Dream-stage classifier', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'NREM/REM stage classification from breathing + micro-motion.', budget: 'M', status: 'research', tags: ['sleep', 'rem'] },\n { id: 'exo_emotion_detect', name: 'Emotion detector', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Coarse arousal/valence from breathing + heart-rate variability.', budget: 'M', status: 'research', tags: ['affect'] },\n { id: 'exo_gesture_language', name: 'Gesture language', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Sign-language pattern recognition.', budget: 'L', status: 'research', tags: ['hci', 'sign'] },\n { id: 'exo_happiness_score', name: 'Happiness score', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Aggregate well-being score from co-occupancy + activity dynamics.', budget: 'M', status: 'research', tags: ['affect', 'wellbeing'] },\n { id: 'exo_hyperbolic_space', name: 'Hyperbolic space embed', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Hyperbolic embeddings for hierarchical scene structure.', budget: 'L', status: 'research', tags: ['embedding', 'hyperbolic'] },\n { id: 'exo_music_conductor', name: 'Music conductor', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Map gesture energy to MIDI tempo/dynamics.', budget: 'M', status: 'research', tags: ['midi', 'art'] },\n { id: 'exo_plant_growth', name: 'Plant-growth tracker', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Slow CSI drift tracking for greenhouse foliage growth.', budget: 'L', status: 'research', tags: ['agriculture'] },\n { id: 'exo_rain_detect', name: 'Rain detector', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Outdoor CSI signature of rainfall.', budget: 'M', status: 'research', tags: ['weather'] },\n { id: 'exo_time_crystal', name: 'Time-crystal periodicity', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Periodicity diagnostics with anti-aliasing harmonics.', budget: 'M', status: 'research', tags: ['periodicity'] },\n];\n\nexport const CATEGORIES: Record = {\n sim: { label: 'Simulators', color: 'oklch(0.78 0.14 70)', range: '—' },\n med: { label: 'Medical & Health', color: 'oklch(0.65 0.22 25)', range: '100–199' },\n sec: { label: 'Security & Safety', color: 'oklch(0.7 0.18 35)', range: '200–299' },\n bld: { label: 'Smart Building', color: 'oklch(0.78 0.12 195)', range: '300–399' },\n ret: { label: 'Retail & Hospitality', color: 'oklch(0.78 0.14 145)', range: '400–499' },\n ind: { label: 'Industrial', color: 'oklch(0.72 0.18 330)', range: '500–599' },\n sig: { label: 'Signal Processing', color: 'oklch(0.78 0.14 70)', range: '600–619' },\n lrn: { label: 'Online Learning', color: 'oklch(0.78 0.12 260)', range: '620–639' },\n spt: { label: 'Spatial / Graph', color: 'oklch(0.7 0.18 100)', range: '640–659' },\n tmp: { label: 'Temporal / Planning', color: 'oklch(0.7 0.16 50)', range: '660–679' },\n ais: { label: 'AI Safety', color: 'oklch(0.65 0.22 25)', range: '700–719' },\n qnt: { label: 'Quantum', color: 'oklch(0.72 0.18 290)', range: '720–739' },\n aut: { label: 'Autonomy', color: 'oklch(0.78 0.14 145)', range: '740–759' },\n exo: { label: 'Exotic / Research', color: 'oklch(0.72 0.18 330)', range: '650–699' },\n};\n\nexport interface AppActivation {\n id: string;\n /** Active in the current session. */\n active: boolean;\n /** Last activation timestamp. */\n lastActivatedAt?: number;\n /** Last event count seen (for the cards' counter). */\n eventCount?: number;\n}\n\nexport function defaultActivations(): AppActivation[] {\n return APPS.map((a) => ({ id: a.id, active: a.active === true, eventCount: 0 }));\n}\n\nexport function appsByCategory(): Record {\n const map = {} as Record;\n for (const c of Object.keys(CATEGORIES) as AppCategory[]) map[c] = [];\n for (const a of APPS) map[a.category].push(a);\n return map;\n}\n\nexport function findApp(id: string): AppManifest | undefined {\n return APPS.find((a) => a.id === id);\n}\n\nexport function fuzzyMatch(query: string, app: AppManifest): number {\n if (!query) return 1;\n const q = query.toLowerCase();\n let score = 0;\n if (app.id.toLowerCase().includes(q)) score += 3;\n if (app.name.toLowerCase().includes(q)) score += 3;\n if (app.summary.toLowerCase().includes(q)) score += 1;\n if (app.tags?.some((t) => t.toLowerCase().includes(q))) score += 2;\n if (app.category === q) score += 5;\n return score;\n}\n","/* IndexedDB-backed persistence for settings and saved scenes.\n * Mirrors the mockup's `nvsim/kv` store. */\n\nconst DB_NAME = 'nvsim';\nconst DB_VER = 1;\nconst STORE = 'kv';\n\nlet dbPromise: Promise | null = null;\n\nfunction openDb(): Promise {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const req = indexedDB.open(DB_NAME, DB_VER);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n return dbPromise;\n}\n\nexport async function kvGet(key: string): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readonly');\n const r = tx.objectStore(STORE).get(key);\n r.onsuccess = () => resolve(r.result as T | undefined);\n r.onerror = () => reject(r.error);\n });\n}\n\nexport async function kvSet(key: string, value: unknown): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readwrite');\n tx.objectStore(STORE).put(value, key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport async function kvDelete(key: string): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readwrite');\n tx.objectStore(STORE).delete(key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n","/* App Store — catalog of every WASM edge module + simulator app.\n *\n * Mirrors `wifi-densepose-wasm-edge`'s 60+ hot-loadable algorithms and\n * the `nvsim` simulator. Each card is filterable by category, fuzzy\n * name search, and maturity (available / beta / research). A toggle on\n * each card flips activation in the live session — that drives the\n * dashboard's event log when running. WS transport (future) pushes the\n * activation set to the connected ESP32 mesh.\n *\n * ADR-092 §18.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { signal, effect } from '@preact/signals-core';\nimport {\n APPS, CATEGORIES, defaultActivations, fuzzyMatch,\n type AppCategory, type AppManifest, type AppActivation,\n} from '../store/apps';\nimport { kvGet, kvSet } from '../store/persistence';\nimport { pushLog } from '../store/appStore';\n\nconst activations = signal(defaultActivations());\nconst query = signal('');\nconst activeCat = signal('all');\nconst statusFilter = signal<'all' | 'available' | 'beta' | 'research'>('all');\n\n(async () => {\n const saved = await kvGet('app-activations');\n if (saved) activations.value = saved;\n})();\n\neffect(() => {\n // Persist activations on change (post-load).\n const v = activations.value;\n if (v.length > 0) void kvSet('app-activations', v);\n});\n\n@customElement('nv-app-store')\nexport class NvAppStore extends LitElement {\n @state() private renderTick = 0;\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n overflow-y: auto;\n background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);\n padding: 24px;\n }\n .head {\n display: flex; align-items: center; gap: 16px;\n margin-bottom: 18px;\n flex-wrap: wrap;\n }\n .ttl {\n font-size: 22px; font-weight: 700; letter-spacing: -0.02em;\n color: var(--ink);\n flex: 1; min-width: 200px;\n }\n .ttl small {\n font-size: 12.5px; font-weight: 400;\n color: var(--ink-3); margin-left: 8px;\n }\n .search {\n width: 320px; max-width: 100%;\n padding: 8px 12px;\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: 8px;\n font-family: var(--mono);\n font-size: 12.5px;\n color: var(--ink); outline: none;\n }\n .search:focus { border-color: var(--accent); }\n .filters {\n display: flex; flex-wrap: wrap; gap: 6px;\n margin-bottom: 18px;\n }\n .chip {\n padding: 4px 10px;\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 11.5px; color: var(--ink-3);\n cursor: pointer;\n font-family: var(--mono);\n display: inline-flex; align-items: center; gap: 4px;\n }\n .chip:hover { color: var(--ink); border-color: var(--line-2); }\n .chip.on { background: var(--bg-3); border-color: var(--accent); color: var(--ink); }\n .chip .swatch {\n width: 7px; height: 7px; border-radius: 50%;\n }\n .chip .count { color: var(--ink-3); font-size: 10px; }\n .grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n }\n .card {\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: var(--radius);\n padding: 12px 14px;\n display: flex; flex-direction: column; gap: 6px;\n transition: border-color 0.15s, transform 0.15s;\n position: relative;\n }\n .card:hover { border-color: var(--line-2); transform: translateY(-1px); }\n .card.active {\n border-color: oklch(0.78 0.14 145 / 0.7);\n background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 145 / 0.04) 100%);\n }\n .card-h {\n display: flex; align-items: flex-start; gap: 8px;\n margin-bottom: 2px;\n }\n .card-h .name {\n font-size: 13.5px; font-weight: 600; color: var(--ink);\n flex: 1; line-height: 1.3;\n }\n .card-h .swatch {\n width: 10px; height: 10px; border-radius: 50%;\n flex-shrink: 0; margin-top: 4px;\n }\n .summary {\n font-size: 12px; color: var(--ink-2); line-height: 1.45;\n flex: 1;\n }\n .meta {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;\n font-family: var(--mono); font-size: 10px;\n }\n .badge {\n padding: 1px 6px; border-radius: 4px;\n background: var(--bg-3); color: var(--ink-3);\n border: 1px solid var(--line);\n }\n .badge.cat { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.3); }\n .badge.status-available { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }\n .badge.status-beta { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }\n .badge.status-research { color: var(--accent-3); border-color: oklch(0.72 0.18 330 / 0.4); }\n .badge.budget { color: var(--accent-2); border-color: oklch(0.78 0.12 195 / 0.3); }\n .card-foot {\n display: flex; align-items: center; gap: 8px;\n padding-top: 8px; margin-top: 4px;\n border-top: 1px solid var(--line);\n font-size: 11px; color: var(--ink-3);\n }\n .toggle {\n position: relative;\n width: 32px; height: 18px;\n background: var(--bg-3); border: 1px solid var(--line-2);\n border-radius: 999px; cursor: pointer;\n transition: background 0.15s;\n flex-shrink: 0;\n }\n .toggle::after {\n content: ''; position: absolute;\n top: 1px; left: 1px;\n width: 12px; height: 12px;\n background: var(--ink-3); border-radius: 50%;\n transition: transform 0.15s, background 0.15s;\n }\n .toggle.on { background: var(--accent); border-color: var(--accent); }\n .toggle.on::after { background: #1a0f00; transform: translateX(14px); }\n .events {\n font-family: var(--mono); font-size: 10px; color: var(--ink-3);\n flex: 1;\n }\n .empty {\n padding: 40px;\n text-align: center; color: var(--ink-3);\n font-size: 13px;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { activations.value; query.value; activeCat.value; statusFilter.value; this.renderTick++; });\n }\n\n private isActive(id: string): boolean {\n return activations.value.find((a) => a.id === id)?.active === true;\n }\n\n private toggle(app: AppManifest): void {\n const next = activations.value.map((a) => a.id === app.id ? { ...a, active: !a.active, lastActivatedAt: Date.now() } : a);\n activations.value = next;\n pushLog(this.isActive(app.id) ? 'ok' : 'info', `app ${app.id} deactivated`);\n }\n\n private filtered(): AppManifest[] {\n let list = APPS;\n if (activeCat.value !== 'all') list = list.filter((a) => a.category === activeCat.value);\n if (statusFilter.value !== 'all') list = list.filter((a) => a.status === statusFilter.value);\n if (query.value.trim()) {\n list = list\n .map((a) => ({ a, s: fuzzyMatch(query.value, a) }))\n .filter((x) => x.s > 0)\n .sort((a, b) => b.s - a.s)\n .map((x) => x.a);\n }\n return list;\n }\n\n private categoryCounts(): Record {\n const counts: Record = { all: APPS.length };\n for (const k of Object.keys(CATEGORIES)) counts[k] = 0;\n for (const a of APPS) counts[a.category] = (counts[a.category] ?? 0) + 1;\n return counts;\n }\n\n override render() {\n const list = this.filtered();\n const counts = this.categoryCounts();\n const activeCount = activations.value.filter((a) => a.active).length;\n return html`\n \n
\n App Store\n ${APPS.length} edge apps · ${activeCount} active \n
\n
{ query.value = (e.target as HTMLInputElement).value; }} />\n
\n\n \n activeCat.value = 'all'}>\n All${counts.all} \n \n ${(Object.keys(CATEGORIES) as AppCategory[]).map((k) => html`\n activeCat.value = k}>\n \n ${CATEGORIES[k].label}\n ${counts[k] ?? 0} \n \n `)}\n \n statusFilter.value = 'all'}>any \n statusFilter.value = 'available'}>available \n statusFilter.value = 'beta'}>beta \n statusFilter.value = 'research'}>research \n
\n\n ${list.length === 0\n ? html`No apps match the current filters.
`\n : html`${list.map((app) => this.card(app))}
`}\n `;\n }\n\n private card(app: AppManifest) {\n const active = this.isActive(app.id);\n const cat = CATEGORIES[app.category];\n return html`\n \n
\n \n ${app.name} \n
\n
${app.summary}
\n
\n ${cat.label} \n ${app.status} \n ${app.budget ? html`budget ${app.budget} ` : ''}\n ${app.adr ? html`${app.adr} ` : ''}\n ${app.events?.length ? html`events ${app.events.join('·')} ` : ''}\n
\n \n
\n `;\n }\n}\n","/* Command palette ⌘K. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state, query } from 'lit/decorators.js';\nimport { toast } from './nv-toast';\nimport { openModal } from './nv-modal';\nimport {\n getClient, theme, expectedWitness, witnessHex, witnessVerified, pushLog, running,\n} from '../store/appStore';\n\ninterface Cmd { ico: string; label: string; kbd?: string; run: () => void; }\n\n@customElement('nv-palette')\nexport class NvPalette extends LitElement {\n @state() private open = false;\n @state() private filter = '';\n @state() private idx = 0;\n @query('#palette-input') private inputEl!: HTMLInputElement;\n\n static styles = css`\n :host {\n position: fixed; inset: 0; z-index: 220;\n background: rgba(0,0,0,0.5);\n opacity: 0; pointer-events: none;\n transition: opacity 0.15s;\n display: flex; justify-content: center; padding-top: 12vh;\n backdrop-filter: blur(4px);\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .palette {\n width: min(560px, 92vw);\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n overflow: hidden;\n display: flex; flex-direction: column;\n max-height: 60vh;\n }\n .input {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n }\n input {\n width: 100%;\n background: transparent; border: none; outline: none;\n color: var(--ink); font-size: 14px;\n font-family: inherit;\n }\n .list { flex: 1; overflow-y: auto; padding: 4px; }\n .item {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12.5px;\n }\n .item.active { background: var(--bg-3); }\n .item .ico { width: 20px; text-align: center; color: var(--accent); }\n .item .lbl { flex: 1; }\n .item .kbd {\n font-family: var(--mono); font-size: 10.5px;\n color: var(--ink-3);\n padding: 1px 5px; background: var(--bg-3); border-radius: 4px;\n }\n `;\n\n private cmds: Cmd[] = [\n { ico: '▶', label: 'Run pipeline', kbd: 'Space', run: async () => { await getClient()?.run(); running.value = true; toast('Pipeline running', '▶'); } },\n { ico: '❚', label: 'Pause pipeline', run: async () => { await getClient()?.pause(); running.value = false; toast('Paused', '❚❚'); } },\n { ico: '+', label: 'New scene…', kbd: '⌘N', run: () => openModal({\n title: 'New scene',\n body: `Build a fresh magnetic scene. The dashboard generates the JSON\n and pushes it to the running pipeline (or you can copy the JSON\n for offline use).
\n Name \n \n Heart-proxy dipole moment (A·m²) \n \n Distance heart → sensor (m) \n \n Add ferrous distractor at +x = 1 m? \n \n No \n Yes (steel coil, χ=5000) \n \n Add 60 Hz mains-current loop? \n \n No \n Yes (2 A loop, 5 cm radius, +y = 1 m) \n `,\n buttons: [\n { label: 'Cancel', variant: 'ghost' },\n { label: 'Create', variant: 'primary', onClick: async () => {\n const root = document.querySelector('nv-app')?.shadowRoot?.querySelector('nv-modal')?.shadowRoot;\n if (!root) return;\n const name = (root.querySelector('#ns-name')?.value ?? 'custom').trim();\n const m = parseFloat(root.querySelector('#ns-moment')?.value ?? '1e-6');\n const d = parseFloat(root.querySelector('#ns-distance')?.value ?? '0.5');\n const ferr = root.querySelector('#ns-ferrous')?.value === '1';\n const mains = root.querySelector('#ns-mains')?.value === '1';\n const scene = {\n dipoles: [{ position: [0, 0, d] as [number, number, number], moment: [0, 0, m] as [number, number, number] }],\n loops: mains ? [{\n centre: [0, 1, 0] as [number, number, number],\n normal: [0, 1, 0] as [number, number, number],\n radius: 0.05, current: 2.0, n_segments: 64,\n }] : [],\n ferrous: ferr ? [{ position: [1, 0, 0] as [number, number, number], volume: 1e-4, susceptibility: 5000 }] : [],\n eddy: [],\n sensors: [[0, 0, 0] as [number, number, number]],\n ambient_field: [1e-6, 0, 0] as [number, number, number],\n };\n await getClient()?.loadScene(scene);\n pushLog('ok', `scene ${name} loaded · 1 dipole · ${mains ? '1 loop · ' : ''}${ferr ? '1 ferrous · ' : ''}1 sensor`);\n toast(`Scene \"${name}\" loaded`, '+');\n } },\n ],\n }) },\n { ico: '📦', label: 'Export proof bundle…', kbd: '⌘E', run: async () => {\n const c = getClient(); if (!c) return;\n pushLog('dbg', 'building proof bundle…');\n try {\n const blob = await c.exportProofBundle();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `nvsim-proof-${Date.now()}.json`;\n a.click();\n URL.revokeObjectURL(url);\n pushLog('ok', `proof bundle exported · ${blob.size} bytes`);\n toast(`Proof bundle saved (${blob.size} B)`, '📦');\n } catch (e) { pushLog('err', `export failed: ${(e as Error).message}`); }\n } },\n { ico: '⟳', label: 'Reset pipeline', kbd: '⌘R', run: () => openModal({\n title: 'Reset pipeline?',\n body: 'Clears the frame stream and rewinds t to 0.
',\n buttons: [\n { label: 'Cancel', variant: 'ghost' },\n { label: 'Reset', variant: 'danger', onClick: async () => { await getClient()?.reset(); pushLog('warn', 'pipeline reset · t=0'); toast('Pipeline reset', '⟳'); } },\n ],\n }) },\n { ico: '✓', label: 'Verify witness', run: async () => {\n const c = getClient(); if (!c) return;\n witnessVerified.value = 'pending';\n const exp = expectedWitness.value;\n const eb = new Uint8Array(32);\n for (let i = 0; i < 32; i++) eb[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(eb);\n if (r.ok) { witnessVerified.value = 'ok'; witnessHex.value = exp; toast('Witness verified', '✓'); }\n else { witnessVerified.value = 'fail'; toast('Witness mismatch!', '✗'); }\n } },\n { ico: '☼', label: 'Toggle theme', kbd: '⌘/', run: () => { theme.value = theme.value === 'dark' ? 'light' : 'dark'; } },\n { ico: '⚙', label: 'Open settings', kbd: '⌘,', run: () => window.dispatchEvent(new CustomEvent('open-settings')) },\n { ico: '?', label: 'Keyboard shortcuts…', run: () => openModal({\n title: 'Keyboard shortcuts',\n body: `\n
⌘K / Ctrl K
Command palette
\n
Space
Play / pause
\n
⌘R
Reset
\n
⌘,
Settings
\n
⌘/
Toggle theme
\n
\\`
Debug HUD
\n
1 · 2 · 3
Inspector tabs
\n
Esc
Close modal/palette
\n
/
Focus REPL
\n
`,\n buttons: [{ label: 'Close', variant: 'primary' }],\n }) },\n { ico: 'i', label: 'About nvsim…', run: () => openModal({\n title: 'About nvsim',\n body: `nvsim is a deterministic, byte-reproducible forward simulator for nitrogen-vacancy diamond magnetometry.
\n This dashboard runs nvsim as WASM in a Web Worker. Same (scene, config, seed) → byte-identical SHA-256 witness across runs and machines.
\n License: MIT OR Apache-2.0 · See ADR-089, ADR-092.
`,\n buttons: [{ label: 'Close', variant: 'primary' }],\n }) },\n ];\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('keydown', this.onKey);\n window.addEventListener('nv-palette', this.onOpen as EventListener);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('keydown', this.onKey);\n window.removeEventListener('nv-palette', this.onOpen as EventListener);\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n this.openPal();\n } else if (e.key === 'Escape' && this.open) {\n this.closePal();\n } else if (this.open) {\n if (e.key === 'ArrowDown') { this.idx = Math.min(this.cmds.length - 1, this.idx + 1); e.preventDefault(); }\n else if (e.key === 'ArrowUp') { this.idx = Math.max(0, this.idx - 1); e.preventDefault(); }\n else if (e.key === 'Enter') { this.runIdx(); e.preventDefault(); }\n }\n };\n\n private onOpen = (): void => this.openPal();\n\n private openPal(): void {\n this.open = true; this.setAttribute('open', '');\n this.filter = ''; this.idx = 0;\n setTimeout(() => this.inputEl?.focus(), 0);\n }\n private closePal(): void { this.open = false; this.removeAttribute('open'); }\n\n private filtered(): Cmd[] {\n if (!this.filter.trim()) return this.cmds;\n const q = this.filter.toLowerCase();\n return this.cmds.filter((c) => c.label.toLowerCase().includes(q));\n }\n\n private runIdx(): void {\n const f = this.filtered();\n const c = f[this.idx];\n if (c) { c.run(); this.closePal(); }\n }\n\n override render() {\n const items = this.filtered();\n return html`\n \n
\n { this.filter = (e.target as HTMLInputElement).value; this.idx = 0; }} />\n
\n
\n ${items.map((c, i) => html`\n
{ this.idx = i; this.runIdx(); }}>\n ${c.ico} \n ${c.label} \n ${c.kbd ? html`${c.kbd} ` : ''}\n
\n `)}\n
\n
\n `;\n }\n}\n","/* Debug HUD toggled with `. Shows render fps, sim t, frames, |B|, SNR. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { fps, framesEmitted, bMag, snr, t as simT } from '../store/appStore';\n\n@customElement('nv-debug-hud')\nexport class NvDebugHud extends LitElement {\n @state() private open = false;\n @state() private renderFps = 0;\n private lastTs = performance.now();\n private frameCount = 0;\n private rafId = 0;\n\n static styles = css`\n :host {\n position: fixed; bottom: 8px; right: 8px;\n width: 220px;\n background: rgba(13,17,23,0.85);\n backdrop-filter: blur(8px);\n border: 1px solid var(--line-2);\n border-radius: 8px;\n padding: 8px 10px;\n font-family: var(--mono); font-size: 11px;\n color: var(--ink-2);\n z-index: 99;\n display: none;\n box-shadow: var(--shadow);\n }\n :host([open]) { display: block; }\n .h {\n display: flex; justify-content: space-between;\n font-weight: 600; color: var(--ink);\n margin-bottom: 6px; padding-bottom: 4px;\n border-bottom: 1px solid var(--line);\n }\n .x { cursor: pointer; color: var(--ink-3); }\n .row {\n display: flex; justify-content: space-between;\n padding: 1px 0;\n }\n .k { color: var(--ink-3); }\n .v { color: var(--ink); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('keydown', this.onKey);\n effect(() => { fps.value; framesEmitted.value; bMag.value; snr.value; simT.value; this.requestUpdate(); });\n this.tick();\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('keydown', this.onKey);\n cancelAnimationFrame(this.rafId);\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === '`' && !(e.target as HTMLElement).matches('input, textarea')) {\n this.open = !this.open;\n this.toggleAttribute('open', this.open);\n }\n };\n\n private tick = (): void => {\n this.rafId = requestAnimationFrame(this.tick);\n const now = performance.now();\n this.frameCount++;\n if (now - this.lastTs >= 500) {\n this.renderFps = (this.frameCount * 1000) / (now - this.lastTs);\n this.frameCount = 0;\n this.lastTs = now;\n this.requestUpdate();\n }\n };\n\n override render() {\n return html`\n nvsim · debug { this.open = false; this.removeAttribute('open'); }}>✕
\n render fps ${this.renderFps.toFixed(1)}
\n sim fps ${fps.value > 0 ? Math.round(fps.value) : '—'}
\n frames ${framesEmitted.value.toString()}
\n |B| ${(bMag.value * 1e9).toFixed(3)} nT
\n SNR ${snr.value > 0 ? snr.value.toFixed(1) : '—'}
\n DOM ${document.querySelectorAll('*').length}
\n `;\n }\n}\n","/* Settings drawer — theme / density / motion / auto-update. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { theme, density, motionReduced, autoUpdate, transport, wsUrl } from '../store/appStore';\n\n@customElement('nv-settings-drawer')\nexport class NvSettingsDrawer extends LitElement {\n @state() private open = false;\n\n static styles = css`\n :host {\n position: fixed; top: 0; right: 0; bottom: 0;\n width: 420px; max-width: 100vw;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n z-index: 51;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex; flex-direction: column;\n box-shadow: -20px 0 60px -20px rgba(0,0,0,0.5);\n }\n :host([open]) { transform: translateX(0); }\n .scrim {\n position: fixed; inset: 0;\n background: rgba(0,0,0,0.5);\n z-index: 50;\n opacity: 0; pointer-events: none;\n transition: opacity 0.2s;\n }\n :host([open]) .scrim { opacity: 1; pointer-events: auto; }\n .h {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n display: flex; align-items: center; justify-content: space-between;\n }\n .h .ttl { font-size: 14px; font-weight: 600; }\n .body { flex: 1; overflow-y: auto; padding: 16px; }\n .group { margin-bottom: 22px; }\n .group h4 {\n margin: 0 0 10px;\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.08em;\n color: var(--ink-3);\n }\n .row {\n display: flex; justify-content: space-between; align-items: center;\n padding: 10px 0;\n border-bottom: 1px solid var(--line);\n }\n .row:last-child { border-bottom: 0; }\n .row .lbl { font-size: 13px; }\n .row .desc { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }\n .row > div:first-child { flex: 1; padding-right: 12px; }\n .seg {\n display: inline-flex;\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 2px;\n }\n .seg button {\n padding: 4px 10px;\n background: transparent; border: none;\n border-radius: 6px;\n font-size: 11.5px; color: var(--ink-3);\n font-family: var(--mono);\n cursor: pointer;\n }\n .seg button.on { background: var(--bg-1); color: var(--ink); }\n .toggle {\n position: relative;\n width: 36px; height: 20px;\n background: var(--bg-3);\n border: 1px solid var(--line-2);\n border-radius: 999px;\n cursor: pointer;\n flex-shrink: 0;\n }\n .toggle::after {\n content: ''; position: absolute;\n top: 2px; left: 2px;\n width: 14px; height: 14px;\n background: var(--ink-3);\n border-radius: 50%;\n transition: transform 0.15s, background 0.15s;\n }\n .toggle.on { background: var(--accent); border-color: var(--accent); }\n .toggle.on::after { background: #1a0f00; transform: translateX(16px); }\n .close {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-2);\n }\n input[type=\"text\"] {\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 6px;\n padding: 6px 10px;\n color: var(--ink); font-family: var(--mono); font-size: 12px;\n outline: none;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { theme.value; density.value; motionReduced.value; autoUpdate.value; transport.value; wsUrl.value; this.requestUpdate(); });\n window.addEventListener('open-settings', () => { this.open = true; this.setAttribute('open', ''); });\n }\n\n private close(): void { this.open = false; this.removeAttribute('open'); }\n\n override render() {\n return html`\n this.close()}>
\n \n
Settings
\n
this.close()}>× \n
\n \n
\n
Appearance \n
\n
\n
\n theme.value = 'dark'}>dark \n theme.value = 'light'}>light \n
\n
\n
\n
\n
Density
\n
Affects panel padding and font scale.
\n
\n
\n density.value = 'comfy'}>comfy \n density.value = 'default'}>default \n density.value = 'compact'}>compact \n
\n
\n
\n
\n
Reduce motion
\n
Disable rotating crystal & field-line animation.
\n
\n
motionReduced.value = !motionReduced.value}> \n
\n
\n\n
\n
Pipeline \n
\n
Auto-rerun on edit
\n
Restart pipeline when scene/config changes.
\n
autoUpdate.value = !autoUpdate.value}> \n
\n
\n\n
\n
Transport \n
\n
\n
\n transport.value = 'wasm'}>WASM \n transport.value = 'ws'}>WS \n
\n
\n ${transport.value === 'ws' ? html`\n
\n
\n
wsUrl.value = (e.target as HTMLInputElement).value} />\n
` : ''}\n
\n
\n `;\n }\n}\n","/* First-run welcome tour. 5 steps walking the user through the\n * dashboard's main concepts. Persists `seen` flag in IndexedDB so it\n * only shows the first time. ADR-092 §10 Pass 6.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { kvGet, kvSet } from '../store/persistence';\n\ninterface TourStep {\n title: string;\n body: string;\n cta?: string;\n}\n\nconst STEPS: TourStep[] = [\n {\n title: 'Welcome to nvsim',\n body: `nvsim is an open-source, deterministic forward simulator for\n nitrogen-vacancy diamond magnetometry — a real Rust crate compiled to\n WASM and running in your browser, right now.
\n This 30-second tour highlights the four panels you'll use most.
`,\n cta: 'Start tour',\n },\n {\n title: '1. Scene canvas',\n body: `The middle panel shows your magnetic scene — sources you can\n drag (rebar, heart proxy, mains hum, ferrous door) and a single NV-diamond\n sensor in the centre. Field lines from each source connect to the sensor\n and animate while the pipeline runs.
\n Click 2 on your keyboard any time to jump to the Frame inspector.
`,\n },\n {\n title: '2. Run the pipeline',\n body: `Click the ▶ Run button (top-right) to start streaming\n MagFrame records at the digitiser's sample rate. The B-vector\n trace and Frame stream sparkline update live, and the FPS pill in the\n topbar shows the simulator's throughput in kHz.
\n Space toggles run/pause from anywhere.
`,\n },\n {\n title: '3. Witness panel',\n body: `The Witness tab is the heart of nvsim's determinism contract.\n Click Verify and the pipeline re-derives the SHA-256 over a 256-frame\n reference run and asserts it matches the constant pinned in the Rust crate.
\n Same input → same hash → byte-for-byte across browsers, OSes, transports.\n If the hash drifts, your build is non-canonical.
`,\n },\n {\n title: '4. App Store',\n body: `The grid icon on the left rail opens the App Store — every\n hot-loadable WASM edge module RuView ships, plus the simulators. 66 apps\n across 13 categories: medical, security, building, retail, industrial,\n signal, learning, autonomy, and more.
\n Toggle any card to mark it active in this session; the WS transport\n will push the activation set to a connected ESP32 mesh.
`,\n },\n {\n title: 'You are ready',\n body: `Press ⌘K (or Ctrl K ) any time for the command\n palette, ? for the full shortcuts list, or just start clicking.
\n Source on GitHub:\n github.com/ruvnet/RuView · ADR-089, ADR-092 · MIT/Apache-2.0.
`,\n cta: 'Get started',\n },\n];\n\n@customElement('nv-onboarding')\nexport class NvOnboarding extends LitElement {\n @state() private open = false;\n @state() private step = 0;\n\n static styles = css`\n :host {\n position: fixed; inset: 0;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(4px);\n z-index: 240;\n display: grid; place-items: center;\n opacity: 0; pointer-events: none;\n transition: opacity 0.18s;\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .card {\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n width: min(560px, 92vw);\n max-height: 86vh;\n display: flex; flex-direction: column;\n transform: translateY(12px) scale(0.98);\n transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);\n }\n :host([open]) .card { transform: translateY(0) scale(1); }\n .h {\n padding: 20px 22px 8px;\n display: flex; justify-content: space-between; align-items: flex-start;\n }\n .h h2 { margin: 0; font-size: 18px; letter-spacing: -0.01em; }\n .body {\n padding: 8px 22px 16px;\n font-size: 13px; color: var(--ink-2); line-height: 1.55;\n overflow-y: auto;\n }\n .body p { margin: 0 0 12px; }\n .body code, .body kbd {\n font-family: var(--mono); font-size: 11.5px;\n padding: 1px 5px; background: var(--bg-3);\n border: 1px solid var(--line); border-radius: 4px;\n color: var(--accent);\n }\n .footer {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 22px;\n border-top: 1px solid var(--line);\n }\n .dots { display: flex; gap: 6px; flex: 1; }\n .dot {\n width: 6px; height: 6px; border-radius: 50%;\n background: var(--bg-3); border: 1px solid var(--line-2);\n }\n .dot.active { background: var(--accent); border-color: var(--accent); }\n button {\n padding: 8px 14px;\n border-radius: 8px;\n font-size: 12.5px; font-weight: 500;\n border: 1px solid var(--line);\n background: var(--bg-2); color: var(--ink);\n cursor: pointer;\n font-family: inherit;\n }\n button.primary {\n background: var(--accent); border-color: var(--accent);\n color: #1a0f00;\n }\n button.ghost { background: transparent; }\n .skip {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px; color: var(--ink-2);\n }\n `;\n\n override async connectedCallback(): Promise {\n super.connectedCallback();\n window.addEventListener('nv-show-tour', this.show as EventListener);\n const seen = await kvGet('onboarding-seen');\n if (!seen) {\n this.open = true;\n this.setAttribute('open', '');\n }\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-show-tour', this.show as EventListener);\n }\n\n private show = (): void => {\n this.step = 0;\n this.open = true;\n this.setAttribute('open', '');\n };\n\n private async dismiss(): Promise {\n this.open = false;\n this.removeAttribute('open');\n await kvSet('onboarding-seen', true);\n }\n\n private next(): void {\n if (this.step < STEPS.length - 1) this.step++;\n else void this.dismiss();\n }\n\n private prev(): void {\n if (this.step > 0) this.step--;\n }\n\n override render() {\n const s = STEPS[this.step];\n return html`\n \n
\n
${s.title} \n this.dismiss()} aria-label=\"Skip tour\">× \n \n
\n \n
\n `;\n }\n}\n","/* Ghost Murmur — research view.\n *\n * Walks through the publicly-reported April 2026 CIA program and maps\n * the physically-defensible parts onto RuView's three-tier heartbeat\n * mesh. Source: docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md\n *\n * This view is reference material, not an operational mode. It exists\n * so practitioners (and journalists) can audit the physics-vs-press\n * gap in the open. ADR-092 §14b.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { getClient, pushLog } from '../store/appStore';\nimport type { TransientRunResult } from '../transport/NvsimClient';\n\n// Tier detection thresholds — order-of-magnitude floor each transport\n// can resolve cardiac signal at, in Tesla. Source: Ghost Murmur spec\n// §4.7, Wolf 2015, Barry 2020. These are deliberately optimistic for the\n// \"available\" path; the shoot-the-moon press claim sits 6+ orders below.\nconst TIERS = [\n { id: 'nvBest', label: 'NV-ensemble (best lab)', floorT: 1e-12, color: 'oklch(0.78 0.14 70)' },\n { id: 'nvCots', label: 'NV-DNV-B1 (COTS)', floorT: 3e-10, color: 'oklch(0.72 0.18 50)' },\n { id: 'squid', label: 'SQUID (shielded room)', floorT: 1e-15, color: 'oklch(0.78 0.12 195)' },\n { id: 'mmw', label: '60 GHz mmWave (μ-Doppler)', floorT: 0, color: 'oklch(0.78 0.14 145)' },\n { id: 'csi', label: 'WiFi CSI (presence)', floorT: 0, color: 'oklch(0.72 0.18 330)' },\n];\n\n// Cardiac dipole moment (A·m²) — order-of-magnitude estimate from\n// Wikswo / Bison cardiac MCG modelling.\nconst HEART_DIPOLE_AM2 = 5e-9;\n\n@customElement('nv-ghost-murmur')\nexport class NvGhostMurmur extends LitElement {\n @state() private distanceM = 0.1;\n @state() private momentLog10 = -8.3; // log10(5e-9)\n @state() private result: TransientRunResult | null = null;\n @state() private running = false;\n @state() private err: string | null = null;\n static styles = css`\n :host {\n display: block;\n height: 100%;\n overflow-y: auto;\n background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);\n padding: 24px 28px 60px;\n }\n h1 {\n margin: 0 0 4px;\n font-size: 22px;\n letter-spacing: -0.02em;\n color: var(--ink);\n }\n .subtitle {\n color: var(--ink-3);\n font-size: 13px;\n margin-bottom: 22px;\n }\n .links {\n display: flex; flex-wrap: wrap; gap: 6px;\n margin-bottom: 22px;\n }\n .links a {\n padding: 5px 10px;\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 11.5px;\n font-family: var(--mono);\n color: var(--accent-2);\n text-decoration: none;\n }\n .links a:hover { border-color: var(--accent-2); }\n h2 {\n font-size: 14px;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--ink-3);\n margin: 28px 0 10px;\n }\n .grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 12px;\n }\n .card {\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: var(--radius);\n padding: 14px;\n }\n .card h3 {\n margin: 0 0 8px;\n font-size: 13.5px; font-weight: 600;\n color: var(--ink);\n }\n .card p {\n font-size: 12.5px; color: var(--ink-2);\n margin: 0 0 8px;\n line-height: 1.5;\n }\n .card p:last-child { margin-bottom: 0; }\n .stat {\n display: inline-flex; align-items: baseline; gap: 6px;\n margin-right: 10px;\n }\n .stat .v {\n font-family: var(--mono); font-size: 16px; font-weight: 600;\n color: var(--accent);\n }\n .stat .l {\n font-size: 10px; color: var(--ink-3);\n text-transform: uppercase; letter-spacing: 0.04em;\n }\n table {\n width: 100%; border-collapse: collapse;\n font-size: 12.5px;\n }\n th, td {\n padding: 8px 10px;\n text-align: left;\n border-bottom: 1px solid var(--line);\n }\n th {\n color: var(--ink-3);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n }\n td.amber { color: var(--accent); font-family: var(--mono); }\n td.cyan { color: var(--accent-2); font-family: var(--mono); }\n td.bad { color: var(--bad); font-family: var(--mono); }\n .pill {\n display: inline-block;\n padding: 1px 6px;\n border-radius: 4px;\n font-family: var(--mono);\n font-size: 10px;\n border: 1px solid var(--line);\n }\n .pill.ok { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }\n .pill.skeptical { color: var(--bad); border-color: oklch(0.65 0.22 25 / 0.4); }\n .pill.partial { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }\n .architecture {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--ink-2);\n background: var(--bg-3);\n padding: 16px;\n border-radius: var(--radius-sm);\n border: 1px solid var(--line);\n white-space: pre;\n overflow-x: auto;\n line-height: 1.4;\n }\n .ethics {\n background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.65 0.22 25 / 0.04) 100%);\n border: 1px solid oklch(0.65 0.22 25 / 0.25);\n border-radius: var(--radius);\n padding: 16px;\n }\n .ethics h3 { color: var(--bad); margin-top: 0; }\n .ethics ul { padding-left: 18px; margin: 8px 0; }\n .ethics li { font-size: 12.5px; color: var(--ink-2); margin-bottom: 4px; }\n\n /* Demo */\n .demo {\n background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 70 / 0.04) 100%);\n border: 1px solid oklch(0.78 0.14 70 / 0.3);\n border-radius: var(--radius);\n padding: 18px;\n }\n .demo-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 18px;\n margin-top: 12px;\n }\n @media (max-width: 720px) { .demo-grid { grid-template-columns: 1fr; } }\n .control { margin-bottom: 14px; }\n .control .top {\n display: flex; justify-content: space-between;\n font-size: 12px; margin-bottom: 6px;\n }\n .control .top .lbl { color: var(--ink-3); }\n .control .top .val {\n font-family: var(--mono); color: var(--ink);\n }\n .control input[type=\"range\"] {\n -webkit-appearance: none; appearance: none;\n width: 100%; height: 4px;\n background: var(--bg-3); border-radius: 2px; outline: none;\n }\n .control input[type=\"range\"]::-webkit-slider-thumb {\n -webkit-appearance: none; appearance: none;\n width: 14px; height: 14px; border-radius: 50%;\n background: var(--accent); cursor: pointer;\n border: 2px solid var(--bg-2);\n }\n .demo-btn {\n width: 100%;\n padding: 10px;\n border: 1px solid var(--accent);\n background: var(--accent);\n color: #1a0f00;\n border-radius: 8px;\n font-size: 13px; font-weight: 600;\n cursor: pointer;\n }\n .demo-btn:hover { filter: brightness(1.08); }\n .demo-btn:disabled { opacity: 0.6; cursor: progress; }\n .readout {\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 8px;\n padding: 12px;\n }\n .readout-row {\n display: flex; justify-content: space-between;\n padding: 4px 0;\n font-family: var(--mono); font-size: 12px;\n }\n .readout-row .l { color: var(--ink-3); }\n .readout-row .v { color: var(--ink); }\n .readout-row .v.amber { color: var(--accent); }\n .tier-bar {\n position: relative;\n margin: 6px 0;\n height: 22px;\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 4px;\n overflow: hidden;\n }\n .tier-bar .fill {\n position: absolute; top: 0; bottom: 0; left: 0;\n transition: width 0.2s ease-out;\n border-right: 2px solid;\n }\n .tier-bar .lbl {\n position: relative; z-index: 1;\n font-family: var(--mono); font-size: 11px;\n padding: 3px 8px;\n color: var(--ink);\n display: flex; justify-content: space-between;\n pointer-events: none;\n }\n .verdict {\n margin-top: 10px;\n padding: 10px 12px;\n border-radius: 8px;\n font-size: 12.5px; font-weight: 500;\n border: 1px solid;\n }\n .verdict.ok { background: oklch(0.78 0.14 145 / 0.08); border-color: oklch(0.78 0.14 145 / 0.4); color: var(--ok); }\n .verdict.warn { background: oklch(0.7 0.18 35 / 0.08); border-color: oklch(0.7 0.18 35 / 0.4); color: var(--warn); }\n .verdict.bad { background: oklch(0.65 0.22 25 / 0.08); border-color: oklch(0.65 0.22 25 / 0.4); color: var(--bad); }\n .demo-notes {\n font-size: 11.5px; color: var(--ink-3);\n margin-top: 10px; line-height: 1.5;\n }\n `;\n\n /**\n * Predicted MCG dipole field (Tesla) at distance r in metres.\n * Far-field approximation: |B| ≈ μ₀ · m / (4π · r³). Source: Jackson 3e §5.\n */\n private predictedDipoleFieldT(r: number, m: number): number {\n const MU_0 = 4 * Math.PI * 1e-7;\n return (MU_0 * m) / (4 * Math.PI * Math.pow(Math.max(r, 1e-6), 3));\n }\n\n private async runDemo(): Promise {\n const c = getClient();\n if (!c) { this.err = 'WASM client not ready'; return; }\n this.err = null;\n this.running = true;\n this.requestUpdate();\n try {\n const r = this.distanceM;\n const m = Math.pow(10, this.momentLog10);\n // Heart proxy at +z = r, dipole moment along z = m A·m².\n const scene = {\n dipoles: [{ position: [0, 0, r] as [number, number, number], moment: [0, 0, m] as [number, number, number] }],\n loops: [],\n ferrous: [],\n eddy: [],\n sensors: [[0, 0, 0] as [number, number, number]],\n ambient_field: [0, 0, 0] as [number, number, number],\n };\n const config = {\n digitiser: { f_s_hz: 10000, f_mod_hz: 1000 },\n sensor: {\n gamma_fwhm_hz: 1.0e6,\n t1_s: 5.0e-3,\n t2_s: 1.0e-6,\n t2_star_s: 200e-9,\n contrast: 0.03,\n n_spins: 1.0e12,\n shot_noise_disabled: false,\n },\n dt_s: null,\n };\n this.result = await c.runTransient(scene, config, 42n, 64);\n pushLog('ok', `ghost-demo · r=${r.toFixed(3)} m · |B| recovered = ${(this.result.bMagT * 1e12).toExponential(2)} pT`);\n } catch (e) {\n this.err = (e as Error).message;\n pushLog('err', `ghost-demo failed: ${this.err}`);\n } finally {\n this.running = false;\n this.requestUpdate();\n }\n }\n\n private formatField(t: number): string {\n if (t === 0) return '0 T';\n const abs = Math.abs(t);\n if (abs >= 1e-3) return `${(t * 1e3).toFixed(2)} mT`;\n if (abs >= 1e-6) return `${(t * 1e6).toFixed(2)} µT`;\n if (abs >= 1e-9) return `${(t * 1e9).toFixed(3)} nT`;\n if (abs >= 1e-12) return `${(t * 1e12).toFixed(2)} pT`;\n if (abs >= 1e-15) return `${(t * 1e15).toFixed(2)} fT`;\n if (abs >= 1e-18) return `${(t * 1e18).toFixed(2)} aT`;\n return `${t.toExponential(2)} T`;\n }\n\n private formatDistance(r: number): string {\n if (r < 1) return `${(r * 100).toFixed(1)} cm`;\n if (r < 1000) return `${r.toFixed(2)} m`;\n if (r < 1e5) return `${(r / 1000).toFixed(2)} km`;\n return `${(r / 1609).toFixed(0)} mi`;\n }\n\n private renderDemo() {\n const m = Math.pow(10, this.momentLog10);\n const predicted = this.predictedDipoleFieldT(this.distanceM, m);\n const recovered = this.result?.bMagT ?? 0;\n const noiseFloor = (this.result?.noiseFloorPtSqrtHz ?? 0) * 1e-12; // pT/√Hz → T/√Hz\n\n const verdictPills = TIERS.map((t) => {\n let detect: 'ok' | 'warn' | 'bad' = 'bad';\n let label = 'below floor';\n if (t.id === 'mmw') {\n if (this.distanceM <= 5) { detect = 'ok'; label = 'µ-Doppler @ chest'; }\n else if (this.distanceM <= 15) { detect = 'warn'; label = 'edge of range'; }\n else { detect = 'bad'; label = 'out of range'; }\n } else if (t.id === 'csi') {\n if (this.distanceM <= 30) { detect = this.distanceM <= 10 ? 'ok' : 'warn'; label = 'presence/breathing'; }\n else { detect = 'bad'; label = 'out of range'; }\n } else if (t.floorT > 0) {\n const ratio = predicted / t.floorT;\n if (ratio > 100) { detect = 'ok'; label = `${ratio.toExponential(1)}× floor`; }\n else if (ratio > 1) { detect = 'warn'; label = `${ratio.toFixed(1)}× floor`; }\n else { detect = 'bad'; label = `${(1 / ratio).toExponential(1)}× too weak`; }\n }\n const fillPct = t.floorT > 0\n ? Math.max(2, Math.min(100, 100 + 12 * Math.log10(predicted / t.floorT)))\n : (t.id === 'mmw' ? Math.max(2, 100 - this.distanceM * 7) : Math.max(2, 100 - this.distanceM * 2));\n return html`\n \n
\n
\n ${t.label} \n ${label} \n
\n
\n `;\n });\n\n const overallDetect: 'ok' | 'warn' | 'bad' =\n predicted > 1e-12 ? 'ok' : predicted > 1e-15 ? 'warn' : 'bad';\n const overallText =\n overallDetect === 'ok'\n ? `Above NV-ensemble lab floor — close-range MCG plausible at ${this.formatDistance(this.distanceM)}.`\n : overallDetect === 'warn'\n ? `Below NV ensemble best, above SQUID — research-grade only at ${this.formatDistance(this.distanceM)}.`\n : `Below every published instrument's noise floor at ${this.formatDistance(this.distanceM)}. Press-release physics.`;\n\n return html`\n \n
Try it yourself \n
\n Place a cardiac dipole at variable distance from the NV sensor. The\n dashboard runs the real nvsim Rust pipeline (compiled to WASM)\n end-to-end and reports what each tier would actually detect. Same\n determinism contract as the rest of the dashboard.\n
\n
\n
\n
\n
\n Distance from sensor \n ${this.formatDistance(this.distanceM)} \n
\n
{ this.distanceM = Math.pow(10, +(e.target as HTMLInputElement).value); }} />\n
\n 10 cm → 100 km log scale\n
\n
\n
\n
\n Heart dipole moment \n ${m.toExponential(2)} A·m² \n
\n
{ this.momentLog10 = +(e.target as HTMLInputElement).value; }} />\n
\n published cardiac MCG ≈ 5×10⁻⁹ A·m²\n
\n
\n
this.runDemo()}>\n ${this.running ? 'Running nvsim…' : '▶ Run nvsim at this distance'}\n \n ${this.err ? html`
Error: ${this.err}
` : ''}\n
\n\n
\n
\n
\n Predicted |B| (1/r³) \n ${this.formatField(predicted)} \n
\n
\n Recovered |B| (nvsim) \n ${this.result ? this.formatField(recovered) : '—'} \n
\n
\n Sensor noise floor \n ${this.result ? this.formatField(noiseFloor) + '/√Hz' : '—'} \n
\n
\n Frames run \n ${this.result?.nFrames ?? '—'} \n
\n
\n Witness (this run) \n ${this.result?.witnessHex.slice(0, 16) ?? '—'}… \n
\n
\n
\n
\n Per-tier detectability\n
\n ${verdictPills}\n
\n
\n
\n
${overallText}
\n
\n The predicted value uses the closed-form magnetic-dipole\n far field |B| = μ₀·m / (4π·r³). The recovered\n value comes from the same Rust pipeline that drives the Witness panel —\n scene → Biot-Savart → NV ensemble → ADC → MagFrame. Use the moment\n slider to ask \"what if the heart were stronger?\". Use the distance\n slider to walk through 10 cm (clinical MCG), 1 m (close approach),\n 10 m (room-scale), 1 km (skeptic's range), and 65 km (the press claim).\n
\n
\n `;\n }\n\n override render() {\n return html`\n Ghost Murmur — open-source reality check \n \n The physics-vs-press audit for the publicly-reported April 2026\n CIA NV-diamond heartbeat detector, and how RuView's existing\n stack maps onto an honest, civilian version of the same idea.\n
\n\n \n\n What the press reported \n \n
\n
The story \n
3 Apr 2026: USAF F-15E pilot \"Dude 44 Bravo\" goes down in southern Iran during the regional exchange and evades for ~2 days.
\n
President Trump publicly suggests detection from 40 miles away on a mountainside at night; CIA Director Ratcliffe says \"invisible to the enemy, but not to the CIA.\"
\n
\n
\n
The named tech \n
\"Ghost Murmur\" — Lockheed Skunk Works system using NV defects in synthetic diamond + AI to extract a heartbeat from environmental noise.
\n
Outlets: Newsweek, Scientific American, Military.com, WION, Open The Magazine, Yahoo, Calcalist + HN thread #47679241.
\n
\n
\n
What physicists said \n
Wikswo (Vanderbilt), Orzel (Union College), Roth (Oakland) — all pushing back hard.
\n
\"At 1 km, the heartbeat field drops to ~10⁻¹² of its 10 cm value.\" MCG-only at multi-mile range is not consistent with published physics .
\n
\n
\n\n Live demo — nvsim WASM \n ${this.renderDemo()}\n\n Physics reality check \n \n
\n \n Distance Cardiac MCG (peak QRS) vs Earth field (~50 µT) \n \n \n 10 cm 50 pT 10⁹× weaker \n 1 m 50 fT 10¹²× weaker \n 10 m 50 aT 10¹⁵× weaker \n 1 km 5 × 10⁻²³ T 10²⁷× weaker \n 40 mi (65 km) ~10⁻²⁸ T 10³³× weaker \n \n
\n
\n Best published NV-ensemble lab record: 0.9 pT/√Hz [Wolf 2015].\n Best SQUID in a shielded room: ~1 fT/√Hz . To detect a single heartbeat at 10 m\n you'd need ~2 billion× more sensitivity than any published ensemble has ever shown,\n in a magnetically silent environment. 40 miles is press-release physics. \n
\n
\n\n RuView's three-tier mesh — what is actually buildable \n ┌──────────────────────────┐\n │ Tier 3 — NV-diamond │ Range: 0.1–2 m (lab)\n │ magnetometer ring │ Status: nvsim simulator only\n │ (close-confirm) │ Hardware: $$$ (≥$8k DNV-B1)\n └──────────┬───────────────┘\n │\n ┌──────────┴───────────────┐\n │ Tier 2 — 60 GHz FMCW │ Range: 1–10 m HR/BR\n │ mmWave radar mesh │ Status: shipping (ADR-021)\n │ (vital signs, posture) │ Hardware: $15 (MR60BHA2 + ESP32-C6)\n └──────────┬───────────────┘\n │\n ┌──────────┴───────────────┐\n │ Tier 1 — WiFi CSI mesh │ Range: 10–30 m through-wall\n │ (presence, breathing, │ Status: shipping (ADR-014, ADR-029)\n │ pose, intention) │ Hardware: $9 (ESP32-S3 8MB)\n └──────────┬───────────────┘\n │\n ▼\n ┌────────────────────────────────┐\n │ RuvSense multistatic fusion │\n │ + cross-viewpoint attention │\n │ + AETHER re-ID embeddings │\n │ + Cramer-Rao gating │\n └────────────────────────────────┘
\n\n Press claim → RuView equivalent \n \n
\n \n Press claim RuView equivalent today Crate / ADR Honest range \n \n \n \n NV-diamond magnetometry \n Deterministic NV pipeline simulator \n nvsim · ADR-089 \n Simulator only \n \n \n \"AI strips environmental noise\" \n RuvSense multistatic fusion + AETHER \n signal/ruvsense/ · ADR-029 \n Mature \n \n \n Heartbeat at distance \n 60 GHz FMCW HR/BR + WiFi CSI breathing \n vitals · ADR-021 \n 1–5 m HR · 10–30 m presence \n \n \n Long-range localisation \n Multistatic time-of-flight + CRLB \n ruvector/viewpoint/ \n Limited by node spacing \n \n \n 40-mile single-heartbeat detection \n Not feasible at any tier \n — \n Press-release physics \n \n \n
\n
\n\n Build today on $165 \n \n
\n
Bill of materials \n
\n 3 × ESP32-S3 8 MB ($9 ea) \n 3 × PoE injector + cat6 ($6 ea) \n 1 × ESP32-C6 + Seeed MR60BHA2 ($15) \n 1 × Raspberry Pi 5 8 GB ($80) \n 1 × unmanaged GbE switch ($25)\n
\n
Total: $165
\n
\n
\n
Honest performance \n 95% TPR (LOS, 0–15 m) \n ±2 bpm HR (LOS 0–3 m) \n ±1 br/min BR (any mode) \n ~10 cm pose error \n 80–150 ms end-to-end latency \n \n
\n
Determinism \n
Same (scene, config, seed) → byte-identical SHA-256 witness across browsers, OSes, transports.
\n
Reference: cc8de9b01b0ff5bd…
\n
Try the Witness tab on the right — it re-derives the hash live in this browser and compares against the published reference.
\n
\n
\n\n Privacy, ethics, legal \n \n
This is the open-source version. Same physics, opposite governance. \n
\n Civilian opt-in only — search-and-rescue, elder-care, occupancy, ICU vitals. Not surveillance. \n No directional pursuit — no beam-steering, target-following, or remote person-of-interest tracking. \n Data minimisation — fused output is (presence, HR, BR, pose, p_alive); raw streams discarded at the edge. \n PII gates (ADR-040) block identifying biometric streams from leaving the local mesh without consent. \n Adversarial-signal detection flags physically-impossible signal patterns from compromised mesh nodes. \n No export-controlled hardware — RuView targets < $50 COTS. ITAR/EAR sub-THz coherent radars and shielded NV ensembles are out of scope. \n \n
\n RuView is not affiliated with the United States government, the CIA, Lockheed Martin,\n or any classified program. References to \"Ghost Murmur\" in this view refer\n exclusively to the publicly-reported program of that name as covered in the open\n press in April 2026.\n
\n
\n\n Cross-references \n \n
\n ADRs: 014 (signal) · 021 (vitals) · 024 (AETHER) · 027 (MERIDIAN) ·\n 028 (witness audit) · 029 (RuvSense) · 040 (PII gates) · 086 (ESP32 RaBitQ) ·\n 089 (nvsim, Accepted) · 090 (Lindblad, Proposed-conditional) ·\n 091 (sub-THz radar research) · 092 (this dashboard) . \n Primary physics: Cohen 1970 · Bison 2009 · Wolf 2015 · Barry RMP 2020 · Doherty 2013 · Jackson 3e §5.6/§5.8.\n
\n
\n `;\n }\n}\n","/* Top-level shell: 4-zone grid with rail / topbar / sidebar / scene / inspector / console.\n * View routing is per-rail-button: the central area swaps between\n * ``, ``, etc. */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport './nv-rail';\nimport './nv-topbar';\nimport './nv-sidebar';\nimport './nv-scene';\nimport './nv-inspector';\nimport './nv-console';\nimport './nv-app-store';\nimport './nv-toast';\nimport './nv-modal';\nimport './nv-palette';\nimport './nv-debug-hud';\nimport './nv-settings-drawer';\nimport './nv-onboarding';\nimport './nv-ghost-murmur';\n\nexport type View = 'scene' | 'apps' | 'inspector' | 'witness' | 'ghost-murmur';\n\n@customElement('nv-app')\nexport class NvApp extends LitElement {\n @state() private view: View = 'scene';\n\n static styles = css`\n :host {\n display: block;\n height: 100vh;\n width: 100vw;\n background: var(--bg-0);\n }\n .skip-link {\n position: absolute;\n top: -40px;\n left: 8px;\n padding: 6px 12px;\n background: var(--accent);\n color: #1a0f00;\n border-radius: 6px;\n font-size: 12.5px;\n font-weight: 600;\n text-decoration: none;\n z-index: 1000;\n transition: top 0.15s;\n }\n .skip-link:focus { top: 8px; }\n .app {\n display: grid;\n grid-template-columns: 56px 280px 1fr 340px;\n grid-template-rows: 48px 1fr 220px;\n grid-template-areas:\n 'rail topbar topbar topbar'\n 'rail sidebar main inspector'\n 'rail sidebar console inspector';\n height: 100vh;\n width: 100vw;\n }\n nv-rail { grid-area: rail; }\n nv-topbar { grid-area: topbar; }\n nv-sidebar { grid-area: sidebar; }\n .main { grid-area: main; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n nv-inspector { grid-area: inspector; }\n nv-console { grid-area: console; min-height: 0; }\n @media (max-width: 1180px) {\n .app {\n grid-template-columns: 56px 1fr 320px;\n grid-template-areas:\n 'rail topbar topbar'\n 'rail main inspector'\n 'rail console console';\n }\n nv-sidebar { display: none; }\n }\n @media (max-width: 860px) {\n .app {\n grid-template-columns: 1fr;\n grid-template-rows: 52px 1fr 200px;\n grid-template-areas:\n 'topbar'\n 'main'\n 'console';\n }\n nv-rail, nv-sidebar, nv-inspector { display: none; }\n }\n `;\n\n override render() {\n return html`\n { e.preventDefault(); const sr = this.shadowRoot; sr?.querySelector('.main')?.focus(); }}>\n Skip to main content\n \n \n ) => (this.view = e.detail)}> \n \n \n \n ${this.view === 'apps'\n ? html` `\n : this.view === 'ghost-murmur'\n ? html` `\n : html` `}\n \n \n \n \n
\n \n \n \n \n \n \n `;\n }\n}\n","/* Common NvsimClient interface — both WasmClient and WsClient implement it.\n * Dashboard binds to this interface and never to a concrete client.\n * Aligns with ADR-092 §5.2.\n */\n\nexport interface PipelineConfigJson {\n digitiser?: {\n f_s_hz: number;\n f_mod_hz: number;\n lp_cutoff_hz?: number;\n };\n sensor?: {\n gamma_fwhm_hz?: number;\n t1_s?: number;\n t2_s?: number;\n t2_star_s?: number;\n contrast?: number;\n n_spins?: number;\n n_centers?: number;\n shot_noise_disabled?: boolean;\n };\n dt_s?: number | null;\n}\n\nexport interface SceneJson {\n dipoles: { position: [number, number, number]; moment: [number, number, number] }[];\n loops: {\n centre: [number, number, number];\n normal: [number, number, number];\n radius: number;\n current: number;\n n_segments: number;\n }[];\n ferrous: {\n position: [number, number, number];\n volume: number;\n susceptibility: number;\n }[];\n eddy: unknown[];\n sensors: [number, number, number][];\n ambient_field: [number, number, number];\n}\n\nexport interface MagFrameRecord {\n magic: number;\n version: number;\n flags: number;\n sensorId: number;\n tUs: bigint;\n bPt: [number, number, number];\n sigmaPt: [number, number, number];\n noiseFloorPtSqrtHz: number;\n temperatureK: number;\n raw: Uint8Array;\n}\n\nexport interface MagFrameBatch {\n frames: MagFrameRecord[];\n bytes: Uint8Array;\n}\n\nexport type NvsimEvent =\n | { type: 'log'; level: 'info' | 'warn' | 'err' | 'dbg' | 'ok'; msg: string }\n | { type: 'witness'; hex: string }\n | { type: 'fps'; value: number }\n | { type: 'state'; running: boolean; t: number; framesEmitted: number };\n\nexport interface RunOpts { frames?: number }\n\n/** One-shot pipeline run for \"what would the sensor recover at this scene?\"\n * use cases. Doesn't disturb the running pipeline. */\nexport interface TransientRunResult {\n bRecoveredT: [number, number, number];\n bMagT: number;\n noiseFloorPtSqrtHz: number;\n sigmaPt: [number, number, number];\n nFrames: number;\n witnessHex: string;\n}\n\nexport interface NvsimClient {\n loadScene(scene: SceneJson): Promise;\n setConfig(cfg: PipelineConfigJson): Promise;\n setSeed(seed: bigint): Promise;\n reset(): Promise;\n run(opts?: RunOpts): Promise;\n pause(): Promise;\n step(direction: 'fwd' | 'back', dtMs: number): Promise;\n\n onFrames(cb: (batch: MagFrameBatch) => void): void;\n onEvent(cb: (ev: NvsimEvent) => void): void;\n\n generateWitness(samples: number): Promise;\n verifyWitness(expected: Uint8Array): Promise<{ ok: true } | { ok: false; actual: Uint8Array }>;\n exportProofBundle(): Promise;\n runTransient(scene: SceneJson, config: PipelineConfigJson, seed: bigint, samples: number): Promise;\n\n buildId(): Promise;\n close(): Promise;\n}\n\n/** Parse one MagFrame from a 60-byte slice. Layout matches `nvsim::frame`. */\nexport function parseMagFrame(view: DataView, offset: number, raw: Uint8Array): MagFrameRecord {\n // v1 layout: magic(u32) | version(u16) | flags(u16) | sensor_id(u16) | _reserved(u16) |\n // t_us(u64) | b_pt[3](f32) | sigma_pt[3](f32) | noise_floor_pt_sqrt_hz(f32) |\n // temperature_k(f32) — 60 bytes total. All little-endian.\n const magic = view.getUint32(offset + 0, true);\n const version = view.getUint16(offset + 4, true);\n const flags = view.getUint16(offset + 6, true);\n const sensorId = view.getUint16(offset + 8, true);\n // skip 2 bytes reserved at offset+10\n const tUs = view.getBigUint64(offset + 12, true);\n const bx = view.getFloat32(offset + 20, true);\n const by = view.getFloat32(offset + 24, true);\n const bz = view.getFloat32(offset + 28, true);\n const sx = view.getFloat32(offset + 32, true);\n const sy = view.getFloat32(offset + 36, true);\n const sz = view.getFloat32(offset + 40, true);\n const noiseFloorPtSqrtHz = view.getFloat32(offset + 44, true);\n const temperatureK = view.getFloat32(offset + 48, true);\n return {\n magic,\n version,\n flags,\n sensorId,\n tUs,\n bPt: [bx, by, bz],\n sigmaPt: [sx, sy, sz],\n noiseFloorPtSqrtHz,\n temperatureK,\n raw: raw.subarray(offset, offset + 60),\n };\n}\n\nexport function parseFrameBatch(bytes: Uint8Array): MagFrameRecord[] {\n const frameSize = 60;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const out: MagFrameRecord[] = [];\n for (let off = 0; off + frameSize <= bytes.byteLength; off += frameSize) {\n out.push(parseMagFrame(view, off, bytes));\n }\n return out;\n}\n","/* Default `NvsimClient` implementation. Talks to the Web Worker that\n * hosts the nvsim WASM module. ADR-092 §5.4 + §6.3. */\n\nimport {\n type NvsimClient,\n type SceneJson,\n type PipelineConfigJson,\n type RunOpts,\n type MagFrameBatch,\n type NvsimEvent,\n type TransientRunResult,\n parseFrameBatch,\n} from './NvsimClient';\n\ninterface PendingRequest {\n resolve: (v: T) => void;\n reject: (err: Error) => void;\n}\n\nexport interface WasmBootInfo {\n buildVersion: string;\n frameMagic: number;\n frameBytes: number;\n expectedWitnessHex: string;\n}\n\nexport class WasmClient implements NvsimClient {\n private worker: Worker;\n private nextId = 1;\n private pending = new Map>();\n private frameSubs = new Set<(b: MagFrameBatch) => void>();\n private eventSubs = new Set<(e: NvsimEvent) => void>();\n private bootInfo: WasmBootInfo | null = null;\n\n constructor() {\n this.worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });\n this.worker.addEventListener('message', (ev) => this.onMessage(ev));\n this.worker.addEventListener('error', (e) =>\n this.eventSubs.forEach((s) => s({ type: 'log', level: 'err', msg: String(e.message) })),\n );\n }\n\n private onMessage(ev: MessageEvent): void {\n const m = ev.data as { type: string; id?: number; [k: string]: unknown };\n if (m.type === 'frames') {\n const buf = m.batch as ArrayBuffer;\n const bytes = new Uint8Array(buf);\n const frames = parseFrameBatch(bytes);\n const batch: MagFrameBatch = { frames, bytes };\n this.frameSubs.forEach((s) => s(batch));\n const fps = m.fps as number;\n if (fps > 0) {\n this.eventSubs.forEach((s) => s({ type: 'fps', value: fps }));\n }\n return;\n }\n if (m.type === 'state') {\n this.eventSubs.forEach((s) =>\n s({\n type: 'state',\n running: Boolean(m.running),\n t: 0,\n framesEmitted: Number(m.framesEmitted ?? 0),\n }),\n );\n return;\n }\n if (m.type === 'ready') {\n return;\n }\n if (m.type === 'err' && m.id == null) {\n this.eventSubs.forEach((s) =>\n s({ type: 'log', level: 'err', msg: String(m.msg) }),\n );\n return;\n }\n if (typeof m.id === 'number' && this.pending.has(m.id)) {\n const p = this.pending.get(m.id)!;\n this.pending.delete(m.id);\n if (m.type === 'err') p.reject(new Error(String(m.msg)));\n else p.resolve(m);\n }\n }\n\n private rpc(msg: Record, transfer: Transferable[] = []): Promise {\n const id = this.nextId++;\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject });\n this.worker.postMessage({ ...msg, id }, transfer);\n });\n }\n\n async boot(): Promise {\n if (this.bootInfo) return this.bootInfo;\n // Pass Vite's resolved BASE_URL so the worker can locate /nvsim-pkg/\n // under the same prefix the dashboard is served from (e.g. /RuView/nvsim/\n // on GitHub Pages, \"/\" in dev).\n const base = import.meta.env.BASE_URL ?? '/';\n const r = await this.rpc<{ buildVersion: string; frameMagic: number; frameBytes: number; expectedWitnessHex: string }>(\n { type: 'boot', base },\n );\n this.bootInfo = {\n buildVersion: r.buildVersion,\n frameMagic: r.frameMagic,\n frameBytes: r.frameBytes,\n expectedWitnessHex: r.expectedWitnessHex,\n };\n return this.bootInfo;\n }\n\n async loadScene(scene: SceneJson): Promise {\n await this.rpc({ type: 'setScene', json: JSON.stringify(scene) });\n }\n\n async setConfig(cfg: PipelineConfigJson): Promise {\n await this.rpc({ type: 'setConfig', json: JSON.stringify(cfg) });\n }\n\n async setSeed(seed: bigint): Promise {\n await this.rpc({ type: 'setSeed', seed: Number(seed & 0xFFFFFFFFn) });\n }\n\n async reset(): Promise {\n await this.rpc({ type: 'reset' });\n }\n\n async run(_opts?: RunOpts): Promise {\n await this.rpc({ type: 'run' });\n }\n\n async pause(): Promise {\n await this.rpc({ type: 'pause' });\n }\n\n async step(_direction: 'fwd' | 'back', _dtMs: number): Promise {\n await this.rpc({ type: 'step' });\n }\n\n onFrames(cb: (batch: MagFrameBatch) => void): void { this.frameSubs.add(cb); }\n onEvent(cb: (ev: NvsimEvent) => void): void { this.eventSubs.add(cb); }\n\n async generateWitness(samples: number): Promise {\n const r = await this.rpc<{ witness: ArrayBuffer; hex: string }>({ type: 'witnessGenerate', samples });\n return new Uint8Array(r.witness);\n }\n\n async verifyWitness(expected: Uint8Array): Promise<{ ok: true } | { ok: false; actual: Uint8Array }> {\n const buf = expected.slice().buffer;\n const r = await this.rpc<{ ok: boolean; actual: ArrayBuffer; actualHex: string }>(\n { type: 'witnessVerify', samples: 256, expected: buf },\n [buf],\n );\n if (r.ok) return { ok: true };\n return { ok: false, actual: new Uint8Array(r.actual) };\n }\n\n async runTransient(\n scene: SceneJson,\n config: PipelineConfigJson,\n seed: bigint,\n samples: number,\n ): Promise {\n const r = await this.rpc<{\n bRecoveredT: number[];\n bMagT: number;\n noiseFloorPtSqrtHz: number;\n sigmaPt: number[];\n nFrames: number;\n witnessHex: string;\n }>({\n type: 'runTransient',\n scene: JSON.stringify(scene),\n config: JSON.stringify(config),\n seed: Number(seed & 0xFFFFFFFFn),\n samples,\n });\n return {\n bRecoveredT: [r.bRecoveredT[0], r.bRecoveredT[1], r.bRecoveredT[2]],\n bMagT: r.bMagT,\n noiseFloorPtSqrtHz: r.noiseFloorPtSqrtHz,\n sigmaPt: [r.sigmaPt[0], r.sigmaPt[1], r.sigmaPt[2]],\n nFrames: r.nFrames,\n witnessHex: r.witnessHex,\n };\n }\n\n async exportProofBundle(): Promise {\n // Bundle = REFERENCE_SCENE_JSON + computed witness hex + version. Wraps\n // the same artifacts `Proof::generate` produces natively. ADR-092 §6.1.\n const w = await this.generateWitness(256);\n const hex = Array.from(w).map((b) => b.toString(16).padStart(2, '0')).join('');\n const info = this.bootInfo ?? (await this.boot());\n const manifest = JSON.stringify(\n {\n kind: 'nvsim-proof-bundle',\n version: info.buildVersion,\n seed: '0x0000002A',\n nSamples: 256,\n witness: hex,\n expected: info.expectedWitnessHex,\n ok: hex === info.expectedWitnessHex,\n ts: new Date().toISOString(),\n },\n null,\n 2,\n );\n return new Blob([manifest], { type: 'application/json' });\n }\n\n async buildId(): Promise {\n const r = await this.rpc<{ buildId: string }>({ type: 'buildId' });\n return r.buildId;\n }\n\n async close(): Promise {\n this.worker.terminate();\n }\n}\n","/* nvsim dashboard entry — boots the WasmClient, mounts . */\nimport './app.css';\nimport './components/nv-app';\nimport { effect } from '@preact/signals-core';\n\nimport { WasmClient } from './transport/WasmClient';\nimport {\n setClient, transport, theme, density, motionReduced,\n pushLog, expectedWitness, framesEmitted, fps, lastB, bMag,\n pushTrace, pushStripBar, lastFrame, sceneJson, witnessHex,\n replHistory, scenePositions, type SceneItemPos,\n} from './store/appStore';\nimport { kvGet, kvSet } from './store/persistence';\n\nfunction applyTheme(t: string): void {\n document.documentElement.setAttribute('data-theme', t);\n}\nfunction applyDensity(d: string): void {\n document.body.classList.remove('density-comfy', 'density-default', 'density-compact');\n document.body.classList.add(`density-${d}`);\n}\nfunction applyMotion(reduced: boolean): void {\n document.body.classList.toggle('reduce-motion', reduced);\n}\n\n(async () => {\n // Restore persisted prefs\n const t = (await kvGet<'dark' | 'light'>('theme')) ?? 'dark';\n const d = (await kvGet<'comfy' | 'default' | 'compact'>('density')) ?? 'default';\n const sysMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n const m = (await kvGet('motionReduced')) ?? sysMotion;\n theme.value = t; applyTheme(t);\n density.value = d; applyDensity(d);\n motionReduced.value = m; applyMotion(m);\n\n // React to changes → persist\n effect(() => { applyTheme(theme.value); kvSet('theme', theme.value); });\n effect(() => { applyDensity(density.value); kvSet('density', density.value); });\n effect(() => { applyMotion(motionReduced.value); kvSet('motionReduced', motionReduced.value); });\n\n // REPL history + scene drag positions persistence (P0.10, P1.7)\n const histSaved = await kvGet('repl-history');\n if (histSaved && Array.isArray(histSaved)) replHistory.value = histSaved;\n effect(() => { void kvSet('repl-history', replHistory.value); });\n const positionsSaved = await kvGet('scene-positions');\n if (positionsSaved && Array.isArray(positionsSaved)) scenePositions.value = positionsSaved;\n effect(() => { void kvSet('scene-positions', scenePositions.value); });\n\n // Boot WASM client\n const client = new WasmClient();\n setClient(client);\n\n pushLog('info', 'nvsim — booting WASM runtime');\n client.onEvent((ev) => {\n if (ev.type === 'log') pushLog(ev.level, ev.msg);\n if (ev.type === 'fps') fps.value = ev.value;\n if (ev.type === 'state') {\n framesEmitted.value = BigInt(ev.framesEmitted);\n }\n });\n\n client.onFrames((batch) => {\n if (batch.frames.length === 0) return;\n const last = batch.frames[batch.frames.length - 1];\n lastFrame.value = last;\n const bx = last.bPt[0] * 1e-12; // pT → T\n const by = last.bPt[1] * 1e-12;\n const bz = last.bPt[2] * 1e-12;\n lastB.value = [bx, by, bz];\n bMag.value = Math.sqrt(bx * bx + by * by + bz * bz);\n // For trace display we use nT scale.\n pushTrace([bx * 1e9, by * 1e9, bz * 1e9]);\n const amp = Math.min(1, Math.abs(bz * 1e9) / 5 + 0.3);\n pushStripBar(amp);\n });\n\n try {\n const info = await client.boot();\n expectedWitness.value = info.expectedWitnessHex;\n pushLog('ok', `WASM module ready · nvsim@${info.buildVersion} · magic=0x${info.frameMagic.toString(16).toUpperCase()}`);\n pushLog('info', `expected witness · ${info.expectedWitnessHex.slice(0, 16)}…`);\n\n // Load reference scene by default.\n sceneJson.value = '(reference scene)';\n transport.value = 'wasm';\n } catch (e) {\n pushLog('err', `boot failed: ${(e as Error).message}`);\n }\n\n // Auto-verify witness once at boot — proves WASM determinism contract.\n try {\n const exp = expectedWitness.value;\n if (exp) {\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await client.verifyWitness(expBytes);\n if (r.ok) {\n witnessHex.value = exp;\n pushLog('ok', `witness verified · determinism gate ✓`);\n } else {\n const actual = Array.from(r.actual)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n witnessHex.value = actual;\n pushLog('err', `WITNESS MISMATCH · expected ${exp.slice(0, 16)}… got ${actual.slice(0, 16)}…`);\n }\n }\n } catch (e) {\n pushLog('warn', `witness verify skipped: ${(e as Error).message}`);\n }\n})();\n"],"names":["t","e","o","r","n","i","s","c","NvRail","LitElement","v","html","css","__decorateClass","property","customElement","transport","signal","wsUrl","running","speed","framesEmitted","seed","fs","fmod","dtMs","noiseEnabled","theme","density","motionReduced","autoUpdate","lastB","bMag","snr","fps","witnessHex","witnessVerified","expectedWitness","lastFrame","traceX","traceY","traceZ","stripBars","sceneName","sceneJson","consolePaused","consoleFilter","replHistory","pushReplHistory","cmd","next","scenePositions","transportLabel","computed","_client","setClient","getClient","consoleLines","MAX_LINES","pushLog","level","msg","pushTrace","b","x","y","z","pushStripBar","amp","NvModal","root","trap","focusables","el","first","last","active","state","openModal","req","NvToast","detail","toast","icon","NvTopbar","effect","cur","inp","raw","seedHex","configPushTimer","pushConfigDebounced","NvSidebar","NvScene","id","item","svgEl","pt","it","saved","p","f","bmag","sigmaMax","snrVal","speeds","idx","k","vbX","vbY","bnT","bMagNT","animClass","vbW","vbH","svg","NvInspector","changed","exp","expBytes","actual","make","arr","bytes","hex","status","cls","label","NvConsole","h","body","l","line","args","arg","blob","url","a","filter","visible","ts","tsStr","query","APPS","CATEGORIES","defaultActivations","fuzzyMatch","app","q","score","DB_NAME","DB_VER","STORE","dbPromise","openDb","resolve","reject","db","kvGet","key","kvSet","value","tx","activations","activeCat","statusFilter","NvAppStore","list","counts","activeCount","cat","NvPalette","name","m","d","ferr","mains","scene","eb","items","NvDebugHud","now","simT","NvSettingsDrawer","STEPS","NvOnboarding","_","TIERS","NvGhostMurmur","config","abs","predicted","recovered","noiseFloor","verdictPills","detect","ratio","fillPct","overallDetect","overallText","NvApp","parseMagFrame","view","offset","magic","version","flags","sensorId","tUs","bx","by","bz","sx","sy","sz","noiseFloorPtSqrtHz","temperatureK","parseFrameBatch","out","off","WasmClient","ev","buf","batch","transfer","cfg","_opts","_direction","_dtMs","cb","samples","expected","w","info","manifest","applyTheme","applyDensity","applyMotion","reduced","sysMotion","histSaved","positionsSaved","client"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4]}
\ No newline at end of file
diff --git a/nvsim/index.html b/nvsim/index.html
index 260b6da9..1f62d289 100644
--- a/nvsim/index.html
+++ b/nvsim/index.html
@@ -10,7 +10,7 @@
-
+
diff --git a/nvsim/sw.js b/nvsim/sw.js
index 294fdca6..b8683485 100644
--- a/nvsim/sw.js
+++ b/nvsim/sw.js
@@ -1,2 +1,2 @@
-if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let o={};const l=e=>i(e,c),d={module:{uri:c},exports:o,require:l};s[c]=Promise.all(n.map(e=>d[e]||l(e))).then(e=>(r(...e),o))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"4bcaa063d693b37532f242f566232490"},{url:"index.html",revision:"89c26907fa424b69e8502586989f4bee"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"a617e7e24b2d5e976ce7e8d4f473104d"},{url:"nvsim-pkg/nvsim.js",revision:"ff4ecdcc8ace84fd24c4ad396809bd88"},{url:"assets/worker-C19MRcXs.js",revision:null},{url:"assets/signals-SG45zFCj.js",revision:null},{url:"assets/lit-BS7WqYd5.js",revision:null},{url:"assets/index-meW-_lqo.js",revision:null},{url:"assets/index-CyUCBwRA.css",revision:null},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"nvsim-pkg/nvsim.js",revision:"ff4ecdcc8ace84fd24c4ad396809bd88"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"a617e7e24b2d5e976ce7e8d4f473104d"},{url:"manifest.webmanifest",revision:"e8c97968cae19a0ed3b64c1303a27a90"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
+if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let o={};const l=e=>i(e,c),d={module:{uri:c},exports:o,require:l};s[c]=Promise.all(n.map(e=>d[e]||l(e))).then(e=>(r(...e),o))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"4bcaa063d693b37532f242f566232490"},{url:"index.html",revision:"a81e9aaaffb4924e759f42842815b902"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"a617e7e24b2d5e976ce7e8d4f473104d"},{url:"nvsim-pkg/nvsim.js",revision:"ff4ecdcc8ace84fd24c4ad396809bd88"},{url:"assets/worker-C19MRcXs.js",revision:null},{url:"assets/signals-SG45zFCj.js",revision:null},{url:"assets/lit-BS7WqYd5.js",revision:null},{url:"assets/index-CyUCBwRA.css",revision:null},{url:"assets/index-CjC_xGBQ.js",revision:null},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"nvsim-pkg/nvsim.js",revision:"ff4ecdcc8ace84fd24c4ad396809bd88"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"a617e7e24b2d5e976ce7e8d4f473104d"},{url:"manifest.webmanifest",revision:"e8c97968cae19a0ed3b64c1303a27a90"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
//# sourceMappingURL=sw.js.map
diff --git a/nvsim/sw.js.map b/nvsim/sw.js.map
index 04baaf87..af3c4204 100644
--- a/nvsim/sw.js.map
+++ b/nvsim/sw.js.map
@@ -1 +1 @@
-{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/98a82f991424f07f8b8237a7197af5f2/sw.js"],"sourcesContent":["import {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"4bcaa063d693b37532f242f566232490\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"89c26907fa424b69e8502586989f4bee\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"a617e7e24b2d5e976ce7e8d4f473104d\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ff4ecdcc8ace84fd24c4ad396809bd88\"\n },\n {\n \"url\": \"assets/worker-C19MRcXs.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/signals-SG45zFCj.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/lit-BS7WqYd5.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-meW-_lqo.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CyUCBwRA.css\",\n \"revision\": null\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ff4ecdcc8ace84fd24c4ad396809bd88\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"a617e7e24b2d5e976ce7e8d4f473104d\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"e8c97968cae19a0ed3b64c1303a27a90\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox","registerRoute","workbox_routing_NavigationRoute","NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,6BACPC,SAAY,MAEd,CACED,IAAO,yBACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAE,GACLC,EAAAA,wBAC6BC,EAAAC,cAAC,IAAIC,EAA+BC,gBAACC,0BAA2C"}
\ No newline at end of file
+{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/969fa6b57e97cb6342d7d6f135306c48/sw.js"],"sourcesContent":["import {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"4bcaa063d693b37532f242f566232490\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"a81e9aaaffb4924e759f42842815b902\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"a617e7e24b2d5e976ce7e8d4f473104d\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ff4ecdcc8ace84fd24c4ad396809bd88\"\n },\n {\n \"url\": \"assets/worker-C19MRcXs.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/signals-SG45zFCj.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/lit-BS7WqYd5.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CyUCBwRA.css\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CjC_xGBQ.js\",\n \"revision\": null\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ff4ecdcc8ace84fd24c4ad396809bd88\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"a617e7e24b2d5e976ce7e8d4f473104d\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"e8c97968cae19a0ed3b64c1303a27a90\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox","registerRoute","workbox_routing_NavigationRoute","NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,6BACPC,SAAY,MAEd,CACED,IAAO,yBACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAE,GACLC,EAAAA,wBAC6BC,EAAAC,cAAC,IAAIC,EAA+BC,gBAACC,0BAA2C"}
\ No newline at end of file