From b861ff344134a3b6f524ca2f1e95a9605ecc82d7 Mon Sep 17 00:00:00 2001 From: ruv Date: Sun, 26 Apr 2026 21:20:55 -0400 Subject: [PATCH] deploy(nvsim): live Ghost Murmur WASM demo + ADR-093 gap analysis Adds 'Try it yourself' interactive section to the Ghost Murmur view: distance + heart-moment sliders that drive nvsim::Pipeline live via the new runTransient WASM export. Per-tier detectability bars compare predicted |B| vs each transport's noise floor (NV-ensemble lab, COTS DNV-B1, SQUID, 60 GHz mmWave, WiFi CSI). Witness for the transient run is shown alongside the canonical reference witness. Powered by ADR-093 gap analysis. Live at https://ruvnet.github.io/RuView/nvsim/ --- nvsim/assets/index-9VRqUHc5.js | 1927 +++++++++++++++++++++++++++ nvsim/assets/index-9VRqUHc5.js.map | 1 + nvsim/assets/worker-C19MRcXs.js | 2 + nvsim/assets/worker-C19MRcXs.js.map | 1 + nvsim/index.html | 2 +- nvsim/nvsim-pkg/nvsim.d.ts | 21 + nvsim/nvsim-pkg/nvsim.js | 68 + nvsim/nvsim-pkg/nvsim_bg.wasm | Bin 165315 -> 168015 bytes nvsim/nvsim-pkg/nvsim_bg.wasm.d.ts | 1 + nvsim/sw.js | 2 +- nvsim/sw.js.map | 2 +- 11 files changed, 2024 insertions(+), 3 deletions(-) create mode 100644 nvsim/assets/index-9VRqUHc5.js create mode 100644 nvsim/assets/index-9VRqUHc5.js.map create mode 100644 nvsim/assets/worker-C19MRcXs.js create mode 100644 nvsim/assets/worker-C19MRcXs.js.map diff --git a/nvsim/assets/index-9VRqUHc5.js b/nvsim/assets/index-9VRqUHc5.js new file mode 100644 index 00000000..ff482ca1 --- /dev/null +++ b/nvsim/assets/index-9VRqUHc5.js @@ -0,0 +1,1927 @@ +import{f as Ye,u as Qe,i as b,a as h,b as d,w as K}from"./lit-BS7WqYd5.js";import{y as c,g as Je,j as y}from"./signals-SG45zFCj.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))r(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const n of i.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&r(n)}).observe(document,{childList:!0,subtree:!0});function s(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerPolicy&&(i.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?i.credentials="include":a.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(a){if(a.ep)return;a.ep=!0;const i=s(a);fetch(a.href,i)}})();/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const f=e=>(t,s)=>{s!==void 0?s.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const Ze={attribute:!0,type:String,converter:Qe,reflect:!1,hasChanged:Ye},et=(e=Ze,t,s)=>{const{kind:r,metadata:a}=s;let i=globalThis.litPropertyMetadata.get(a);if(i===void 0&&globalThis.litPropertyMetadata.set(a,i=new Map),r==="setter"&&((e=Object.create(e)).wrapped=!0),i.set(s.name,e),r==="accessor"){const{name:n}=s;return{set(o){const p=t.get.call(this);t.set.call(this,o),this.requestUpdate(n,p,e,!0,o)},init(o){return o!==void 0&&this.C(n,void 0,e,o),o}}}if(r==="setter"){const{name:n}=s;return function(o){const p=this[n];t.call(this,o),this.requestUpdate(n,p,e,!0,o)}}throw Error("Unsupported decorator location: "+r)};function ze(e){return(t,s)=>typeof s=="object"?et(e,t,s):((r,a,i)=>{const n=a.hasOwnProperty(i);return a.constructor.createProperty(i,r),n?Object.getOwnPropertyDescriptor(a,i):void 0})(e,t,s)}/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */function u(e){return ze({...e,state:!0,attribute:!1})}/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const tt=(e,t,s)=>(s.configurable=!0,s.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,s),s);/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */function He(e,t){return(s,r,a)=>{const i=n=>n.renderRoot?.querySelector(e)??null;return tt(s,r,{get(){return i(this)}})}}var at=Object.defineProperty,st=Object.getOwnPropertyDescriptor,Le=(e,t,s,r)=>{for(var a=r>1?void 0:r?st(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&at(t,s,a),a};let ce=class extends h{constructor(){super(...arguments),this.view="scene"}navigate(e){this.dispatchEvent(new CustomEvent("navigate",{detail:e}))}render(){return d` + + + + + + +
+ + `}};ce.styles=b` + :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; } + `;Le([ze()],ce.prototype,"view",2);ce=Le([f("nv-rail")],ce);const C=c("wasm"),ke=c("");c(!1);c(null);const v=c(!1);c(!0);c(1);const rt=c(0),_e=c(0n),X=c(0xCAFEBABEn),se=c(1e4),re=c(1e3),ie=c(1),ne=c(!0),m=c("dark"),k=c("default"),_=c(!1),oe=c(!0),pe=c([0,0,0]),O=c(0),F=c(0),$=c(0),z=c(""),x=c("idle"),I=c(""),Me=c(null),ue=c([]),ve=c([]),ge=c([]),me=c([]),De=c("rebar-walkby-01"),it=c(""),q=c(!1),$e=c("all"),Ee=Je(()=>C.value==="wasm"?"wasm":"ws");let Be=null;function nt(e){Be=e}function M(){return Be}const P=c([]),ot=200;function l(e,t){if(q.value)return;const s=P.value.slice();for(s.push({ts:Date.now(),level:e,msg:t});s.length>ot;)s.shift();P.value=s}function lt(e){const s=ue.value.slice();s.push(e[0]),s.length>200&&s.shift();const r=ve.value.slice();r.push(e[1]),r.length>200&&r.shift();const a=ge.value.slice();a.push(e[2]),a.length>200&&a.shift(),ue.value=s,ve.value=r,ge.value=a}function dt(e){const s=me.value.slice();for(s.push(Math.max(0,Math.min(1,e)));s.length>48;)s.shift();me.value=s}var ct=Object.getOwnPropertyDescriptor,pt=(e,t,s,r)=>{for(var a=r>1?void 0:r?ct(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=n(a)||a);return a};let Ce=class extends h{connectedCallback(){super.connectedCallback(),y(()=>{$.value,Ee.value,X.value,m.value,De.value,v.value,this.requestUpdate()})}async toggleRun(){const e=M();e&&(v.value?(await e.pause(),v.value=!1):(await e.run(),v.value=!0))}async reset(){const e=M();e&&await e.reset()}toggleTheme(){m.value=m.value==="dark"?"light":"dark"}render(){const e=X.value.toString(16).toUpperCase().padStart(8,"0");return d` +
+ RuView/ + nvsim/ + ${De.value} +
+
+ + + ${$.value>0?($.value/1e3).toFixed(2)+" kHz":"idle"} + + ${Ee.value} + seed: 0x${e} + + + + `}};Ce.styles=b` + :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); } + .pill.seed b { color: var(--accent); font-weight: 600; } + 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; } + `;Ce=pt([f("nv-topbar")],Ce);var ut=Object.getOwnPropertyDescriptor,vt=(e,t,s,r)=>{for(var a=r>1?void 0:r?ut(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=n(a)||a);return a};let Pe=class extends h{connectedCallback(){super.connectedCallback(),y(()=>{se.value,re.value,ie.value,ne.value,v.value,this.requestUpdate()})}render(){return d` +
+
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
+
V1 mm³
+
N1e12 NV
+
C0.030
+
T₂*200 ns
+
δB1.18 pT/√Hz
+
+ +
+
Tunables
+
+
Sample rate${(se.value/1e3).toFixed(1)} kHz
+ se.value=+e.target.value} /> +
+
+
Lockin f_mod${(re.value/1e3).toFixed(3)} kHz
+ re.value=+e.target.value} /> +
+
+
Integration t${ie.value.toFixed(1)} ms
+ ie.value=+e.target.value} /> +
+
+
Shot noise${ne.value?"ON":"OFF"}
+ ne.value=e.target.value==="1"} /> +
+
+ +
+
Pipeline
+
+ scene + + B-S + + prop + + NV + + ADC + + frame +
+
+ `}};Pe.styles=b` + :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; } + `;Pe=vt([f("nv-sidebar")],Pe);var gt=Object.defineProperty,mt=Object.getOwnPropertyDescriptor,ye=(e,t,s,r)=>{for(var a=r>1?void 0:r?mt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&>(t,s,a),a};let H=class extends h{constructor(){super(...arguments),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 s=this.items.find(i=>i.id===e);if(!s)return;const r=this.renderRoot.querySelector("svg");if(!r)return;const a=this.toSvg(t,r);this.dragOffset={dx:a.x-s.x,dy:a.y-s.y}},this.onPointerMove=e=>{if(!this.dragging)return;const t=this.renderRoot.querySelector("svg");if(!t)return;const s=this.toSvg(e,t);this.items=this.items.map(r=>r.id===this.dragging?{...r,x:s.x-this.dragOffset.dx,y:s.y-this.dragOffset.dy}:r)},this.onPointerUp=()=>{this.dragging=null}}connectedCallback(){super.connectedCallback(),y(()=>{pe.value,O.value,$.value,F.value,_.value,this.requestUpdate()}),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp)}toSvg(e,t){const s=t.getBoundingClientRect(),r=(e.clientX-s.left)/s.width*1e3,a=(e.clientY-s.top)/s.height*600;return{x:r,y:a}}render(){const e=pe.value,t=[e[0]*1e9,e[1]*1e9,e[2]*1e9],s=O.value*1e9,r=_.value?"":"anim";return d` +
+ + + + + + + + + + + ${this.items.map(a=>K` + + `)} + + + ${this.items.map(a=>K` + this.onDown(a.id,i)}> + + + ${a.name} + + `)} + + + + + + + + + + sensor · 〈111〉 NV + + + B_in: [${t[0].toFixed(2)}, ${t[1].toFixed(2)}, ${t[2].toFixed(2)}] nT + + + + +
+
+
|B|
+
${s.toFixed(3)} nT
+
+
+
FPS
+
${$.value>0?Math.round($.value):"—"}
+
+
+
SNR
+
${F.value>0?F.value.toFixed(1):"—"}
+
+
+ `}};H.styles=b` + :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; + } + `;ye([u()],H.prototype,"items",2);ye([u()],H.prototype,"dragging",2);ye([u()],H.prototype,"selected",2);H=ye([f("nv-scene")],H);var bt=Object.defineProperty,ht=Object.getOwnPropertyDescriptor,Te=(e,t,s,r)=>{for(var a=r>1?void 0:r?ht(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&bt(t,s,a),a};let J=class extends h{constructor(){super(...arguments),this.tab="signal",this.pinTab=null}connectedCallback(){super.connectedCallback(),y(()=>{ue.value,ve.value,ge.value,me.value,Me.value,z.value,x.value,pe.value,O.value,this.requestUpdate()})}willUpdate(e){e.has("pinTab")&&this.pinTab&&this.tab!==this.pinTab&&(this.tab=this.pinTab)}async verify(){const e=M();if(e){x.value="pending",l("info","verifying witness over 256 frames…");try{const t=I.value,s=new Uint8Array(32);for(let a=0;a<32;a++)s[a]=parseInt(t.slice(a*2,a*2+2),16);const r=await e.verifyWitness(s);if(r.ok)x.value="ok",z.value=t,l("ok",`witness ${t.slice(0,16)}… matches · determinism gate ✓`);else{x.value="fail";const a=Array.from(r.actual).map(i=>i.toString(16).padStart(2,"0")).join("");z.value=a,l("err",`WITNESS MISMATCH actual=${a.slice(0,16)}…`)}}catch(t){x.value="fail",l("err",`verify failed: ${t.message}`)}}}renderSignalTab(){const i=n=>{let o="";return n.forEach((p,g)=>{const W=g/Math.max(1,199)*320,S=65-p*22;o+=(g===0?"M":"L")+` ${W.toFixed(1)} ${S.toFixed(1)} `}),o};return d` +
+
+ B-vector trace + 3-axis · nT +
+ + + ${K``} + ${K``} + ${K``} + +
+ +
+
+ Frame stream + live +
+
+ ${me.value.map(n=>d`
`)} +
+
+ `}renderFrameTab(){const e=Me.value,t=e?.raw;let s="";return t&&(s=Array.from(t).map(a=>a.toString(16).padStart(2,"0")).slice(0,60).join(" ")),d` +
+
+ MagFrame v1 fields + 60 B +
+ + + + + + + + + + + +
magic${e?"0x"+e.magic.toString(16).toUpperCase():"—"}
version${e?.version??"—"}
flags0x${(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 +
+
${s||"—"}
+
+ `}renderWitnessTab(){const e=x.value,t=e==="ok"?"ok":e==="fail"?"fail":"",s=e==="pending"?"Verifying…":e==="ok"?"✓ Witness verified · determinism gate":e==="fail"?"✗ Witness mismatch · audit required":"Verify witness";return d` +
+
+ Expected (Proof::EXPECTED_WITNESS_HEX) + SHA-256 +
+
${I.value||"(loading…)"}
+
+
+
+ Actual (last verify) + SHA-256 +
+
${z.value||"(not verified yet)"}
+ +
+ `}render(){return d` +
+ + + +
+
+ ${this.tab==="signal"?this.renderSignalTab():this.tab==="frame"?this.renderFrameTab():this.renderWitnessTab()} +
+ `}};J.styles=b` + :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); } + `;Te([u()],J.prototype,"tab",2);Te([ze({attribute:!1})],J.prototype,"pinTab",2);J=Te([f("nv-inspector")],J);var ft=Object.defineProperty,xt=Object.getOwnPropertyDescriptor,Ne=(e,t,s,r)=>{for(var a=r>1?void 0:r?xt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&ft(t,s,a),a};let be=class extends h{constructor(){super(...arguments),this.history=[],this.hIdx=-1,this.onKey=e=>{e.key==="Enter"?(this.exec(this.inputEl.value),this.inputEl.value=""):e.key==="ArrowUp"?this.history.length&&(this.hIdx=Math.max(0,this.hIdx-1),this.inputEl.value=this.history[this.hIdx]??"",e.preventDefault()):e.key==="ArrowDown"&&this.history.length&&(this.hIdx=Math.min(this.history.length,this.hIdx+1),this.inputEl.value=this.history[this.hIdx]??"",e.preventDefault())}}connectedCallback(){super.connectedCallback(),y(()=>{P.value,$e.value,q.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 P.value)e[t.level]=(e[t.level]??0)+1;return e.all=P.value.length,e}async exec(e){if(e=e.trim(),!e)return;l("info",`nvsim> ${e}`),this.history.push(e),this.hIdx=this.history.length;const[t,...s]=e.split(/\s+/),r=s.join(" "),a=M();switch(t){case"help":l("info","commands: help · scene.list · sensor.config · run · pause · seed · proof.verify · clear · theme · status");break;case"scene.list":l("info","scene rebar-walkby-01:"),l("info"," rebar.steel.coil @ [+2.7, 0.0, +0.3] m χ=5000"),l("info"," dipole.heart_proxy @ [-1.4, +0.2, +0.4] m m=1.0e-6 A·m²"),l("info"," loop.mains_60Hz @ [-1.6, -0.4, 0.0] m I=2 A"),l("info"," eddy.door_steel @ [+0.0, +1.8, +0.4] m σ=1e6 S/m");break;case"sensor.config":l("info","NvSensor::cots_defaults() {"),l("info"," pos=[0,0,0], V=1mm³, N=1e12, C=0.03, T2*=200ns"),l("info"," D=2.870 GHz, γe=28 GHz/T, Γ=1.0 MHz, axes=4×〈111〉"),l("info"," δB ≈ 1.18 pT/√Hz (Barry 2020 §III.A) }");break;case"run":a&&(await a.run(),v.value=!0,l("ok","pipeline RUN"));break;case"pause":a&&(await a.pause(),v.value=!1,l("warn","pipeline PAUSED"));break;case"reset":a&&(await a.reset(),l("info","pipeline reset · t=0"));break;case"seed":{if(!r){l("info",`current seed = 0x${X.value.toString(16).toUpperCase()}`);break}const i=BigInt(r.startsWith("0x")?r:"0x"+r);X.value=i,a&&await a.setSeed(i),l("ok",`seed → 0x${i.toString(16).toUpperCase()}`);break}case"proof.verify":{if(!a)break;l("dbg","computing SHA-256 over 256 frames…");try{const i=I.value,n=new Uint8Array(32);for(let p=0;p<32;p++)n[p]=parseInt(i.slice(p*2,p*2+2),16);(await a.verifyWitness(n)).ok?(x.value="ok",z.value=i,l("ok",`witness ${i.slice(0,16)}… matches · determinism gate ✓`)):(x.value="fail",l("err","WITNESS MISMATCH"))}catch(i){l("err",`verify failed: ${i.message}`)}break}case"clear":P.value=[];break;case"theme":{const i=(r||"").toLowerCase();i==="light"||i==="dark"?(m.value=i,l("ok",`theme → ${i}`)):l("info","theme [light|dark]");break}case"status":l("info",`running=${v.value} seed=0x${X.value.toString(16).toUpperCase()} verified=${x.value}`);break;default:l("err",`unknown command: ${t} · try help`)}}render(){const e=this.counts(),t=$e.value,s=P.value.filter(r=>t==="all"||r.level===t);return d` +
+ ${["all","info","warn","err","dbg"].map(r=>d` + + `)} + +
+ + +
+
+
+ ${s.map(r=>{const a=new Date(r.ts),i=`${String(a.getSeconds()).padStart(2,"0")}.${String(a.getMilliseconds()).padStart(3,"0")}`;return d`
+
${i}
+
${r.level}
+
+
`})} +
+
+ nvsim> + +
+ `}};be.styles=b` + :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); } + `;Ne([He("#console-input")],be.prototype,"inputEl",2);be=Ne([f("nv-console")],be);const G=[{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"]}],j={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 yt(){return G.map(e=>({id:e.id,active:e.active===!0,eventCount:0}))}function wt(e,t){if(!e)return 1;const s=e.toLowerCase();let r=0;return t.id.toLowerCase().includes(s)&&(r+=3),t.name.toLowerCase().includes(s)&&(r+=3),t.summary.toLowerCase().includes(s)&&(r+=1),t.tags?.some(a=>a.toLowerCase().includes(s))&&(r+=2),t.category===s&&(r+=5),r}const kt="nvsim",$t=1,L="kv";let le=null;function We(){return le||(le=new Promise((e,t)=>{const s=indexedDB.open(kt,$t);s.onupgradeneeded=()=>{const r=s.result;r.objectStoreNames.contains(L)||r.createObjectStore(L)},s.onsuccess=()=>e(s.result),s.onerror=()=>t(s.error)}),le)}async function Y(e){const t=await We();return await new Promise((s,r)=>{const i=t.transaction(L,"readonly").objectStore(L).get(e);i.onsuccess=()=>s(i.result),i.onerror=()=>r(i.error)})}async function Q(e,t){const s=await We();return await new Promise((r,a)=>{const i=s.transaction(L,"readwrite");i.objectStore(L).put(t,e),i.oncomplete=()=>r(),i.onerror=()=>a(i.error)})}var St=Object.defineProperty,_t=Object.getOwnPropertyDescriptor,je=(e,t,s,r)=>{for(var a=r>1?void 0:r?_t(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&St(t,s,a),a};const R=c(yt()),V=c(""),A=c("all"),w=c("all");(async()=>{const e=await Y("app-activations");e&&(R.value=e)})();y(()=>{const e=R.value;e.length>0&&Q("app-activations",e)});let he=class extends h{constructor(){super(...arguments),this.renderTick=0}connectedCallback(){super.connectedCallback(),y(()=>{R.value,V.value,A.value,w.value,this.renderTick++})}isActive(e){return R.value.find(t=>t.id===e)?.active===!0}toggle(e){const t=R.value.map(s=>s.id===e.id?{...s,active:!s.active,lastActivatedAt:Date.now()}:s);R.value=t,l(this.isActive(e.id)?"ok":"info",`app ${e.id} deactivated`)}filtered(){let e=G;return A.value!=="all"&&(e=e.filter(t=>t.category===A.value)),w.value!=="all"&&(e=e.filter(t=>t.status===w.value)),V.value.trim()&&(e=e.map(t=>({a:t,s:wt(V.value,t)})).filter(t=>t.s>0).sort((t,s)=>s.s-t.s).map(t=>t.a)),e}categoryCounts(){const e={all:G.length};for(const t of Object.keys(j))e[t]=0;for(const t of G)e[t.category]=(e[t.category]??0)+1;return e}render(){const e=this.filtered(),t=this.categoryCounts(),s=R.value.filter(r=>r.active).length;return d` +
+
+ App Store + ${G.length} edge apps · ${s} active +
+ {V.value=r.target.value}} /> +
+ +
+ A.value="all"}> + All${t.all} + + ${Object.keys(j).map(r=>d` + A.value=r}> + + ${j[r].label} + ${t[r]??0} + + `)} + + w.value="all"}>any + w.value="available"}>available + w.value="beta"}>beta + w.value="research"}>research +
+ + ${e.length===0?d`
No apps match the current filters.
`:d`
${e.map(r=>this.card(r))}
`} + `}card(e){const t=this.isActive(e.id),s=j[e.category];return d` +
+
+ + ${e.name} +
+
${e.summary}
+
+ ${s.label} + ${e.status} + ${e.budget?d`budget ${e.budget}`:""} + ${e.adr?d`${e.adr}`:""} + ${e.events?.length?d`events ${e.events.join("·")}`:""} +
+
+ ${e.crate} + this.toggle(e)}> +
+
+ `}};he.styles=b` + :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; + } + `;je([u()],he.prototype,"renderTick",2);he=je([f("nv-app-store")],he);var Mt=Object.defineProperty,Ct=Object.getOwnPropertyDescriptor,we=(e,t,s,r)=>{for(var a=r>1?void 0:r?Ct(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Mt(t,s,a),a};let B=class extends h{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 d`${this.icon}${this.msg}`}};B.styles=b` + :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); } + `;we([u()],B.prototype,"visible",2);we([u()],B.prototype,"msg",2);we([u()],B.prototype,"icon",2);B=we([f("nv-toast")],B);function U(e,t="✓"){window.dispatchEvent(new CustomEvent("nv-toast",{detail:{msg:e,icon:t}}))}var Pt=Object.defineProperty,zt=Object.getOwnPropertyDescriptor,te=(e,t,s,r)=>{for(var a=r>1?void 0:r?zt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Pt(t,s,a),a};let D=class extends h{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","")},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)}close(){this.open=!1,this.removeAttribute("open")}clickBtn(e){e.onClick?.(),this.close()}render(){return d` + + `}};D.styles=b` + :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); + } + `;te([u()],D.prototype,"open",2);te([u()],D.prototype,"mTitle",2);te([u()],D.prototype,"mBody",2);te([u()],D.prototype,"buttons",2);D=te([f("nv-modal")],D);function Se(e){window.dispatchEvent(new CustomEvent("nv-modal",{detail:e}))}var Tt=Object.defineProperty,At=Object.getOwnPropertyDescriptor,ae=(e,t,s,r)=>{for(var a=r>1?void 0:r?At(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Tt(t,s,a),a};let E=class extends h{constructor(){super(...arguments),this.open=!1,this.filter="",this.idx=0,this.cmds=[{ico:"▶",label:"Run pipeline",kbd:"Space",run:async()=>{await M()?.run(),v.value=!0,U("Pipeline running","▶")}},{ico:"❚",label:"Pause pipeline",run:async()=>{await M()?.pause(),v.value=!1,U("Paused","❚❚")}},{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 M()?.reset(),l("warn","pipeline reset · t=0"),U("Pipeline reset","⟳")}}]})},{ico:"✓",label:"Verify witness",run:async()=>{const e=M();if(!e)return;x.value="pending";const t=I.value,s=new Uint8Array(32);for(let a=0;a<32;a++)s[a]=parseInt(t.slice(a*2,a*2+2),16);(await e.verifyWitness(s)).ok?(x.value="ok",z.value=t,U("Witness verified","✓")):(x.value="fail",U("Witness mismatch!","✗"))}},{ico:"☼",label:"Toggle theme",kbd:"⌘/",run:()=>{m.value=m.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 d` +
+
+ {this.filter=t.target.value,this.idx=0}} /> +
+
+ ${e.map((t,s)=>d` +
{this.idx=s,this.runIdx()}}> + ${t.ico} + ${t.label} + ${t.kbd?d`${t.kbd}`:""} +
+ `)} +
+
+ `}};E.styles=b` + :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; + } + `;ae([u()],E.prototype,"open",2);ae([u()],E.prototype,"filter",2);ae([u()],E.prototype,"idx",2);ae([He("#palette-input")],E.prototype,"inputEl",2);E=ae([f("nv-palette")],E);var Rt=Object.defineProperty,Dt=Object.getOwnPropertyDescriptor,Ae=(e,t,s,r)=>{for(var a=r>1?void 0:r?Dt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Rt(t,s,a),a};let Z=class extends h{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),y(()=>{$.value,_e.value,O.value,F.value,rt.value,this.requestUpdate()}),this.tick()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.onKey),cancelAnimationFrame(this.rafId)}render(){return d` +
nvsim · debug{this.open=!1,this.removeAttribute("open")}}>✕
+
render fps${this.renderFps.toFixed(1)}
+
sim fps${$.value>0?Math.round($.value):"—"}
+
frames${_e.value.toString()}
+
|B|${(O.value*1e9).toFixed(3)} nT
+
SNR${F.value>0?F.value.toFixed(1):"—"}
+
DOM${document.querySelectorAll("*").length}
+ `}};Z.styles=b` + :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); } + `;Ae([u()],Z.prototype,"open",2);Ae([u()],Z.prototype,"renderFps",2);Z=Ae([f("nv-debug-hud")],Z);var Et=Object.defineProperty,Ft=Object.getOwnPropertyDescriptor,Ve=(e,t,s,r)=>{for(var a=r>1?void 0:r?Ft(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Et(t,s,a),a};let fe=class extends h{constructor(){super(...arguments),this.open=!1}connectedCallback(){super.connectedCallback(),y(()=>{m.value,k.value,_.value,oe.value,C.value,ke.value,this.requestUpdate()}),window.addEventListener("open-settings",()=>{this.open=!0,this.setAttribute("open","")})}close(){this.open=!1,this.removeAttribute("open")}render(){return d` +
this.close()}>
+
+
Settings
+ +
+
+
+

Appearance

+
+
Theme
+
+ + +
+
+
+
+
Density
+
Affects panel padding and font scale.
+
+
+ + + +
+
+
+
+
Reduce motion
+
Disable rotating crystal & field-line animation.
+
+ _.value=!_.value}> +
+
+ +
+

Pipeline

+
+
Auto-rerun on edit
+
Restart pipeline when scene/config changes.
+ oe.value=!oe.value}> +
+
+ +
+

Transport

+
+
Mode
+
+ + +
+
+ ${C.value==="ws"?d` +
+
WS URL
+ ke.value=e.target.value} /> +
`:""} +
+
+ `}};fe.styles=b` + :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; + } + `;Ve([u()],fe.prototype,"open",2);fe=Ve([f("nv-settings-drawer")],fe);var Ot=Object.defineProperty,It=Object.getOwnPropertyDescriptor,Re=(e,t,s,r)=>{for(var a=r>1?void 0:r?It(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Ot(t,s,a),a};const de=[{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 ee=class extends h{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 Y("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 Q("onboarding-seen",!0)}next(){this.step0&&this.step--}render(){const e=de[this.step];return d` + + `}};ee.styles=b` + :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); + } + `;Re([u()],ee.prototype,"open",2);Re([u()],ee.prototype,"step",2);ee=Re([f("nv-onboarding")],ee);var Ht=Object.defineProperty,Lt=Object.getOwnPropertyDescriptor,N=(e,t,s,r)=>{for(var a=r>1?void 0:r?Lt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Ht(t,s,a),a};const Bt=[{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 T=class extends h{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=M();if(!e){this.err="WASM client not ready";return}this.err=null,this.running=!0,this.requestUpdate();try{const t=this.distanceM,s=Math.pow(10,this.momentLog10),r={dipoles:[{position:[0,0,t],moment:[0,0,s]}],loops:[],ferrous:[],eddy:[],sensors:[[0,0,0]],ambient_field:[0,0,0]},a={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,a,42n,64),l("ok",`ghost-demo · r=${t.toFixed(3)} m · |B| recovered = ${(this.result.bMagT*1e12).toExponential(2)} pT`)}catch(t){this.err=t.message,l("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),s=this.result?.bMagT??0,r=(this.result?.noiseFloorPtSqrtHz??0)*1e-12,a=Bt.map(o=>{let p="bad",g="below floor";if(o.id==="mmw")this.distanceM<=5?(p="ok",g="µ-Doppler @ chest"):this.distanceM<=15?(p="warn",g="edge of range"):(p="bad",g="out of range");else if(o.id==="csi")this.distanceM<=30?(p=this.distanceM<=10?"ok":"warn",g="presence/breathing"):(p="bad",g="out of range");else if(o.floorT>0){const S=t/o.floorT;S>100?(p="ok",g=`${S.toExponential(1)}× floor`):S>1?(p="warn",g=`${S.toFixed(1)}× floor`):(p="bad",g=`${(1/S).toExponential(1)}× too weak`)}const W=o.floorT>0?Math.max(2,Math.min(100,100+12*Math.log10(t/o.floorT))):o.id==="mmw"?Math.max(2,100-this.distanceM*7):Math.max(2,100-this.distanceM*2);return d` +
+
+
+ ${o.label} + ${g} +
+
+ `}),i=t>1e-12?"ok":t>1e-15?"warn":"bad",n=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 d` +
+

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,+o.target.value)}} /> +
+ 10 cm → 100 km log scale +
+
+
+
+ Heart dipole moment + ${e.toExponential(2)} A·m² +
+ {this.momentLog10=+o.target.value}} /> +
+ published cardiac MCG ≈ 5×10⁻⁹ A·m² +
+
+ + ${this.err?d`
Error: ${this.err}
`:""} +
+ +
+
+
+ Predicted |B| (1/r³) + ${this.formatField(t)} +
+
+ Recovered |B| (nvsim) + ${this.result?this.formatField(s):"—"} +
+
+ 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 +
+ ${a} +
+
+
+
${n}
+
+ 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 d` +

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

+
+ + + + + + + + + + + +
DistanceCardiac MCG (peak QRS)vs Earth field (~50 µT)
10 cm50 pT10⁹× weaker
1 m50 fT10¹²× weaker
10 m50 aT10¹⁵× weaker
1 km5 × 10⁻²³ T10²⁷× weaker
40 mi (65 km)~10⁻²⁸ T10³³× 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 claimRuView equivalent todayCrate / ADRHonest range
NV-diamond magnetometryDeterministic NV pipeline simulatornvsim · ADR-089Simulator only
"AI strips environmental noise"RuvSense multistatic fusion + AETHERsignal/ruvsense/ · ADR-029Mature
Heartbeat at distance60 GHz FMCW HR/BR + WiFi CSI breathingvitals · ADR-0211–5 m HR · 10–30 m presence
Long-range localisationMultistatic time-of-flight + CRLBruvector/viewpoint/Limited by node spacing
40-mile single-heartbeat detectionNot feasible at any tierPress-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 bpmHR (LOS 0–3 m)

+ ±1 br/minBR (any mode)

+ ~10 cmpose error

+ 80–150 msend-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. +

+
+ `}};T.styles=b` + :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; + } + `;N([u()],T.prototype,"distanceM",2);N([u()],T.prototype,"momentLog10",2);N([u()],T.prototype,"result",2);N([u()],T.prototype,"running",2);N([u()],T.prototype,"err",2);T=N([f("nv-ghost-murmur")],T);var Nt=Object.defineProperty,Wt=Object.getOwnPropertyDescriptor,Ue=(e,t,s,r)=>{for(var a=r>1?void 0:r?Wt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Nt(t,s,a),a};let xe=class extends h{constructor(){super(...arguments),this.view="scene"}render(){return d` +
+ this.view=e.detail}> + + +
+ ${this.view==="apps"?d``:this.view==="ghost-murmur"?d``:d``} +
+ + + +
+ + + + + + + `}};xe.styles=b` + :host { + display: block; + height: 100vh; + width: 100vw; + background: var(--bg-0); + } + .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; } + } + `;Ue([u()],xe.prototype,"view",2);xe=Ue([f("nv-app")],xe);function jt(e,t,s){const r=e.getUint32(t+0,!0),a=e.getUint16(t+4,!0),i=e.getUint16(t+6,!0),n=e.getUint16(t+8,!0),o=e.getBigUint64(t+12,!0),p=e.getFloat32(t+20,!0),g=e.getFloat32(t+24,!0),W=e.getFloat32(t+28,!0),S=e.getFloat32(t+32,!0),qe=e.getFloat32(t+36,!0),Ge=e.getFloat32(t+40,!0),Ke=e.getFloat32(t+44,!0),Xe=e.getFloat32(t+48,!0);return{magic:r,version:a,flags:i,sensorId:n,tUs:o,bPt:[p,g,W],sigmaPt:[S,qe,Ge],noiseFloorPtSqrtHz:Ke,temperatureK:Xe,raw:s.subarray(t,t+60)}}function Vt(e){const s=new DataView(e.buffer,e.byteOffset,e.byteLength),r=[];for(let a=0;a+60<=e.byteLength;a+=60)r.push(jt(s,a,e));return r}class Ut{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(s=>s({type:"log",level:"err",msg:String(t.message)})))}onMessage(t){const s=t.data;if(s.type==="frames"){const r=s.batch,a=new Uint8Array(r),n={frames:Vt(a),bytes:a};this.frameSubs.forEach(p=>p(n));const o=s.fps;o>0&&this.eventSubs.forEach(p=>p({type:"fps",value:o}));return}if(s.type==="state"){this.eventSubs.forEach(r=>r({type:"state",running:!!s.running,t:0,framesEmitted:Number(s.framesEmitted??0)}));return}if(s.type!=="ready"){if(s.type==="err"&&s.id==null){this.eventSubs.forEach(r=>r({type:"log",level:"err",msg:String(s.msg)}));return}if(typeof s.id=="number"&&this.pending.has(s.id)){const r=this.pending.get(s.id);this.pending.delete(s.id),s.type==="err"?r.reject(new Error(String(s.msg))):r.resolve(s)}}}rpc(t,s=[]){const r=this.nextId++;return new Promise((a,i)=>{this.pending.set(r,{resolve:a,reject:i}),this.worker.postMessage({...t,id:r},s)})}async boot(){if(this.bootInfo)return this.bootInfo;const s=await this.rpc({type:"boot",base:"/RuView/nvsim/"});return this.bootInfo={buildVersion:s.buildVersion,frameMagic:s.frameMagic,frameBytes:s.frameBytes,expectedWitnessHex:s.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,s){await this.rpc({type:"step"})}onFrames(t){this.frameSubs.add(t)}onEvent(t){this.eventSubs.add(t)}async generateWitness(t){const s=await this.rpc({type:"witnessGenerate",samples:t});return new Uint8Array(s.witness)}async verifyWitness(t){const s=t.slice().buffer,r=await this.rpc({type:"witnessVerify",samples:256,expected:s},[s]);return r.ok?{ok:!0}:{ok:!1,actual:new Uint8Array(r.actual)}}async runTransient(t,s,r,a){const i=await this.rpc({type:"runTransient",scene:JSON.stringify(t),config:JSON.stringify(s),seed:Number(r&0xFFFFFFFFn),samples:a});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),s=Array.from(t).map(i=>i.toString(16).padStart(2,"0")).join(""),r=this.bootInfo??await this.boot(),a=JSON.stringify({kind:"nvsim-proof-bundle",version:r.buildVersion,seed:"0x0000002A",nSamples:256,witness:s,expected:r.expectedWitnessHex,ok:s===r.expectedWitnessHex,ts:new Date().toISOString()},null,2);return new Blob([a],{type:"application/json"})}async buildId(){return(await this.rpc({type:"buildId"})).buildId}async close(){this.worker.terminate()}}function Fe(e){document.documentElement.setAttribute("data-theme",e)}function Oe(e){document.body.classList.remove("density-comfy","density-default","density-compact"),document.body.classList.add(`density-${e}`)}function Ie(e){document.body.classList.toggle("reduce-motion",e)}(async()=>{const e=await Y("theme")??"dark",t=await Y("density")??"default",s=await Y("motionReduced")??!1;m.value=e,Fe(e),k.value=t,Oe(t),_.value=s,Ie(s),y(()=>{Fe(m.value),Q("theme",m.value)}),y(()=>{Oe(k.value),Q("density",k.value)}),y(()=>{Ie(_.value),Q("motionReduced",_.value)});const r=new Ut;nt(r),l("info","nvsim — booting WASM runtime"),r.onEvent(a=>{a.type==="log"&&l(a.level,a.msg),a.type==="fps"&&($.value=a.value),a.type==="state"&&(_e.value=BigInt(a.framesEmitted))}),r.onFrames(a=>{if(a.frames.length===0)return;const i=a.frames[a.frames.length-1];Me.value=i;const n=i.bPt[0]*1e-12,o=i.bPt[1]*1e-12,p=i.bPt[2]*1e-12;pe.value=[n,o,p],O.value=Math.sqrt(n*n+o*o+p*p),lt([n*1e9,o*1e9,p*1e9]);const g=Math.min(1,Math.abs(p*1e9)/5+.3);dt(g)});try{const a=await r.boot();I.value=a.expectedWitnessHex,l("ok",`WASM module ready · nvsim@${a.buildVersion} · magic=0x${a.frameMagic.toString(16).toUpperCase()}`),l("info",`expected witness · ${a.expectedWitnessHex.slice(0,16)}…`),it.value="(reference scene)",C.value="wasm"}catch(a){l("err",`boot failed: ${a.message}`)}try{const a=I.value;if(a){const i=new Uint8Array(32);for(let o=0;o<32;o++)i[o]=parseInt(a.slice(o*2,o*2+2),16);const n=await r.verifyWitness(i);if(n.ok)z.value=a,l("ok","witness verified · determinism gate ✓");else{const o=Array.from(n.actual).map(p=>p.toString(16).padStart(2,"0")).join("");z.value=o,l("err",`WITNESS MISMATCH · expected ${a.slice(0,16)}… got ${o.slice(0,16)}…`)}}}catch(a){l("warn",`witness verify skipped: ${a.message}`)}})(); +//# sourceMappingURL=index-9VRqUHc5.js.map diff --git a/nvsim/assets/index-9VRqUHc5.js.map b/nvsim/assets/index-9VRqUHc5.js.map new file mode 100644 index 00000000..ffbd3379 --- /dev/null +++ b/nvsim/assets/index-9VRqUHc5.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index-9VRqUHc5.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-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-toast.ts","../../src/components/nv-modal.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 \n \n \n \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\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","/* 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,\n} from '../store/appStore';\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); }\n .pill.seed b { color: var(--accent); font-weight: 600; }\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\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 ${transportLabel.value}\n seed: 0x${seedHex}\n \n \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 } from '../store/appStore';\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
V1 mm³
\n
N1e12 NV
\n
C0.030
\n
T₂*200 ns
\n
δB1.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} />\n
\n
\n
Lockin f_mod${(fmod.value / 1000).toFixed(3)} kHz
\n fmod.value = +(e.target as HTMLInputElement).value} />\n
\n
\n
Integration t${dtMs.value.toFixed(1)} ms
\n dtMs.value = +(e.target as HTMLInputElement).value} />\n
\n
\n
Shot noise${noiseEnabled.value ? 'ON' : 'OFF'}
\n noiseEnabled.value = (e.target as HTMLInputElement).value === '1'} />\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 } 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 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 `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { lastB.value; bMag.value; fps.value; snr.value; motionReduced.value; this.requestUpdate(); });\n window.addEventListener('pointermove', this.onPointerMove);\n window.addEventListener('pointerup', this.onPointerUp);\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 => { this.dragging = null; };\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 return html`\n
\n \n \n \n \n \n \n \n \n\n \n ${this.items.map((it) => svg`\n \n `)}\n\n \n ${this.items.map((it) => svg`\n this.onDown(it.id, e)}>\n \n \n ${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
|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 \n \n \n \n \n \n \n \n \n \n
magic${f ? '0x' + f.magic.toString(16).toUpperCase() : '—'}
version${f?.version ?? '—'}
flags0x${(f?.flags ?? 0).toString(16).padStart(4, '0')}
sensor_id${f?.sensorId ?? '—'}
t_us${f ? f.tUs.toString() : '—'}
b_pT[0]${f ? f.bPt[0].toFixed(1) : '—'}
b_pT[1]${f ? f.bPt[1].toFixed(1) : '—'}
b_pT[2]${f ? f.bPt[2].toFixed(1) : '—'}
noise_floor${f ? f.noiseFloorPtSqrtHz.toFixed(2) : '—'}
temp_K${f ? f.temperatureK.toFixed(1) : '—'}
\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 \n
\n `;\n }\n\n override render() {\n return html`\n
\n \n \n \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,\n} from '../store/appStore';\n\n@customElement('nv-console')\nexport class NvConsole extends LitElement {\n @query('#console-input') private inputEl!: HTMLInputElement;\n private history: string[] = [];\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 this.history.push(line); this.hIdx = this.history.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 · seed · proof.verify · 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 '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 if (this.history.length) {\n this.hIdx = Math.max(0, this.hIdx - 1);\n this.inputEl.value = this.history[this.hIdx] ?? '';\n e.preventDefault();\n }\n } else if (e.key === 'ArrowDown') {\n if (this.history.length) {\n this.hIdx = Math.min(this.history.length, this.hIdx + 1);\n this.inputEl.value = this.history[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 \n `)}\n \n
\n \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 ${app.crate}\n this.toggle(app)}>\n
\n
\n `;\n }\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","/* 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 };\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 \n
\n
\n
\n ${this.buttons.map((b) => html`\n \n `)}\n
\n
\n `;\n }\n}\n\nexport function openModal(req: ModalReq): void {\n window.dispatchEvent(new CustomEvent('nv-modal', { detail: req }));\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: '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 \n
\n
\n
\n

Appearance

\n
\n
Theme
\n
\n \n \n
\n
\n
\n
\n
Density
\n
Affects panel padding and font scale.
\n
\n
\n \n \n \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
Mode
\n
\n \n \n
\n
\n ${transport.value === 'ws' ? html`\n
\n
WS URL
\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 \n
\n
\n
\n
\n ${STEPS.map((_, i) => html`
`)}\n
\n ${this.step > 0\n ? html``\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 \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 \n \n \n \n \n \n \n \n \n
DistanceCardiac MCG (peak QRS)vs Earth field (~50 µT)
10 cm50 pT10⁹× weaker
1 m50 fT10¹²× weaker
10 m50 aT10¹⁵× weaker
1 km5 × 10⁻²³ T10²⁷× weaker
40 mi (65 km)~10⁻²⁸ T10³³× weaker
\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 \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Press claimRuView equivalent todayCrate / ADRHonest range
NV-diamond magnetometryDeterministic NV pipeline simulatornvsim · ADR-089Simulator only
\"AI strips environmental noise\"RuvSense multistatic fusion + AETHERsignal/ruvsense/ · ADR-029Mature
Heartbeat at distance60 GHz FMCW HR/BR + WiFi CSI breathingvitals · ADR-0211–5 m HR · 10–30 m presence
Long-range localisationMultistatic time-of-flight + CRLBruvector/viewpoint/Limited by node spacing
40-mile single-heartbeat detectionNot feasible at any tierPress-release physics
\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 bpmHR (LOS 0–3 m)

\n ±1 br/minBR (any mode)

\n ~10 cmpose error

\n 80–150 msend-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 .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
\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} 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 m = (await kvGet('motionReduced')) ?? false;\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 // 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","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","transportLabel","computed","_client","setClient","getClient","consoleLines","MAX_LINES","pushLog","level","msg","next","pushTrace","b","x","y","z","pushStripBar","amp","NvTopbar","effect","seedHex","NvSidebar","NvScene","id","item","svgEl","pt","it","vbX","vbY","bnT","bMagNT","animClass","svg","state","NvInspector","changed","exp","expBytes","actual","make","arr","p","f","bytes","hex","status","cls","label","NvConsole","body","l","line","cmd","args","arg","filter","visible","k","ts","tsStr","query","APPS","CATEGORIES","defaultActivations","a","fuzzyMatch","app","q","score","DB_NAME","DB_VER","STORE","dbPromise","openDb","resolve","reject","req","db","kvGet","key","kvSet","value","tx","activations","activeCat","statusFilter","saved","NvAppStore","list","counts","activeCount","active","cat","NvToast","detail","toast","icon","NvModal","openModal","NvPalette","eb","items","NvDebugHud","now","simT","NvSettingsDrawer","STEPS","NvOnboarding","_","TIERS","NvGhostMurmur","m","scene","config","abs","predicted","recovered","noiseFloor","verdictPills","detect","ratio","fillPct","overallDetect","overallText","NvApp","parseMagFrame","view","offset","raw","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","d","applyMotion","reduced","client","last"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAuJvB,CACF,EAxnBakJ,EAMJ,OAASjJ;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAA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","x_google_ignoreList":[0,1,2,3,4]} \ No newline at end of file diff --git a/nvsim/assets/worker-C19MRcXs.js b/nvsim/assets/worker-C19MRcXs.js new file mode 100644 index 00000000..5d1e3c94 --- /dev/null +++ b/nvsim/assets/worker-C19MRcXs.js @@ -0,0 +1,2 @@ +const u=self;let l,x,_,k,F,T;async function S(o){const e=new URL(o,u.location.origin).href,t=await import(new URL("nvsim-pkg/nvsim.js",e).href);await t.default(),l=t.WasmPipeline,x=t.referenceSceneJson,_=t.expectedReferenceWitnessHex,k=t.hexWitness,F=t.referenceWitness,T=t.runTransient}let c=null,b="",y="",W=BigInt(3405691582),g=!1,d=null,a=0,w=0;function f(){y||(y=x()),b||(b=JSON.stringify({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})),c?.free?.(),c=new l(y,b,Number(W&0xFFFFFFFFn))}function s(o,e=[]){u.postMessage(o,e)}function H(){if(d!==null)return;w=performance.now(),a=0;const o=()=>{if(!g||!c)return;const e=32,n=c.run(e);a+=e;const t=(performance.now()-w)/1e3,i=t>0?a/t:0;s({type:"frames",batch:n.buffer,count:e,fps:i,framesEmitted:a},[n.buffer]),d=u.setTimeout(o,16)};d=u.setTimeout(o,0)}function h(){d!==null&&(u.clearTimeout(d),d=null)}u.addEventListener("message",async o=>{const e=o.data;try{switch(e.type){case"boot":{const n=e.base??"/";await S(n),f(),s({type:"booted",id:e.id,buildVersion:l.buildVersion(),frameMagic:l.frameMagic(),frameBytes:l.frameBytes(),expectedWitnessHex:_()});break}case"setScene":{y=e.json,f(),s({type:"ack",id:e.id});break}case"setConfig":{b=e.json,f(),s({type:"ack",id:e.id});break}case"setSeed":{W=BigInt(e.seed),f(),s({type:"ack",id:e.id});break}case"reset":{h(),g=!1,f(),a=0,s({type:"ack",id:e.id}),s({type:"state",running:!1,framesEmitted:a});break}case"run":{c||f(),g=!0,H(),s({type:"ack",id:e.id}),s({type:"state",running:!0,framesEmitted:a});break}case"pause":{g=!1,h(),s({type:"ack",id:e.id}),s({type:"state",running:!1,framesEmitted:a});break}case"step":{c||f();const n=c.run(1);a+=1,s({type:"frames",batch:n.buffer,count:1,fps:0,framesEmitted:a},[n.buffer]),s({type:"ack",id:e.id});break}case"witnessGenerate":{c||f();const n=e.samples??256,t=c.runWithWitness(n),i=k(t.witness);s({type:"witness",id:e.id,witness:t.witness.buffer,hex:i,frameCount:t.frameCount},[t.witness.buffer]);break}case"witnessVerify":{const n=e.expected,t=new Uint8Array(n),i=F();let p=i.length===t.length;if(p){for(let m=0;m\n\nconst ws = self as unknown as DedicatedWorkerGlobalScope;\n\ninterface WasmPipelineApi {\n run(n: number): Uint8Array;\n runWithWitness(n: number): { frames: Uint8Array; witness: Uint8Array; frameCount: number };\n free?: () => void;\n}\ntype WasmPipelineCtor = new (sceneJson: string, configJson: string, seed: number) => WasmPipelineApi;\ntype WasmPipelineStatic = WasmPipelineCtor & {\n buildVersion(): string;\n frameMagic(): number;\n frameBytes(): number;\n};\n\ninterface TransientResult {\n bRecoveredT: Float64Array;\n bMagT: number;\n noiseFloorPtSqrtHz: number;\n sigmaPt: Float64Array;\n nFrames: number;\n witnessHex: string;\n}\n\ninterface NvsimPkg {\n default: (input?: unknown) => Promise;\n WasmPipeline: WasmPipelineStatic;\n referenceSceneJson: () => string;\n expectedReferenceWitnessHex: () => string;\n hexWitness: (b: Uint8Array) => string;\n referenceWitness: () => Uint8Array;\n runTransient: (sceneJson: string, configJson: string, seed: number, nSamples: number) => TransientResult;\n}\n\nlet _WasmPipeline!: WasmPipelineStatic;\nlet referenceSceneJson!: () => string;\nlet expectedReferenceWitnessHex!: () => string;\nlet hexWitness!: (b: Uint8Array) => string;\nlet referenceWitness!: () => Uint8Array;\nlet runTransient!: (sceneJson: string, configJson: string, seed: number, nSamples: number) => TransientResult;\n\nasync function loadPkg(base: string): Promise {\n // `base` is the dashboard's BASE_URL injected by Vite, prefixed with the\n // origin so we get an absolute URL the dynamic import can resolve. In dev\n // this is \"/\", in prod under GitHub Pages it's \"/RuView/nvsim/\".\n const absoluteBase = new URL(base, ws.location.origin).href;\n const pkgUrl = new URL('nvsim-pkg/nvsim.js', absoluteBase).href;\n const pkg = (await import(/* @vite-ignore */ pkgUrl)) as NvsimPkg;\n await pkg.default();\n _WasmPipeline = pkg.WasmPipeline;\n referenceSceneJson = pkg.referenceSceneJson;\n expectedReferenceWitnessHex = pkg.expectedReferenceWitnessHex;\n hexWitness = pkg.hexWitness;\n referenceWitness = pkg.referenceWitness;\n runTransient = pkg.runTransient;\n}\n\nlet pipeline: WasmPipelineApi | null = null;\nlet configJson = '';\nlet sceneJson = '';\nlet seed = BigInt(0xCAFEBABE);\n\nlet running = false;\nlet timer: number | null = null;\nlet framesEmitted = 0;\nlet tStart = 0;\n\nfunction ensureRebuild(): void {\n if (!sceneJson) sceneJson = referenceSceneJson();\n if (!configJson) {\n configJson = JSON.stringify({\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 }\n pipeline?.free?.();\n pipeline = new _WasmPipeline(sceneJson, configJson, Number(seed & 0xFFFFFFFFn));\n}\n\nfunction post(msg: unknown, transfer: Transferable[] = []): void {\n // postMessage Transferable overload: pass transfer list as 2nd arg\n (ws.postMessage as (msg: unknown, t: Transferable[]) => void)(msg, transfer);\n}\n\nfunction startTimer(): void {\n if (timer !== null) return;\n tStart = performance.now();\n framesEmitted = 0;\n const tick = (): void => {\n if (!running || !pipeline) return;\n // Per-tick: simulate 32 frames; push as one batch.\n const n = 32;\n const bytes = pipeline.run(n);\n framesEmitted += n;\n const elapsed = (performance.now() - tStart) / 1000;\n const fps = elapsed > 0 ? framesEmitted / elapsed : 0;\n post(\n { type: 'frames', batch: bytes.buffer, count: n, fps, framesEmitted },\n [bytes.buffer],\n );\n timer = ws.setTimeout(tick, 16);\n };\n timer = ws.setTimeout(tick, 0);\n}\n\nfunction stopTimer(): void {\n if (timer !== null) {\n ws.clearTimeout(timer);\n timer = null;\n }\n}\n\nws.addEventListener('message', async (ev: MessageEvent): Promise => {\n const m = ev.data as { type: string; id?: number; [k: string]: unknown };\n try {\n switch (m.type) {\n case 'boot': {\n const base = (m.base as string | undefined) ?? '/';\n await loadPkg(base);\n ensureRebuild();\n post({\n type: 'booted',\n id: m.id,\n buildVersion: _WasmPipeline.buildVersion(),\n frameMagic: _WasmPipeline.frameMagic(),\n frameBytes: _WasmPipeline.frameBytes(),\n expectedWitnessHex: expectedReferenceWitnessHex(),\n });\n break;\n }\n case 'setScene': {\n sceneJson = m.json as string;\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'setConfig': {\n configJson = m.json as string;\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'setSeed': {\n seed = BigInt(m.seed as string | number | bigint);\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'reset': {\n stopTimer();\n running = false;\n ensureRebuild();\n framesEmitted = 0;\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: false, framesEmitted });\n break;\n }\n case 'run': {\n if (!pipeline) ensureRebuild();\n running = true;\n startTimer();\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: true, framesEmitted });\n break;\n }\n case 'pause': {\n running = false;\n stopTimer();\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: false, framesEmitted });\n break;\n }\n case 'step': {\n if (!pipeline) ensureRebuild();\n const bytes = pipeline!.run(1);\n framesEmitted += 1;\n post(\n { type: 'frames', batch: bytes.buffer, count: 1, fps: 0, framesEmitted },\n [bytes.buffer],\n );\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'witnessGenerate': {\n if (!pipeline) ensureRebuild();\n const samples = (m.samples as number) ?? 256;\n const result = pipeline!.runWithWitness(samples) as {\n frames: Uint8Array;\n witness: Uint8Array;\n frameCount: number;\n };\n const hex = hexWitness(result.witness);\n post(\n {\n type: 'witness',\n id: m.id,\n witness: result.witness.buffer,\n hex,\n frameCount: result.frameCount,\n },\n [result.witness.buffer],\n );\n break;\n }\n case 'witnessVerify': {\n // Verify always runs the *canonical* reference scene at seed=42, N=256\n // so the witness matches Proof::EXPECTED_WITNESS_HEX byte-for-byte.\n // The user's working scene/config/seed don't affect the witness.\n const expectedBuf = m.expected as ArrayBuffer;\n const expected = new Uint8Array(expectedBuf);\n const actual = referenceWitness();\n let ok = actual.length === expected.length;\n if (ok) {\n for (let i = 0; i < expected.length; i++) {\n if (actual[i] !== expected[i]) { ok = false; break; }\n }\n }\n const actualBuf = actual.slice().buffer;\n post(\n {\n type: 'verify',\n id: m.id,\n ok,\n actual: actualBuf,\n actualHex: hexWitness(actual),\n },\n [actualBuf],\n );\n break;\n }\n case 'runTransient': {\n const sceneJson = m.scene as string;\n const configJson = m.config as string;\n const seed = (m.seed as number) ?? 0;\n const samples = (m.samples as number) ?? 64;\n const r = runTransient(sceneJson, configJson, seed, samples);\n post({\n type: 'transient',\n id: m.id,\n bRecoveredT: Array.from(r.bRecoveredT),\n bMagT: r.bMagT,\n noiseFloorPtSqrtHz: r.noiseFloorPtSqrtHz,\n sigmaPt: Array.from(r.sigmaPt),\n nFrames: r.nFrames,\n witnessHex: r.witnessHex,\n });\n break;\n }\n case 'buildId': {\n post({\n type: 'buildId',\n id: m.id,\n buildId: `nvsim@${_WasmPipeline.buildVersion()}`,\n });\n break;\n }\n default:\n post({ type: 'err', id: m.id, msg: `unknown op ${m.type}` });\n }\n } catch (e) {\n post({ type: 'err', id: m.id, msg: (e as Error).message ?? String(e) });\n }\n});\n\npost({ type: 'ready' });\n"],"names":["ws","_WasmPipeline","referenceSceneJson","expectedReferenceWitnessHex","hexWitness","referenceWitness","runTransient","loadPkg","base","absoluteBase","pkg","pipeline","configJson","sceneJson","seed","running","timer","framesEmitted","tStart","ensureRebuild","post","msg","transfer","startTimer","tick","n","bytes","elapsed","fps","stopTimer","ev","m","samples","result","hex","expectedBuf","expected","actual","ok","i","actualBuf","e"],"mappings":"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"} \ No newline at end of file diff --git a/nvsim/index.html b/nvsim/index.html index 57646cc9..ddae9e1c 100644 --- a/nvsim/index.html +++ b/nvsim/index.html @@ -10,7 +10,7 @@ - + diff --git a/nvsim/nvsim-pkg/nvsim.d.ts b/nvsim/nvsim-pkg/nvsim.d.ts index 0b516990..3f506c5b 100644 --- a/nvsim/nvsim-pkg/nvsim.d.ts +++ b/nvsim/nvsim-pkg/nvsim.d.ts @@ -71,6 +71,26 @@ export function referenceSceneJson(): string; */ export function referenceWitness(): Uint8Array; +/** + * One-shot pipeline run that doesn't disturb the dashboard's main + * pipeline. Used by the Ghost Murmur interactive demo (and any other + * "run-against-this-scene-please" flow) to ask: given a scene + config, + * what does the NV sensor recover at the origin? + * + * Returns a JS object: + * ```js + * { + * bRecoveredT: [number, number, number], // recovered B (Tesla) + * bMagT: number, // |B| (Tesla) + * noiseFloorPtSqrtHz: number, // δB pT/√Hz from this config + * sigmaPt: [number, number, number], // per-axis 1σ noise estimate (pT) + * nFrames: number, // samples actually run + * witnessHex: string // SHA-256 witness for this run + * } + * ``` + */ +export function runTransient(scene_json: string, config_json: string, seed: number, n_samples: number): any; + export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; export interface InitOutput { @@ -80,6 +100,7 @@ export interface InitOutput { readonly hexWitness: (a: number, b: number, c: number) => void; readonly referenceSceneJson: (a: number) => void; readonly referenceWitness: (a: number) => void; + readonly runTransient: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly wasmpipeline_buildVersion: (a: number) => void; readonly wasmpipeline_frameBytes: () => number; readonly wasmpipeline_frameMagic: () => number; diff --git a/nvsim/nvsim-pkg/nvsim.js b/nvsim/nvsim-pkg/nvsim.js index 29235e02..5f9e8f2f 100644 --- a/nvsim/nvsim-pkg/nvsim.js +++ b/nvsim/nvsim-pkg/nvsim.js @@ -230,12 +230,59 @@ export function referenceWitness() { } } +/** + * One-shot pipeline run that doesn't disturb the dashboard's main + * pipeline. Used by the Ghost Murmur interactive demo (and any other + * "run-against-this-scene-please" flow) to ask: given a scene + config, + * what does the NV sensor recover at the origin? + * + * Returns a JS object: + * ```js + * { + * bRecoveredT: [number, number, number], // recovered B (Tesla) + * bMagT: number, // |B| (Tesla) + * noiseFloorPtSqrtHz: number, // δB pT/√Hz from this config + * sigmaPt: [number, number, number], // per-axis 1σ noise estimate (pT) + * nFrames: number, // samples actually run + * witnessHex: string // SHA-256 witness for this run + * } + * ``` + * @param {string} scene_json + * @param {string} config_json + * @param {number} seed + * @param {number} n_samples + * @returns {any} + */ +export function runTransient(scene_json, config_json, seed, n_samples) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(scene_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passStringToWasm0(config_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4); + const len1 = WASM_VECTOR_LEN; + wasm.runTransient(retptr, ptr0, len0, ptr1, len1, seed, n_samples); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + function __wbg_get_imports() { const import0 = { __proto__: null, __wbg___wbindgen_throw_6ddd609b62940d55: function(arg0, arg1) { throw new Error(getStringFromWasm0(arg0, arg1)); }, + __wbg_length_550d8a396009cd38: function(arg0) { + const ret = getObject(arg0).length; + return ret; + }, __wbg_length_ea16607d7b61445b: function(arg0) { const ret = getObject(arg0).length; return ret; @@ -248,6 +295,13 @@ function __wbg_get_imports() { const ret = new Uint8Array(arg0 >>> 0); return addHeapObject(ret); }, + __wbg_new_with_length_eae667475c36c4e4: function(arg0) { + const ret = new Float64Array(arg0 >>> 0); + return addHeapObject(ret); + }, + __wbg_set_636d1e3e4286e068: function(arg0, arg1, arg2) { + getObject(arg0).set(getArrayF64FromWasm0(arg1, arg2)); + }, __wbg_set_7eaa4f96924fd6b3: function() { return handleError(function (arg0, arg1, arg2) { const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); return ret; @@ -294,6 +348,11 @@ function dropObject(idx) { heap_next = idx; } +function getArrayF64FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len); +} + function getArrayU8FromWasm0(ptr, len) { ptr = ptr >>> 0; return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len); @@ -307,6 +366,14 @@ function getDataViewMemory0() { return cachedDataViewMemory0; } +let cachedFloat64ArrayMemory0 = null; +function getFloat64ArrayMemory0() { + if (cachedFloat64ArrayMemory0 === null || cachedFloat64ArrayMemory0.byteLength === 0) { + cachedFloat64ArrayMemory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64ArrayMemory0; +} + function getStringFromWasm0(ptr, len) { ptr = ptr >>> 0; return decodeText(ptr, len); @@ -419,6 +486,7 @@ function __wbg_finalize_init(instance, module) { wasm = instance.exports; wasmModule = module; cachedDataViewMemory0 = null; + cachedFloat64ArrayMemory0 = null; cachedUint8ArrayMemory0 = null; return wasm; } diff --git a/nvsim/nvsim-pkg/nvsim_bg.wasm b/nvsim/nvsim-pkg/nvsim_bg.wasm index 56c52ac34e9e3711e4db18a884c1dc2194f3d217..91e5498d6492ff815ba74fc7ae15d00879db7740 100644 GIT binary patch delta 29375 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 wPj-7))Df2YXAI@N4~yRa2Y?9BcK`qY delta 27399 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 diff --git a/nvsim/nvsim-pkg/nvsim_bg.wasm.d.ts b/nvsim/nvsim-pkg/nvsim_bg.wasm.d.ts index e5ef696f..72877f93 100644 --- a/nvsim/nvsim-pkg/nvsim_bg.wasm.d.ts +++ b/nvsim/nvsim-pkg/nvsim_bg.wasm.d.ts @@ -6,6 +6,7 @@ export const expectedReferenceWitnessHex: (a: number) => void; export const hexWitness: (a: number, b: number, c: number) => void; export const referenceSceneJson: (a: number) => void; export const referenceWitness: (a: number) => void; +export const runTransient: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; export const wasmpipeline_buildVersion: (a: number) => void; export const wasmpipeline_frameBytes: () => number; export const wasmpipeline_frameMagic: () => number; diff --git a/nvsim/sw.js b/nvsim/sw.js index 6d7fe31f..975ebece 100644 --- a/nvsim/sw.js +++ b/nvsim/sw.js @@ -1,2 +1,2 @@ -if(!self.define){let s,e={};const i=(i,n)=>(i=new URL(i+".js",n).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(n,r)=>{const c=s||("document"in self?document.currentScript.src:"")||location.href;if(e[c])return;let d={};const l=s=>i(s,c),o={module:{uri:c},exports:d,require:l};e[c]=Promise.all(n.map(s=>o[s]||l(s))).then(s=>(r(...s),d))}}define(["./workbox-8c29f6e4"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"4bcaa063d693b37532f242f566232490"},{url:"index.html",revision:"934dcb4a251b1c4907091ce92f5ac9d0"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"assets/worker-BW0kLvYS.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-BWlL4FHH.js",revision:null},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"manifest.webmanifest",revision:"e8c97968cae19a0ed3b64c1303a27a90"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.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 d=e=>i(e,c),l={module:{uri:c},exports:o,require:d};s[c]=Promise.all(n.map(e=>l[e]||d(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:"2f6b659c49a92c03cb8d0cef3ec20a05"},{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-9VRqUHc5.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 455d5360..8bd4fc0a 100644 --- a/nvsim/sw.js.map +++ b/nvsim/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/19f266b374f78468c3fcf58fd5709833/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\": \"934dcb4a251b1c4907091ce92f5ac9d0\"\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\": \"b510b70684796cc95dd7fb5bb0d23df7\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"assets/worker-BW0kLvYS.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-BWlL4FHH.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\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"b510b70684796cc95dd7fb5bb0d23df7\"\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 +{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/f7782794cf6d2a4a71fad4aea80c9da1/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\": \"2f6b659c49a92c03cb8d0cef3ec20a05\"\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-9VRqUHc5.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