code wiki / (root) / nx_game_rig_inspection_emit_t230.nx

nx_game_rig_inspection_emit_t230.nx source

↩ module page · 4 lines · 23073 B

1// Shared character inspection adapter; all pose and hierarchy mathematics comes from native preparation. 2func gpe_rig_inspection_emit(out:*u8,pos:i64)->i64{ 3 return gpe_ap(out,pos,"function nxRigAdmission(descriptor,packet){\n const r=descriptor.rig;if(r==null)return {state:'unavailable',reason:'Source rig evidence not prepared'};\n const bad=reason=>{throw Error('prepared-rig-'+reason)};\n if(!Array.isArray(packet.samples)||!packet.samples.length||!Number.isSafeInteger(packet.q)||packet.q<=0||!Number.isSafeInteger(packet.timeQ)||packet.timeQ<=0)bad('sample-basis');\n if(r.schema!=='nishi-source-rig/1'||r.sourceSha256!==descriptor.sourceSha256||r.skin!==descriptor.skin||r.q!==packet.q||r.basis!==descriptor.basis||r.matrixOrder!=='column-major'||!Array.isArray(r.nodes)||!r.nodes.length||!Array.isArray(r.jointNodes)||r.jointNodes.length!==descriptor.joints)bad('identity');\n const nodes=r.nodes,slots=new Map();\n for(let i=0;i<nodes.length;i++){const n=nodes[i];if(n.sourceNode!==i||!Number.isSafeInteger(n.parent)||n.parent< -1||n.parent>=nodes.length||n.parent===i||(n.name!==null&&typeof n.name!=='string')||![n.localRest,n.worldRest].every(a=>Array.isArray(a)&&a.length===16&&a.every(Number.isSafeInteger)))bad('node');\n }\n const done=new Uint8Array(nodes.length);for(let i=0;i<nodes.length;i++){let at=i;const path=[];while(at>=0&&done[at]!==2){if(done[at]===1)bad('cycle');done[at]=1;path.push(at);at=nodes[at].parent;}for(const p of path)done[p]=2;}\n r.jointNodes.forEach((node,slot)=>{if(!Number.isSafeInteger(node)||node<0||node>=nodes.length||slots.has(node))bad('joint-index');slots.set(node,slot);});\n let sampled=true;for(const sample of packet.samples){if(sample.jointWorld===undefined){sampled=false;continue;}if(!Array.isArray(sample.jointWorld)||sample.jointWorld.length!==r.jointNodes.length||!sample.jointWorld.every(a=>Array.isArray(a)&&a.length===3&&a.every(Number.isSafeInteger)))bad('joint-world');}\n return {state:'ready',rig:r,slots,sampled,scope:'Source hierarchy and native sampled joint origins; anatomy and contact unqualified'};\n}\nfunction nxRigObservation(D,nodeIndex){\n const a=D.prepared.rigEvidence;if(a?.state!=='ready')return {state:'unavailable',reason:a?.reason||'No rig evidence'};\n const node=Number.isSafeInteger(nodeIndex)?a.rig.nodes[nodeIndex]:null;if(!node)return {state:'unavailable',reason:'Source node unavailable'};\n const slot=a.slots.get(nodeIndex),sample=nxPreparedCurrentSample(D),world=slot===undefined?null:sample.jointWorld?.[slot]||null;\n return {state:'observed',sourceSha256:a.rig.sourceSha256,descriptorSha256:D.prepared.manifest.descriptor.sha256,discretePoseSha256:D.prepared.manifest.poses.sha256,clipSha256:D.prepared.motionActive!==false?D.prepared.motion?.manifest.clip.sha256||null:null,sourceNode:nodeIndex,name:node.name,parent:node.parent,skinSlot:slot??null,sampleIndex:D.prepared.motionActive!==false&&D.prepared.motion?null:D.prepared.selected,mode:D.prepared.motionActive!==false&&D.prepared.motion?D.prepared.motion.mode:'discrete',time:sample.time,timeQ:D.prepared.packet.timeQ,q:a.rig.q,restOrigin:node.worldRest.slice(12,15),sampleOrigin:world,units:'source-scene coordinates (not Beach placement); physical scale unknown',anatomicalRole:'unassigned',continuousPlayback:D.prepared.motionActive!==false&&!!D.prepared.motion?.status().continuousPlayback,terrainContact:'unqualified',navigation:'unbound'};\n}\nfunction nxRigInspection(D,box){\n const a=D.prepared.rigEvidence,details=document.createElement('details'),summary=document.createElement('summary');summary.textContent='Rig and motion evidence';details.append(summary);details.style.maxInlineSize='100%';box.append(details);\n if(a.state!=='ready'){const p=document.createElement('p');p.textContent=a.reason;details.append(p);return;}\n const label=document.createElement('label'),select=document.createElement('select');label.textContent='Source joint ';select.setAttribute('aria-label','Source joint '+D.l);select.style.maxInlineSize='100%';\n for(const n of a.rig.nodes){const o=document.createElement('option');o.value=String(n.sourceNode);o.textContent='#'+n.sourceNode+' '+(n.name||'Unnamed')+' · parent '+n.parent;select.append(o);}label.append(select);details.append(label);\n const status=document.createElement('p'),record=document.createElement('dl'),table=document.createElement('table'),caption=document.createElement('caption');caption.textContent='Native joint origin by sampled time · source-scene coordinates (not Beach placement)';table.append(caption);const head=document.createElement('thead'),hr=document.createElement('tr');for(const text of ['Time (s)','X','Y','Z']){const th=document.createElement('th');th.textContent=text;hr.append(th);}head.append(hr);table.append(head);const body=document.createElement('tbody');table.append(body);const scroll=document.createElement('div');scroll.style.cssText='max-inline-size:100%;max-block-size:40vh;overflow:auto';scroll.append(table);details.append(record,scroll,status);\n let tableSlot=undefined;const update=()=>{const o=nxRigObservation(D,Number(select.value));window.__nx_rig_observation=o;record.replaceChildren();for(const [key,value]of [['Node',o.name||'Unnamed'],['Source index',o.sourceNode],['Parent index',o.parent],['Skin slot',o.skinSlot??'Not skinned'],['Selected time',(o.time/o.timeQ).toFixed(3)+' s'],['Anatomical role','Unassigned']]){const dt=document.createElement('dt'),dd=document.createElement('dd');dt.textContent=key;dd.textContent=String(value);record.append(dt,dd);}\n if(tableSlot!==o.skinSlot){tableSlot=o.skinSlot;body.replaceChildren();for(const sample of D.prepared.packet.samples){const row=document.createElement('tr'),p=o.skinSlot===null?null:sample.jointWorld?.[o.skinSlot];for(const value of [(sample.time/D.prepared.packet.timeQ).toFixed(3),...(p?p.map(v=>(v/o.q).toFixed(4)):['—','—','—'])]){const td=document.createElement('td');td.textContent=value;row.append(td);}body.append(row);}}\n status.textContent=(o.sampleOrigin?'Native joint samples available. ':'Joint motion not sampled. ')+(D.prepared.motionActive!==false&&D.prepared.motion?'Current native clip time '+(o.time/o.timeQ).toFixed(3)+' s. ':'Discrete native pose. ')+'Anatomical fit, contact and navigation remain unqualified.';\n };\n select.addEventListener('change',update);details.addEventListener('toggle',()=>{if(details.open)update();});D.prepared.rigRefresh=()=>{if(details.open)update();};update();\n}\nconst nxResidentRigCapture={serial:0,pending:null,record:null};\nconst nxResidentRigPhases=['native','ankle','collapse','plant'];\nfunction nxResidentRigRequest(actor,request){\n const c=nxResidentRigCapture,action=request?.action||'status',N=GPU?.cast||GL?.npc,actors=Number(ex.mobs());\n if(!Number.isSafeInteger(actor)||!Number.isSafeInteger(actors)||actor<0||actor>=actors||!N?.st?.[actor])return {schema:'nishi-resident-rig-observation/1',state:'refused',reason:'Resident actor is not loaded',actor,actors};\n if(action==='capture'){\n if(nxResidentComparison.frozen)return {state:'busy',accepted:false,requestedActor:actor,pendingActor:nxResidentComparison.actor,requestId:nxResidentComparison.requestId,reason:'Resume live scene before another capture'};\n if(c.pending)return {state:'busy',accepted:false,requestedActor:actor,pendingActor:c.pending.actor,requestId:c.pending.id};\n c.record=null;c.pending={id:++c.serial,actor,requestedAt:new Date().toISOString()};return {schema:'nishi-resident-rig-observation/1',state:'waiting',accepted:true,request:c.pending,next:'The next normal evaluation of this actor captures native and draw stages; playback is unchanged.'};\n }\n if(action==='cancel'){\n if(!c.pending)return {state:'unavailable',reason:'No pending capture'};\n if(c.pending.actor!==actor||request?.requestId!==c.pending.id)return {state:'refused',reason:'Cancellation requires matching actor and requestId',requestedActor:actor,pendingActor:c.pending.actor,requestId:c.pending.id};\n const pending=c.pending;if(c.record)c.record.state='cancelled';c.pending=null;return {state:'cancelled',request:pending};\n }\n if(action!=='status'&&action!=='read')return {state:'refused',reason:'Unknown observation action'};\n if(c.pending)return {schema:'nishi-resident-rig-observation/1',state:c.pending.actor===actor?'waiting':'busy',requestedActor:actor,pendingActor:c.pending.actor,request:c.pending};\n if(!c.record||c.record.actor!==actor)return {schema:'nishi-resident-rig-observation/1',state:'unavailable',reason:'No completed capture for this actor'};\n if(action==='read')return c.record;\n return {schema:c.record.schema,state:c.record.state,actor:c.record.actor,tick:c.record.tick,requestId:c.record.requestId,phases:c.record.phases.map(p=>p.name),reason:c.record.reason||null};\n}\nfunction nxResidentRigStage(N,m,v,name,rc=0){\n const c=nxResidentRigCapture,p=c.pending;if(!p||p.actor!==m)return;\n try{\n const refuse=reason=>{c.record={...(c.record||{}),schema:'nishi-resident-rig-observation/1',state:'refused',requestId:p.id,actor:m,phases:c.record?.phases||[],reason};c.pending=null;nxResidentComparison.complete(c.record,N);};\n const expected=c.record?.phases.length||0;\n if(name!==nxResidentRigPhases[expected]){refuse('Unexpected palette phase: expected '+nxResidentRigPhases[expected]+', received '+name);return;}\n if(!Number.isSafeInteger(N.nj)||N.nj<1||!Number.isSafeInteger(v)||v<0||(v+1)*N.nj*8>N.jf.length){refuse('Palette extent invalid');return;}\n if(name==='native'){\n const a=window.__nx_cast_asset;c.record={schema:'nishi-resident-rig-observation/1',state:'capturing',requestId:p.id,actor:m,slot:v,tick:String(ex.tnow()),joints:N.nj,source:a?{sha256:a.sha256||null,url:a.actual_url||a.requested_url||null,bytes:a.bytes||null}:null,units:'model units; quaternion and dual rows divided by4096',positionQ8:[String(ex.mobx(BigInt(m))),String(ex.moby(BigInt(m))),String(ex.mobz(BigInt(m)))],idleQ12:String(ex.cast_iw(BigInt(m))),footJoints:Array.from(N.fj||[]),collapsedJoints:Array.from(N.hc||[],x=>Array.from(x)),phases:[],qualification:'Actual evaluator and page overrides; visual deformation remains unqualified'};\n if(rc<0){refuse('Native palette evaluation failed: '+rc);return;}\n }\n const r=c.record;if(r.actor!==m||r.slot!==v||r.joints!==N.nj||r.tick!==String(ex.tnow())){refuse('Actor, palette, or scene tick changed during capture');return;}\n const rows=Array.from(N.jf.slice(v*N.nj*8,(v+1)*N.nj*8));if(rows.length!==N.nj*8||!rows.every(Number.isFinite)){refuse('Palette rows unavailable or nonfinite');return;}\n r.phases.push({name,rows});if(r.phases.length===nxResidentRigPhases.length){r.plantModelUnits=Number(N.zf[v]);if(!Number.isFinite(r.plantModelUnits)){refuse('Plant translation nonfinite');return;}r.state='observed';r.observedAt=new Date().toISOString();c.pending=null;nxResidentComparison.complete(r,N);}\n }catch(error){c.record={schema:'nishi-resident-rig-observation/1',state:'refused',requestId:p.id,actor:m,phases:[],reason:'Observation failed: '+String(error)};c.pending=null;nxResidentComparison.complete(c.record,N);}\n}\nwindow.nishiRigObservation=(asset,node,request)=>{if(asset?.kind==='resident')return request?.action?.startsWith('compare-')?nxResidentComparison.request(asset.actor,request):nxResidentRigRequest(asset.actor,request);const D=DN.find(d=>d.sourceId===asset);return D?.prepared?nxRigObservation(D,node):{state:'unavailable',reason:'Prepared actor not loaded'};};\n\nconst NX_RIG_COMPARE_MODULE={\"schema\":\"nishi-native-rig-comparison-module/1\",\"url\":\"/releases/native-rig-comparison-08e21cb2781894a71886275354fccceb46d04e8aec69b9ab8f50882b091d330b.wasm\",\"bytes\":98661,\"sha256\":\"08e21cb2781894a71886275354fccceb46d04e8aec69b9ab8f50882b091d330b\",\"q\":1073741824,\"modelUnitsPerTranslationUnit\":1024,\"qualification\":\"Rigid hierarchy composition; contact, anatomy and overall deformation unqualified\"};\nclass NishiResidentRigComparison {\n constructor(){this.generation=0;this.state='idle';this.frozen=false;this.actor=null;this.requestId=null;this.mode='current';this.record=null;this.views=null;this.reason=null;this.instance=null;this.loading=null;}\n notify(){try{this.refresh?.();}catch(error){this.uiError=String(error.message||error);}}\n status(){return {schema:'nishi-resident-rig-comparison/1',state:this.state,frozen:this.frozen,actor:this.actor,requestId:this.requestId,mode:this.mode,tick:this.record?.tick||null,source:this.record?.source||null,moduleSha256:NX_RIG_COMPARE_MODULE.sha256,reason:this.reason,scope:'Captured skin palette comparison with identical plant translation; contact and post-skin procedural deformation remain unqualified'};}\n async load(){if(this.instance)return;if(!this.loading)this.loading=(async()=>{const bytes=await nxPreparedBytes(NX_RIG_COMPARE_MODULE);const result=await WebAssembly.instantiate(bytes,{});const x=result.instance.exports;if(!(x.memory instanceof WebAssembly.Memory)||typeof x.hc_dq_apply!=='function'||typeof x.hc_dq_anchor_correction!=='function')throw Error('Native hierarchy module exports unavailable');this.instance=result.instance;})().finally(()=>{this.loading=null;});return this.loading;}\n reserve(n){const x=this.instance.exports,words=n*41+63,need=words*8;if(!Number.isSafeInteger(need)||need<=0)throw Error('Comparison memory extent invalid');if(!this.arena||this.arena.bytes<need){const start=x.memory.buffer.byteLength;x.memory.grow(Math.ceil(need/65536));this.arena={start,bytes:Math.ceil(need/65536)*65536};}let cursor=this.arena.start;const take=count=>{const p=cursor;cursor+=count*8;return p;};const p={parents:take(n),source:take(n*8),target:take(n*8),a:take(n*8),b:take(n*8),work:take(n*8+16),correction:take(7),derive:take(40)};if(cursor>this.arena.start+this.arena.bytes)throw Error('Comparison arena exhausted');this.memory=new BigInt64Array(x.memory.buffer);return p;}\n encode(rows,n,offset){if(!Array.isArray(rows)||rows.length!==n*8)throw Error('Captured palette size changed');const Q=NX_RIG_COMPARE_MODULE.q,U=NX_RIG_COMPARE_MODULE.modelUnitsPerTranslationUnit;for(let i=0;i<rows.length;i++){const value=Math.round(rows[i]*Q/(i<n*4?1:U));if(!Number.isSafeInteger(value))throw Error('Captured palette cannot be represented in native Q30');this.memory[offset/8+i]=BigInt(value);}}\n decode(offset,n){const Q=NX_RIG_COMPARE_MODULE.q,U=NX_RIG_COMPARE_MODULE.modelUnitsPerTranslationUnit;return Array.from({length:n*8},(_,i)=>Number(this.memory[offset/8+i])/Q*(i<n*4?1:U));}\n evaluate(record,N){const n=record.joints,p=this.reserve(n),x=this.instance.exports,par=N.parents;if(!(par instanceof Int32Array)||par.length!==n)throw Error('Loaded source SKEL hierarchy unavailable');if(!/^[0-9a-f]{64}$/.test(record.source?.sha256||'')||record.source.sha256!==window.__nx_cast_asset?.sha256)throw Error('Captured source identity no longer matches loaded actor');if(!Array.isArray(record.footJoints)||!record.footJoints.length)throw Error('Captured correction anchors unavailable');for(let j=0;j<n;j++)this.memory[p.parents/8+j]=BigInt(par[j]);const anchors=new Set(record.footJoints);for(const j of anchors){if(!Number.isSafeInteger(j)||j<0||j>=n)throw Error('Invalid captured correction anchor');let at=par[j],steps=0;while(at>=0){if(at>=n||++steps>n)throw Error('Source hierarchy is cyclic or invalid');if(anchors.has(at))throw Error('Overlapping correction subtrees require an explicit composition policy');at=par[at];}}\n this.encode(record.phases[0].rows,n,p.source);this.encode(record.phases[1].rows,n,p.target);let from=p.source,to=p.a;const apply=(anchor,source,dest)=>{const rc=Number(x.hc_dq_apply(BigInt(p.parents),BigInt(n),BigInt(source),1n,BigInt(anchor),BigInt(p.correction),BigInt(dest),BigInt(n*8),BigInt(p.work),BigInt(n*8+16)));if(rc!==0)throw Error('Native hierarchy composition refused: '+rc);};\n for(const anchor of anchors){const rc=Number(x.hc_dq_anchor_correction(BigInt(p.source),BigInt(p.target),BigInt(n),BigInt(anchor),BigInt(p.correction),BigInt(p.derive),40n));if(rc!==0)throw Error('Native captured-anchor derivation refused: '+rc);apply(anchor,from,to);from=to;to=to===p.a?p.b:p.a;}\n const plant=rows=>{this.encode(Array.from(rows),n,p.source);const c=[0,0,0,NX_RIG_COMPARE_MODULE.q,0,0,Math.round(-record.plantModelUnits*NX_RIG_COMPARE_MODULE.q/NX_RIG_COMPARE_MODULE.modelUnitsPerTranslationUnit)];if(!c.every(Number.isSafeInteger))throw Error('Captured plant translation outside native range');for(let k=0;k<7;k++)this.memory[p.correction/8+k]=BigInt(c[k]);let source=p.source,dest=p.a;for(let j=0;j<n;j++)if(par[j]<0){apply(j,source,dest);source=dest;dest=dest===p.a?p.b:p.a;}return this.decode(source,n);};\n const coherent=this.decode(from,n);return {hierarchy:Float32Array.from(plant(coherent)),baseline:Float32Array.from(plant(record.phases[0].rows)),current:Float32Array.from(record.phases[3].rows)};\n }\n complete(record,N){if(this.state!=='waiting'||record.actor!==this.actor||record.requestId!==this.requestId)return;try{if(record.state!=='observed'||record.phases.map(p=>p.name).join(',')!==nxResidentRigPhases.join(','))throw Error('Complete native/ankle/collapse/plant capture required');this.record=record;this.views=this.evaluate(record,N);this.frozen=true;this.state='ready';this.mode='current';this.reason=null;}catch(error){this.frozen=false;this.state='refused';this.reason=String(error.message||error);}this.notify();}\n apply(N,actor,slot){if(!this.frozen||this.state!=='ready'||actor!==this.actor)return false;try{if(String(ex.tnow())!==this.record.tick||this.record.source?.sha256!==window.__nx_cast_asset?.sha256)throw Error('Scene tick or loaded source changed; comparison released');const rows=this.views[this.mode];if(rows.length!==N.nj*8||!Number.isSafeInteger(slot)||slot<0||(slot+1)*rows.length>N.jf.length)throw Error('Current palette extent no longer matches capture');N.jf.set(rows,slot*rows.length);if(!N.zf)N.zf=new Float32Array(Number(ex.mobs()));N.zf[slot]=this.record.plantModelUnits;return true;}catch(error){this.frozen=false;this.state='refused';this.reason=String(error.message||error);this.notify();return false;}}\n async request(actor,request){\n const action=request.action;\n if(action==='compare-status')return this.status();\n if(action==='compare-read'){\n if(this.state!=='ready'||this.actor!==actor||request.requestId!==this.requestId)return {state:'refused',reason:'Read requires a ready comparison with matching actor and requestId'};\n return {...this.status(),plantModelUnits:this.record.plantModelUnits,views:Object.fromEntries(Object.entries(this.views).map(([name,rows])=>[name,Array.from(rows)]))};\n }\n if(action==='compare-clear'){\n if(!['loading','waiting','ready'].includes(this.state)||this.actor!==actor||request.requestId!==this.requestId)return {state:'refused',reason:'Release requires the matching comparison actor and requestId'};\n if(nxResidentRigCapture.pending?.actor===actor&&nxResidentRigCapture.pending?.id===this.requestId)nxResidentRigRequest(actor,{action:'cancel',requestId:this.requestId});\n this.generation++;this.frozen=false;this.state='idle';this.views=null;this.record=null;this.reason=null;this.notify();return this.status();\n }\n if(action==='compare-mode'){\n if(this.state!=='ready'||this.actor!==actor||request.requestId!==this.requestId||!['baseline','current','hierarchy'].includes(request.mode))return {state:'refused',reason:'Choose a captured comparison view with matching actor and requestId'};\n this.mode=request.mode;this.notify();return this.status();\n }\n if(action!=='compare-capture')return {state:'refused',reason:'Unknown comparison action'};\n if(this.state==='loading'||this.state==='waiting'||this.frozen||nxResidentRigCapture.pending)return {state:'busy',requestedActor:actor,pendingActor:this.actor,requestId:this.requestId,reason:'Release or complete the existing capture first'};\n const admitted=nxResidentRigRequest(actor,{action:'status'});if(admitted.state==='refused')return admitted;\n const generation=++this.generation;this.state='loading';this.actor=actor;this.requestId='loading-'+generation;this.reason=null;this.notify();\n try{\n await this.load();if(generation!==this.generation)return {state:'cancelled',actor,requestId:'loading-'+generation};\n const result=nxResidentRigRequest(actor,{action:'capture'});\n if(!result.accepted){this.state='refused';this.reason=result.reason||result.state;this.notify();return {...result,comparison:this.status()};}\n this.requestId=result.request.id;this.state='waiting';this.notify();return {...this.status(),next:'Frame this actor. Its next normal evaluation freezes the shared scene and retains three palette views.'};\n }catch(error){if(generation!==this.generation)return {state:'cancelled',actor,requestId:'loading-'+generation};this.state='refused';this.reason=String(error.message||error);this.notify();return this.status();}\n }\n\n}\nconst nxResidentComparison=new NishiResidentRigComparison();\nfunction nxResidentComparisonControls(panel){const details=document.createElement('details'),summary=document.createElement('summary'),status=document.createElement('p');summary.textContent='Compare captured rig corrections';details.append(summary);status.setAttribute('role','status');const controls=[];const refresh=()=>{const s=nxResidentComparison.status();status.textContent=s.state==='ready'?'Scene frozen at tick '+s.tick+' · character '+(s.actor+1)+' · '+({baseline:'source articulation',current:'current corrections',hierarchy:'hierarchy-preserving correction'}[s.mode])+'. Same captured plant shift; contact and post-skin effects remain unqualified.':s.state==='waiting'?'Waiting for this character to be evaluated. Frame it to capture; the scene continues until then.':s.state==='loading'?'Loading the verified native comparison module…':s.reason||'Capture one normal frame, compare source/current/hierarchy palettes, then return to live playback.';for(const [b,mode]of controls)b.disabled=mode==='capture'?!['idle','refused'].includes(s.state):mode==='clear'?!['loading','waiting','ready'].includes(s.state):s.state!=='ready';};nxResidentComparison.refresh=refresh;const command=async(action,extra={})=>{if(action==='compare-capture'&&nxInspect.asset){status.textContent='Select a resident character for this capture.';return;}const actor=action==='compare-capture'?nxInspect.actor:nxResidentComparison.actor;const r=await nxResidentComparison.request(actor,{action,requestId:nxResidentComparison.requestId,...extra});refresh();if(r.state==='refused'||r.state==='busy')status.textContent=r.reason||'Another capture owns this comparison.';};for(const [mode,label]of [['capture','Capture and freeze'],['baseline','Source articulation'],['current','Current corrections'],['hierarchy','Hierarchy correction'],['clear','Resume live scene']]){const b=document.createElement('button');b.type='button';b.textContent=label;b.onclick=()=>command(mode==='capture'?'compare-capture':mode==='clear'?'compare-clear':'compare-mode',{mode});controls.push([b,mode]);details.append(b);}details.append(status);panel.append(details);refresh();}\n" as *u8) 4}