/* Illustrative fixtures only: this is not a live model or benchmark replay. */ (() => { 'use strict'; const root = document.querySelector('#world-explorer'); if (!root) return; const $ = id => root.querySelector(`#ex-${id}`); const scenes = { "living": { "name": "Living & kitchen", "sceneId": "104348511_171513654", "image": "assets/explorer/hssd_104348511_topdown.png", "imageSize": [ 1300, 1500 ], "crop": [ 120, 100, 1080, 1080 ], "object": "mug", "id": "023", "appearance": "Illustrative ceramic mug", "locations": [ "Dining table", "Coffee table", "Kitchen island", "Unknown" ], "prior": [ 0.15, 0.65, 0.1, 0.1 ], "relation": "Supported by dining table", "pattern": "In this illustrative routine, a used mug is likely to move toward the living area. The coffee table is the first inspection hypothesis.", "activity": "Daily use may move the target between surfaces.", "recovered": "Kitchen island", "shape": "mug", "anchors": [ [ 1030, 870 ], [ 686, 408 ], [ 487, 985 ] ], "start": [ 361, 661 ], "routes": [ [ [ 361, 661 ], [ 468, 457 ] ], [ [ 468, 457 ], [ 528.5, 695.3 ], [ 719.1, 870.6 ], [ 788, 1007 ] ] ] }, "dining": { "name": "Dining & kitchen", "sceneId": "102344280", "image": "assets/explorer/hssd_102344280_topdown.png", "imageSize": [ 1400, 900 ], "crop": [ 240, 170, 1150, 585 ], "object": "bowl", "id": "041", "appearance": "Illustrative ceramic bowl", "locations": [ "Center table", "Dining table", "Kitchen sink", "Unknown" ], "prior": [ 0.15, 0.65, 0.1, 0.1 ], "relation": "Supported by center table", "pattern": "In this illustrative routine, a bowl is likely to move to the dining table. A fresh inspection tests that hypothesis.", "activity": "Daily use may move the target between surfaces.", "recovered": "Kitchen sink", "shape": "bowl", "anchors": [ [ 1040, 470 ], [ 493, 423 ], [ 945.4, 644.1 ] ], "start": [ 720, 310 ], "routes": [ [ [ 720, 310 ], [ 650, 429 ] ], [ [ 650, 429 ], [ 926.9, 558.3 ] ] ] } }; let shown = [0.15,0.65,0.10,0.10], beliefFrame = 0, story = false, storyRun = 0; const initial = [.96,.02,.01,.01]; let key = 'living', hours = 48, stage = 'predict', busy = false, generation = 0; const reduced = window.matchMedia('(prefers-reduced-motion: reduce)'); const delay = ms => new Promise(resolve => setTimeout(resolve, reduced.matches ? 0 : ms)); function beliefs() { const s = scenes[key], t = hours / 48; let p = initial.map((v,i) => v * (1-t) + s.prior[i] * t); if (stage === 'updated' || stage === 'found') { // P(not detected | candidate): 95% visibility at the inspected location. p = p.map((v,i) => v * (i === 1 ? .05 : 1)); const z = p.reduce((a,b) => a+b,0); p = p.map(v => v/z); } if (stage === 'found') { // Positive detection: high likelihood at the recovered location, small false-positive likelihood elsewhere. p = p.map((v,i) => v * (i === 2 ? .98 : .002)); const z = p.reduce((a,b) => a+b,0); p = p.map(v => v/z); } return p; } function percentages(p) { const values=p.map(v=>Math.floor(v*100)); const order=p.map((v,i)=>({i,r:v*100-values[i]})).sort((a,b)=>b.r-a.r); const remaining=100-values.reduce((a,b)=>a+b,0); for(let i=0;i[(x*c-y*s-(x*s+y*c))*.82,(x*c-y*s+x*s+y*c)*.45-z]; const coord=p=>point(p).map(n=>n.toFixed(2)).join(','); const poly=(v,fill,stroke='#8d8d8d')=>``; function chassis(x,y,z,w,d,h,top,side) { const faces=[ {v:[[x,y,z],[x+w,y,z],[x+w,y,z+h],[x,y,z+h]],fill:side}, {v:[[x+w,y,z],[x+w,y+d,z],[x+w,y+d,z+h],[x+w,y,z+h]],fill:side}, {v:[[x+w,y+d,z],[x,y+d,z],[x,y+d,z+h],[x+w,y+d,z+h]],fill:side}, {v:[[x,y+d,z],[x,y,z],[x,y,z+h],[x,y+d,z+h]],fill:side} ].sort((a,b)=>a.v.reduce((n,p)=>n+point([p[0],p[1],0])[1],0)-b.v.reduce((n,p)=>n+point([p[0],p[1],0])[1],0)); return faces.map(f=>poly(f.v,f.fill)).join('')+poly([[x,y,z+h],[x+w,y,z+h],[x+w,y+d,z+h],[x,y+d,z+h]],top,'#d4d4d4'); } const legs=[[-18,-12,0],[18,-12,Math.PI],[-18,12,Math.PI],[18,12,0]].map(([x,y,offset])=>{ const cycle=phase+offset,stride=walking?Math.sin(cycle)*6:0,lift=walking?Math.max(0,Math.cos(cycle))*5:0; const hip=[x,y,24+bob],knee=[x-5+stride*.4,y*1.1,13+lift*.4],foot=[x+stride+2,y*1.2,2+lift]; const h=point(hip),k=point(knee),f=point(foot),near=point([x,y,0])[1]; return {near,html:``}; }).sort((a,b)=>a.near-b.near); let body=chassis(-25,-11,22+bob,50,22,11,'url(#ex-robot-metal)','#707070'); body+=chassis(-14,-7,33+bob,26,14,2,'#3c3c3c','#555'); body+=chassis(24,-8,24+bob,6,16,7,'#8c8c8c','#292929'); // Forward stereo cameras, top lidar, side panel and restrained status light. for(const y of [-4,4]) {const p=point([30,y,28+bob]);body+=``;} const lidar=point([9,0,38+bob]);body+=``; for(let i=0;i<4;i++)body+=``; return `${legs.slice(0,2).map(l=>l.html).join('')}${body}${legs.slice(2).map(l=>l.html).join('')}`; } function poseRobot(phase=0,walking=false) {$('agent').innerHTML=quadruped(robotHeading,phase,walking);} function robotState(text,mode='idle') { $('robot-status').textContent=text;root.dataset.robotState=mode; } function buildScene() { const s=scenes[key],m=mapLayout(); $('task').textContent=`Find the ${s.object}`; const overlays=s.anchors.map((point,i)=>{ const [a,b]=mapPoint(point),labelX=Math.min(648,Math.max(72,a)),labelY=b-44; return `${s.locations[i]}`; }).join(''); $('map').setAttribute('viewBox','0 0 720 600'); $('map').innerHTML=`HSSD ${s.sceneId}: ${s.name}${overlays}`; $('distribution').innerHTML=s.locations.map((name,i)=>`
${name}
`).join(''); if(s.shape==='bowl')$('object').innerHTML=''; $('robot-preview').innerHTML=quadruped(-.35);$('scene-source').textContent=`HSSD ${s.sceneId}`;$('scene-source').href=s.image; shown=beliefs(); root.querySelectorAll('[data-scene]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.scene===key))); } function render() { if(!busy)robotState(stage==='found'?'Target confirmed':stage==='updated'?'Ready to replan':'Standing by',stage==='found'?'success':'idle'); const s=scenes[key], p=beliefs(), pc=percentages(p), leader=p.indexOf(Math.max(...p)); animateBelief(p); $('map-clock').textContent=`DAY ${String(1+Math.floor((9+hours)/24)).padStart(2,'0')} / ${String((9+hours)%24).padStart(2,'0')}:00`; $('map-desc').textContent=`HSSD ${s.sceneId}; captured scene with illustrative beliefs and robot. ${s.locations.map((n,i)=>`${n}: ${pc[i]}%`).join(', ')}. ${stage==='found'?'Object recovered.':hours===0?'Object directly observed.':'Object location unobserved.'}`; $('time').value=hours; $('time').setAttribute('aria-valuetext',`${hours} hours since observation`); $('elapsed').textContent=hours===0?'Just observed':`${hours} hours`; root.querySelectorAll('[data-time]').forEach(b=>b.setAttribute('aria-pressed',String(Number(b.dataset.time)===hours))); $('phase').textContent=busy?'Inspecting':stage==='found'?'Target recovered':stage==='updated'?'Belief updated':hours===0?'Direct observation':hours<48?'Time elapsing':'Current query'; $('evidence-age').textContent=stage==='found'?'Just observed':`${hours}h since observation`; $('evidence-source').textContent=stage==='found'?'Positive detection':stage==='updated'?'Negative inspection':'Historical observation'; $('evidence-location').textContent=stage==='found'?s.recovered:stage==='updated'?s.locations[1]:s.locations[0]; $('context').textContent=stage==='found'?`New observation · ${s.recovered} · Day 3, 09:15`: `Last seen: ${s.locations[0]} · Day 1, 09:00 · ${hours}h ago`; $('reason-title').textContent=stage==='updated'?'VISIBILITY-AWARE UPDATE':stage==='found'?'NEW EVIDENCE, NEW MEMORY':'WHY THIS PREDICTION?'; $('explanation').textContent=stage==='updated'?`No ${s.object} detected at the ${s.locations[1].toLowerCase()}. With 95% inspection visibility, its probability falls to ${pc[1]}%. Other locations remain plausible.`:stage==='found'?`A positive observation at the ${s.recovered.toLowerCase()} raises its belief to ${pc[2]}%. The observation is recorded as a new memory version.`:hours===0?`The ${s.object} is directly observed on the ${s.locations[0].toLowerCase()}. A fresh observation anchors the belief at 96%.`:hours<48?`${s.activity} No new observation is available; uncertainty grows as the original memory ages.`:s.pattern; $('action').disabled=busy; $('action').innerHTML=busy?'Navigating & inspecting… ···':stage==='found'?'Replay this scenario ↺':stage==='updated'?`Inspect ${s.recovered.toLowerCase()} →`:hours<48?'Advance to current query →':`Inspect ${s.locations[1].toLowerCase()} →`; $('action-hint').textContent=stage==='updated'?'Inspect another plausible location to resolve uncertainty.':stage==='found'?'Evidence closes the loop. Memory stays current.':'Follow the belief. Gather new evidence.'; $('object').setAttribute('transform',`translate(${(mapPoint(s.anchors[stage==='found'?2:0])).join(' ')})`); $('object').style.opacity=hours===0||stage==='found'?'1':'0'; const active=busy?1:stage==='found'?3:stage==='updated'?2:0; root.querySelectorAll('[data-step]').forEach(el=>{el.dataset.active=String(Number(el.dataset.step)<=active);if(Number(el.dataset.step)===active)el.setAttribute('aria-current','step');else el.removeAttribute('aria-current');}); $('status').textContent=busy?`Moving to the ${stage==='updated'?s.recovered.toLowerCase():s.locations[1].toLowerCase()} to gather evidence…`:stage==='found'?`Target found at the ${s.recovered.toLowerCase()}. The agent’s memory now contains a fresh observation.`:stage==='updated'?`${s.locations[1]} checked · target not detected · posterior renormalized across all candidates.`:hours===0?`Day 1 · ${s.object} observed on the ${s.locations[0].toLowerCase()}.`:`${hours} hours without direct observation. ${hours===48?'Inspect the leading hypothesis to see how evidence changes the belief.':'Move through time to see the belief evolve.'}`; $('memory-name').textContent=`${s.object} · object_${s.id}`; $('memory-content').innerHTML=`

IDENTITY

object_${s.id}
${s.appearance}
First observed: Day 1, 09:00

OBSERVATION HISTORY

Day 1 · ${s.locations[0]} · confidence 0.96
${hours>0?`Following ${hours}h · no direct observation`:'Fresh observation'}${stage==='updated'||stage==='found'?`
Day 3 · ${s.locations[1]} · negative evidence`:''}${stage==='found'?`
Day 3, 09:15 · ${s.recovered} · detected`:''}

RELATIONS & PROVENANCE

${stage==='found'?`Located at ${s.recovered}`:s.relation}
Scene: HSSD ${s.sceneId}
Beliefs and target: illustrative scenario
${stage==='updated'?'P(s | no detection) ∝ P(no detection | s) P(s)':'Persistent identity · versioned observations'}

`; } function paintBelief(values) { shown=values;const rounded=percentages(values),leader=values.indexOf(Math.max(...values)); for(let i=0;i<4;i++) { $(`value-${i}`).textContent=`${rounded[i]}%`;$(`fill-${i}`).style.width=`${values[i]*100}%`;$(`bar-${i}`).dataset.leader=String(i===leader); if(i<3){$(`prob-${i}`).textContent=`${rounded[i]}%`;$(`halo-${i}`).style.opacity=.12+values[i]*.88;$(`halo-${i}`).setAttribute('rx',40+values[i]*65);$(`halo-${i}`).setAttribute('ry',22+values[i]*34);} } } function animateBelief(target) { cancelAnimationFrame(beliefFrame); if(reduced.matches){paintBelief(target);return;} const from=[...shown],start=performance.now(); const tick=now=>{const t=Math.min(1,(now-start)/700),ease=1-Math.pow(1-t,4);paintBelief(from.map((v,i)=>v+(target[i]-v)*ease));if(t<1)beliefFrame=requestAnimationFrame(tick);}; beliefFrame=requestAnimationFrame(tick); } function stopStory(){storyRun++;story=false;$('play').textContent='▶ Start demonstration';$('play').setAttribute('aria-pressed','false');} function reset(time=48, keepStory=false) { if(!keepStory)stopStory(); generation++;busy=false;stage='predict';hours=time; robotHeading=-Math.PI/2;poseRobot(); $('route').style.opacity=0;$('route-shadow').style.opacity=0;$('agent').setAttribute('transform',`translate(${mapPoint(scenes[key].start).join(' ')})`); $('scan').querySelector('ellipse').classList.remove('scanning');render(); } function travel(path,token) { return new Promise(resolve=>{ const route=$('route');route.setAttribute('d',path);route.style.opacity=1; const shadow=$('route-shadow');shadow.setAttribute('d',path);shadow.style.opacity='.75'; const length=route.getTotalLength();shadow.style.strokeDasharray=length;shadow.style.strokeDashoffset=length;route.style.strokeDasharray=length;route.style.strokeDashoffset=length; const start=performance.now(),duration=reduced.matches?0:2600; robotState('Walking · route tracking','walking'); let last= start; function frame(now){ if(token!==generation){resolve(false);return;} const t=duration?Math.min(1,(now-start)/duration):1; const ease=t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2; const point=route.getPointAtLength(length*ease); const before=route.getPointAtLength(Math.max(0,length*ease-.6)); const after=route.getPointAtLength(Math.min(length,length*ease+.6)); const dx=after.x-before.x,dy=after.y-before.y; const heading=Math.atan2((dy/.45-dx/.82)/2,(dy/.45+dx/.82)/2); const delta=Math.atan2(Math.sin(heading-robotHeading),Math.cos(heading-robotHeading)); robotHeading+=delta*(reduced.matches?1:1-Math.exp(-Math.min(60,now-last)/85));last=now; poseRobot(length*ease*.12,t>0&&t<1&&!reduced.matches); $('agent').setAttribute('transform',`translate(${point.x} ${point.y})`);route.style.strokeDashoffset=length*(1-ease);shadow.style.strokeDashoffset=length*(1-ease); if(t<1)requestAnimationFrame(frame);else resolve(true); } requestAnimationFrame(frame); }); } async function inspect() { if(busy)return; if(stage==='found'){reset();return;} if(hours<48){reset();return;} const token=++generation,recovering=stage==='updated';busy=true;render(); // Keep the measured NavMesh waypoints; rounded line joins don't cut corners. const path=scenes[key].routes[recovering?1:0].map((v,i)=>`${i?'L':'M'}${mapPoint(v).join(' ')}`).join(' '); if(!await travel(path,token))return; robotState('Stationary · visual scan','scanning'); $('phase').textContent='Scanning';$('action').innerHTML='Acquiring visual evidence… ◌'; $('status').textContent=`Inspecting the ${recovering?scenes[key].recovered.toLowerCase():scenes[key].locations[1].toLowerCase()} · checking target visibility.`; $('scan').setAttribute('transform',`translate(${mapPoint(scenes[key].anchors[recovering?2:1]).join(' ')})`); $('scan').querySelector('ellipse').classList.add('scanning'); await delay(1100);if(token!==generation)return; $('scan').querySelector('ellipse').classList.remove('scanning');stage=recovering?'found':'updated';busy=false;render(); } root.querySelectorAll('[data-scene]').forEach(b=>b.addEventListener('click',()=>{key=b.dataset.scene;stage='predict';hours=48;buildScene();reset();})); root.querySelectorAll('[data-time]').forEach(b=>b.addEventListener('click',()=>reset(Number(b.dataset.time)))); $('time').addEventListener('input',e=>reset(Number(e.target.value))); $('reset').addEventListener('click',()=>reset()); $('inspect-memory').addEventListener('click',()=>{$('memory').open=true;$('memory').querySelector('summary').focus();}); $('action').addEventListener('click',()=>{stopStory();inspect();}); $('play').addEventListener('click',async()=>{ if(story){reset(hours);return;} reset(0);const run=++storyRun;story=true;$('play').textContent='Ⅱ Stop demonstration';$('play').setAttribute('aria-pressed','true'); let token=generation;await delay(1000);if(!story||run!==storyRun||token!==generation)return; // Advance historical time at a steady cadence; manual controls always cancel the story. for(let h=1;h<=48;h++){if(!story||run!==storyRun||token!==generation)return;hours=h;render();await delay(45);} await delay(600);if(!story||run!==storyRun||token!==generation)return; await inspect();if(!story||run!==storyRun)return;token=generation; await delay(1500);if(!story||run!==storyRun||token!==generation)return; await inspect();if(story&&run===storyRun)stopStory(); }); document.addEventListener('visibilitychange',()=>{if(document.hidden&&(story||busy))reset(hours);}); buildScene();reset();root.hidden=false; })();