Spaces:
Running
Running
Rebuild reference Pareto frontier and default all case displays to live 3D
Browse files- README.md +4 -0
- assets/buildingbench.css +7 -0
- assets/pareto.js +44 -0
- assets/scene-cards.js +276 -0
- cases.html +1 -1
- data/pareto.json +554 -0
- index.html +0 -0
README.md
CHANGED
|
@@ -25,3 +25,7 @@ Layout, navigation, wireframe mark, typography and card geometry follow the user
|
|
| 25 |
The reference toolkit's Inter, IBM Plex Mono and Source Serif 4 font files are bundled with their original SIL Open Font License notices in `assets/fonts/`. Provider marks are from the toolkit's Lobehub icons, used to identify the corresponding model providers.
|
| 26 |
|
| 27 |
Deployment remains this Hugging Face static Space: `index.html` and `cases.html`, with the existing media/model paths and headers. The pre-restyle version is recoverable at commit `9ff787d0f9d72905d92f780da56bd2229782b981`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
The reference toolkit's Inter, IBM Plex Mono and Source Serif 4 font files are bundled with their original SIL Open Font License notices in `assets/fonts/`. Provider marks are from the toolkit's Lobehub icons, used to identify the corresponding model providers.
|
| 26 |
|
| 27 |
Deployment remains this Hugging Face static Space: `index.html` and `cases.html`, with the existing media/model paths and headers. The pre-restyle version is recoverable at commit `9ff787d0f9d72905d92f780da56bd2229782b981`.
|
| 28 |
+
|
| 29 |
+
The Pareto renderer (`assets/pareto.js`) ports the reference toolkit's reversed logarithmic cost axis, connected frontier, provider palette and greedy collision-aware label placement. `data/pareto.json` combines unrounded scores from the existing `data/site.js` with exact mean costs from the original published tables; all three task views recompute non-dominance from those values. The table displays three decimals but sorts at source precision.
|
| 30 |
+
|
| 31 |
+
Homepage scenes (`assets/scene-cards.js`) adapt BuildingBench's shared WebGL renderer and per-view canvas engine. Existing public packed models are decoded with the same adapter as `cases.html`; geometry and the full case explorer remain unchanged. Visible scenes load automatically; repeated scenes share decoded assets. Drag or arrow keys orbit, wheel or +/- zoom, and the pause control stops rotation. Both Image-to-Scene cards switch between the saved repair, corrupted input and ground truth using the reference camera.
|
assets/buildingbench.css
CHANGED
|
@@ -24,3 +24,10 @@ section,section.alt,section.dark{padding:34px 0;background:transparent;color:var
|
|
| 24 |
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{animation:none!important;transition:none!important}}
|
| 25 |
.section-header.centered .section-desc{margin-left:0;margin-right:0;text-align:left}
|
| 26 |
.bar-mobile-hint{display:none}@media(max-width:650px){.bar-mobile-hint{display:block;font-size:10px;color:var(--muted);padding:10px 8px 0}.kit-bars{min-width:960px}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{animation:none!important;transition:none!important}}
|
| 25 |
.section-header.centered .section-desc{margin-left:0;margin-right:0;text-align:left}
|
| 26 |
.bar-mobile-hint{display:none}@media(max-width:650px){.bar-mobile-hint{display:block;font-size:10px;color:var(--muted);padding:10px 8px 0}.kit-bars{min-width:960px}}
|
| 27 |
+
/* Live scenes use BuildingBench's single-renderer / per-view canvas architecture. */
|
| 28 |
+
.live-scene{position:relative;display:block;overflow:hidden;isolation:isolate;background:#e6edf0;border-radius:14px;height:273px;touch-action:pan-y}.live-scene canvas{display:block;width:100%;height:100%;cursor:grab;touch-action:none;outline-offset:-3px}.live-scene canvas:active{cursor:grabbing}.scene-loading{position:absolute;inset:0;display:grid;place-items:center;color:#53616a;font-size:12px;pointer-events:none}.scene-hint{position:absolute;left:12px;bottom:10px;font-size:10px;letter-spacing:.02em;color:#fff;background:#17201dcc;border-radius:5px;padding:5px 8px;pointer-events:none}.scene-motion{position:absolute;right:10px;bottom:10px;border:1px solid #fff9;border-radius:50%;background:#fffdf8e8;color:#344341;width:28px;height:28px;padding:0;cursor:pointer}.output-panel .live-scene{height:255px;border-radius:12px}.case-card .live-scene{height:250px;border-radius:16px 16px 0 0}.case-card{display:block}.case-card .meta{padding:20px}.case-card .meta .eyebrow{font-size:9px}.case-card .meta h4{margin:8px 0}.case-card .meta .text-button{display:inline-block;margin-top:13px;font-size:12px}.scene-versions{display:flex;gap:4px;padding:9px;background:#f2f2ee;border-top:1px solid #e0e3df}.scene-versions button{flex:1;border:0;border-radius:6px;background:transparent;padding:7px 4px;color:#707b75;font:500 11px Inter,sans-serif;cursor:pointer}.scene-versions button.on{background:white;color:#17201d;box-shadow:0 1px 3px #0001}.pareto-card{background:#fffefb!important;padding:26px 28px 20px!important}.figure-title{font:400 31px/1.2 'Source Serif 4',serif!important;letter-spacing:-.7px!important;margin:0 0 8px!important}.figure-title span{color:#8d8d8d}.figure-subtitle{font:400 15.5px/22px Inter,sans-serif;color:#8d8d8d;margin:0 0 8px}.figure-caption{font:400 12px/1.7 Inter,sans-serif;color:#7d857f;margin:8px 20px 0!important}.pareto-scroll{overflow-x:auto}.pareto-svg{width:100%;min-width:880px;height:auto;display:block;font-family:Inter,sans-serif}.pareto-svg .grid{stroke:#dfdcd2;stroke-width:.8}.pareto-svg .vertical{stroke-dasharray:2 5;opacity:.65}.pareto-svg .axis{stroke:#c8c4b7;stroke-width:1}.pareto-svg .tick{fill:#9aa19b;font-size:11px}.pareto-svg .axis-title{fill:#7d857f;font-size:16px}.pareto-svg .frontier-line{fill:none;stroke:#2b3531;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}.pareto-svg .frontier-halo{fill:none;stroke:#2b3531;stroke-opacity:.13;stroke-width:11.7;stroke-linejoin:round;stroke-linecap:round}.pareto-svg .model-label{paint-order:stroke;stroke:#fffefb;stroke-width:3.6px;stroke-linejoin:round}.pareto-node{cursor:help;transition:opacity .15s}.pareto-node.dim{opacity:.24}.pareto-node:focus{outline:none}.pareto-node:focus .chip{stroke:#17201d;stroke-width:2}.pareto-tooltip{position:fixed;z-index:1000;padding:12px 15px;border:1px solid #dfdcd2;border-radius:10px;background:#fffefb;color:#4a544f;box-shadow:0 5px 25px #17201d20;pointer-events:none;opacity:0;font:12px/1.7 Inter,sans-serif}.pareto-tooltip.on{opacity:1}.pareto-tooltip strong{display:block;color:#17201d;margin-bottom:5px;font-size:13px}
|
| 29 |
+
@media(max-width:650px){.live-scene{height:260px}.output-panel .live-scene{height:245px}.case-card .live-scene{height:270px}.pareto-card{padding:20px 12px!important}.figure-title{font-size:26px!important}.figure-title span{display:block}.figure-subtitle{font-size:13px}.figure-caption{margin:10px 4px 0!important}.pareto-scroll{margin:0 -12px;padding:0 12px}.scene-hint{font-size:9px}}
|
| 30 |
+
.featured .featured-scene.live-scene{position:absolute;height:calc(100% - 57px);border-radius:0}.featured-footer,.featured-note{z-index:2}.tk figure>.live-scene{height:340px;border-radius:12px}.scene-loading{background:#e6edf0}
|
| 31 |
+
@media(max-width:650px){.case-grid{grid-template-columns:1fr}.tk figure>.live-scene{height:260px}}
|
| 32 |
+
.pareto-card .figure-title{color:#1a1a1a!important}.pareto-card .figure-title span{color:#8d8d8d}
|
| 33 |
+
.pareto-swipe{display:none}@media(max-width:650px){.pareto-swipe{display:block;font:10px Inter,sans-serif;color:#7d857f;margin:6px 0}}
|
assets/pareto.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Adapted from BuildingBench's figure-kit/pareto-frontier/render.py and live SVG.
|
| 2 |
+
// Domain, costs and scores are exclusively Code4Scene's historical paper evaluation.
|
| 3 |
+
const NS='http://www.w3.org/2000/svg';
|
| 4 |
+
const colors={openai:'#10A37F',claude:'#D97757',gemini:'#7b1fa2',meta:'#42a5f5',deepseek:'#3f51e0',zai:'#96650b',grok:'#111111',qwen:'#fe7016',thinkingmachines:'#686868'};
|
| 5 |
+
const data=await fetch('data/pareto.json?v=20261001b').then(r=>r.json());
|
| 6 |
+
await Promise.all([document.fonts.load('400 13px Inter'),document.fonts.load('700 16px Inter')]);
|
| 7 |
+
const measure=document.createElement('canvas').getContext('2d');
|
| 8 |
+
function node(tag,attrs,text){const n=document.createElementNS(NS,tag);for(const[k,v]of Object.entries(attrs))n.setAttribute(k,v);if(text!==undefined)n.textContent=text;return n;}
|
| 9 |
+
const lum=c=>{const a=c.match(/\w\w/g).map(x=>parseInt(x,16)/255).map(x=>x<=.03928?x/12.92:((x+.055)/1.055)**2.4);return .2126*a[0]+.7152*a[1]+.0722*a[2];};
|
| 10 |
+
function labelColor(hex,front){let a=hex.slice(1).match(/../g).map(x=>parseInt(x,16)/255),max=Math.max(...a),min=Math.min(...a),l=(max+min)/2,h=0,s=0,d=max-min;if(d){s=d/(1-Math.abs(2*l-1));h=max===a[0]?((a[1]-a[2])/d)%6:max===a[1]?(a[2]-a[0])/d+2:(a[0]-a[1])/d+4;h=(h/6+1)%1;}s=Math.min(s,front?.92:.55);const rgb=l=>{const c=(1-Math.abs(2*l-1))*s,x=c*(1-Math.abs(h*6%2-1)),m=l-c/2;const q=h<1/6?[c,x,0]:h<2/6?[x,c,0]:h<3/6?[0,c,x]:h<4/6?[0,x,c]:h<5/6?[x,0,c]:[c,0,x];return '#'+q.map(v=>Math.round((v+m)*255).toString(16).padStart(2,'0')).join('');};const target=front?4.6:2.9;if(front&&(lum('fffefb')+.05)/(lum(hex.slice(1))+.05)>=target)return hex;let lo=0,hi=1;for(let i=0;i<26;i++){let mid=(lo+hi)/2;if((lum('fffefb')+.05)/(lum(rgb(mid).slice(1))+.05)>target)lo=mid;else hi=mid;}return rgb((lo+hi)/2);}
|
| 11 |
+
for(const svg of document.querySelectorAll('.pareto-svg')){
|
| 12 |
+
const rows=data[svg.dataset.mode],front=rows.filter(a=>!rows.some(b=>b.cost<=a.cost&&b.score>=a.score&&(b.cost<a.cost||b.score>a.score))).sort((a,b)=>b.cost-a.cost),on=new Set(front.map(d=>d.key));
|
| 13 |
+
const lo=Math.min(...rows.map(d=>-Math.log10(d.cost)))-.30,hi=Math.max(...rows.map(d=>-Math.log10(d.cost)))+.30;
|
| 14 |
+
const x=c=>96+(-Math.log10(c)-lo)/(hi-lo)*1074,y=s=>473.2-s/.96*448;
|
| 15 |
+
const add=(tag,attrs,text)=>{const n=node(tag,attrs,text);svg.append(n);return n;};
|
| 16 |
+
add('rect',{x:0,y:0,width:1200,height:560,fill:'#fffefb'});
|
| 17 |
+
for(const t of [0,.24,.48,.72,.96]){add('line',{x1:96,x2:1170,y1:y(t),y2:y(t),class:'grid'});add('text',{x:84,y:y(t)+4,class:'tick','text-anchor':'end'},t.toFixed(2));}
|
| 18 |
+
for(const c of [100,50,20,10,5,2,1,.5,.2,.1,.05,.02,.01,.005,.002,.001])if(-Math.log10(c)>lo&&-Math.log10(c)<hi){add('line',{x1:x(c),x2:x(c),y1:25.2,y2:473.2,class:'grid vertical'});add('text',{x:x(c),y:499,class:'tick','text-anchor':'middle'},'$'+c);}
|
| 19 |
+
add('line',{x1:96,x2:1170,y1:473.2,y2:473.2,class:'axis'});
|
| 20 |
+
add('text',{x:633,y:539,class:'axis-title','text-anchor':'middle'},'Mean Cost per Case (USD) · cheaper →');
|
| 21 |
+
add('text',{x:27,y:249,transform:'rotate(-90 27 249)',class:'axis-title','text-anchor':'middle'},'Simulation Quality');
|
| 22 |
+
const path=front.map((d,i)=>(i?'L':'M')+x(d.cost)+','+y(d.score)).join(' ');
|
| 23 |
+
add('path',{d:path,class:'frontier-halo'});add('path',{d:path,class:'frontier-line'});
|
| 24 |
+
const points=rows.map(d=>({x:x(d.cost),y:y(d.score)}));const boxes=points.map(p=>[p.x-9,p.y-9,p.x+9,p.y+9]);
|
| 25 |
+
const linePoints=[];for(let i=1;i<front.length;i++){const a=front[i-1],b=front[i],n=Math.max(2,Math.ceil(Math.hypot(x(b.cost)-x(a.cost),y(b.score)-y(a.score))/5));for(let j=0;j<=n;j++)linePoints.push([x(a.cost)+(x(b.cost)-x(a.cost))*j/n,y(a.score)+(y(b.score)-y(a.score))*j/n]);}
|
| 26 |
+
for(const d of [...rows].sort((a,b)=>(on.has(b.key)-on.has(a.key))||b.score-a.score)){
|
| 27 |
+
const isFront=on.has(d.key),cx=x(d.cost),cy=y(d.score),font=isFront?16:12.5,name=d.name.replace(/^Claude /,'').replace(/\((.*?)\)/,(_,s)=>'('+s[0].toUpperCase()+s.slice(1)+')'),size=font;
|
| 28 |
+
measure.font=`${isFront?700:400} ${size}px Inter`;const tw=measure.measureText(name).width,th=size*.78,r=9,gap=5,pad=2.5,up=r+gap,dn=r+gap+th;
|
| 29 |
+
const candidates=[];for(let k=0;k<5;k++){const lift=k*th*1.55;candidates.push([0,-up-lift,'middle'],[0,dn+lift,'middle'],[r+gap,th*.4-lift,'start'],[-r-gap,th*.4-lift,'end'],[r+gap,th*.4+lift,'start'],[-r-gap,th*.4+lift,'end'],[r*.6,-up*.82-lift,'start'],[-r*.6,-up*.82-lift,'end'],[r*.6,dn*.9+lift,'start'],[-r*.6,dn*.9+lift,'end']);}
|
| 30 |
+
const hard=[...boxes,...linePoints.filter(p=>Math.hypot(p[0]-cx,p[1]-cy)>r*2.4).map(p=>[p[0]-4,p[1]-4,p[0]+4,p[1]+4])];let best,bestCost=Infinity;
|
| 31 |
+
for(let i=0;i<candidates.length;i++){const[dx,dy,anchor]=candidates[i],tx=cx+dx,ty=cy+dy,x0=anchor==='middle'?tx-tw/2:anchor==='end'?tx-tw:tx,b=[x0-pad,ty-th-pad,x0+tw+pad,ty+pad];let cost=i*.6;if(b[0]<58)cost+=400+58-b[0];if(b[2]>1180)cost+=400+b[2]-1180;if(b[1]<9)cost+=400+9-b[1];if(b[3]>475)cost+=400+b[3]-475;let overlap=0;for(const q of hard){const w=Math.min(b[2],q[2])-Math.max(b[0],q[0]),h=Math.min(b[3],q[3])-Math.max(b[1],q[1]);if(w>0&&h>0)overlap+=w*h;}cost+=overlap*4;if(cost<bestCost){bestCost=cost;best={dx,dy,anchor,b};}if(!overlap&&cost<400)break;}
|
| 32 |
+
boxes.push(best.b);const color=colors[d.logo]||'#686868',label=labelColor(color,isFront);
|
| 33 |
+
const g=add('g',{class:'pareto-node'+(isFront?' is-frontier':''),tabindex:0,role:'img','aria-label':`${d.name}, score ${d.score.toFixed(6)}, mean cost $${d.cost.toFixed(6)}${isFront?', Pareto frontier':''}`,'data-name':d.name,'data-score':d.score,'data-cost':d.cost,'data-frontier':isFront});
|
| 34 |
+
if(isFront)g.append(node('circle',{cx,cy,r:9,fill:'none',stroke:color,'stroke-width':1.3}));
|
| 35 |
+
g.append(node('rect',{x:cx-5,y:cy-5,width:10,height:10,rx:1,fill:color,stroke:'#fffefb','stroke-width':1.7,class:'chip'}));
|
| 36 |
+
g.append(node('text',{x:cx+best.dx,y:cy+best.dy,'text-anchor':best.anchor,fill:label,'font-size':font,'font-weight':isFront?700:400,class:'model-label'},name));
|
| 37 |
+
g.append(node('circle',{cx,cy,r:14,fill:'transparent'}));
|
| 38 |
+
const tip=document.querySelector('#pareto-tooltip')||Object.assign(document.body.appendChild(document.createElement('div')),{id:'pareto-tooltip',className:'pareto-tooltip'});
|
| 39 |
+
const show=()=>{tip.replaceChildren();const title=document.createElement('strong');title.textContent=d.name;tip.append(title);for(const text of [`Score: ${d.score.toFixed(6)}`,`Mean cost / case: $${d.cost.toFixed(6)}`,isFront?'Pareto frontier':'Dominated configuration']){const p=document.createElement('div');p.textContent=text;tip.append(p);}const rect=g.querySelector('.chip').getBoundingClientRect();tip.classList.add('on');tip.style.left=Math.max(8,Math.min(innerWidth-tip.offsetWidth-8,rect.x+rect.width/2-tip.offsetWidth/2))+'px';tip.style.top=(rect.y<tip.offsetHeight+16?rect.bottom+12:rect.y-tip.offsetHeight-12)+'px';svg.querySelectorAll('.pareto-node').forEach(n=>n.classList.toggle('dim',n!==g));};
|
| 40 |
+
const hide=()=>{tip.classList.remove('on');svg.querySelectorAll('.pareto-node').forEach(n=>n.classList.remove('dim'));};
|
| 41 |
+
g.addEventListener('mouseenter',show);g.addEventListener('focus',show);g.addEventListener('click',show);g.addEventListener('mouseleave',hide);g.addEventListener('blur',hide);window.addEventListener('scroll',hide,{passive:true});
|
| 42 |
+
}
|
| 43 |
+
svg.dataset.ready='true';
|
| 44 |
+
}
|
assets/scene-cards.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as THREE from "three";
|
| 2 |
+
import {GLTFLoader} from "three/addons/loaders/GLTFLoader.js";
|
| 3 |
+
import {MeshoptDecoder} from "three/addons/libs/meshopt_decoder.module.js";
|
| 4 |
+
import {Sky} from "three/addons/objects/Sky.js";
|
| 5 |
+
|
| 6 |
+
"use strict";
|
| 7 |
+
// The 3D engine: one shared WebGL renderer, one scene per loaded submission,
|
| 8 |
+
// and a Viewer per canvas that keeps the same interface the prototype's
|
| 9 |
+
// procedural viewer had (rotationX / rotationY / zoom / paused / group /
|
| 10 |
+
// draw(dt) / destroy()), so the page code above it did not have to change.
|
| 11 |
+
//
|
| 12 |
+
// Every mesh drawn here is the building.glb an agent handed in to the
|
| 13 |
+
// benchmark, re-encoded for the page (textures at most 512 px, JPEG for
|
| 14 |
+
// opaque maps) and gzipped. Geometry is untouched.
|
| 15 |
+
(function () {
|
| 16 |
+
const ADD = {GLTFLoader};
|
| 17 |
+
const activeViewers = new Set();
|
| 18 |
+
window.activeViewers = activeViewers;
|
| 19 |
+
let lastFrame = performance.now();
|
| 20 |
+
|
| 21 |
+
/* ------------------------------------------------------------ renderer */
|
| 22 |
+
let gl = null, ENV = null;
|
| 23 |
+
function renderer() {
|
| 24 |
+
if (gl) return gl;
|
| 25 |
+
gl = new THREE.WebGLRenderer({ antialias: true, alpha: true, premultipliedAlpha: true, powerPreference: "high-performance" });
|
| 26 |
+
gl.setPixelRatio(1);
|
| 27 |
+
gl.outputColorSpace = THREE.SRGBColorSpace;
|
| 28 |
+
gl.toneMapping = THREE.ACESFilmicToneMapping; gl.toneMappingExposure = 1.0;
|
| 29 |
+
gl.shadowMap.enabled = true;
|
| 30 |
+
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
| 31 |
+
gl.setClearColor(0x000000, 0);
|
| 32 |
+
const sky=new Sky();sky.scale.setScalar(1000);const u=sky.material.uniforms;u.turbidity.value=4;u.rayleigh.value=1.4;u.mieCoefficient.value=.004;u.mieDirectionalG.value=.8;u.sunPosition.value.setFromSphericalCoords(1,THREE.MathUtils.degToRad(52),THREE.MathUtils.degToRad(215));const skyScene=new THREE.Scene();skyScene.add(sky);ENV=new THREE.PMREMGenerator(gl).fromScene(skyScene,0,.1,2000).texture;
|
| 33 |
+
return gl;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
// The benchmark's own light rig (city_bench.building_light/1), the numbers
|
| 37 |
+
// the board's renders use: sun in the south-east at 50 degrees, a pale sky,
|
| 38 |
+
// and a muted environment. One rig for the page, moved into whichever scene
|
| 39 |
+
// is being drawn.
|
| 40 |
+
const RIG = (window.BB_DATA && window.BB_DATA.rig) || {};
|
| 41 |
+
const RIG_GROUP = new THREE.Group();
|
| 42 |
+
const SUN = new THREE.DirectionalLight(0xffffff, RIG.sun_intensity ?? 3.2);
|
| 43 |
+
SUN.color.setRGB(...(RIG.sun_colour || [1, 0.97, 0.92]));
|
| 44 |
+
SUN.castShadow = true;
|
| 45 |
+
SUN.shadow.mapSize.set(1024, 1024);
|
| 46 |
+
SUN.shadow.bias = -0.0006;
|
| 47 |
+
SUN.shadow.normalBias = 0.02;
|
| 48 |
+
const SKY = new THREE.HemisphereLight(0xbcd4f0, 0x6b6157, RIG.sky_intensity ?? 0.45);
|
| 49 |
+
SKY.color.setRGB(...(RIG.sky_colour || [0.7, 0.8, 0.94]));
|
| 50 |
+
SKY.groundColor.setRGB(...(RIG.ground_colour || [0.36, 0.34, 0.31]));
|
| 51 |
+
// A ground that shows only the shadow that lands on it, so the page's own
|
| 52 |
+
// background reads through everywhere else.
|
| 53 |
+
const GROUND = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.ShadowMaterial({ opacity: 0.22, transparent: true }));
|
| 54 |
+
GROUND.rotation.x = -Math.PI / 2;
|
| 55 |
+
GROUND.receiveShadow = true;
|
| 56 |
+
RIG_GROUP.add(SUN, SUN.target, SKY);
|
| 57 |
+
|
| 58 |
+
function rigFor(asset) {
|
| 59 |
+
const reach = Math.max(RIG.reach_m || 400, asset.radius * 1.6);
|
| 60 |
+
const az = THREE.MathUtils.degToRad(RIG.sun_azimuth_deg ?? 135), el = THREE.MathUtils.degToRad(RIG.sun_elevation_deg ?? 50);
|
| 61 |
+
SUN.position.set(Math.cos(el) * Math.sin(az), Math.sin(el), -Math.cos(el) * Math.cos(az)).multiplyScalar(reach).add(asset.centre);
|
| 62 |
+
SUN.target.position.copy(asset.centre);
|
| 63 |
+
const s = SUN.shadow.camera, r = asset.radius * 1.15;
|
| 64 |
+
s.left = -r; s.right = r; s.top = r; s.bottom = -r; s.near = 1; s.far = reach * 3;
|
| 65 |
+
s.updateProjectionMatrix();
|
| 66 |
+
GROUND.position.set(asset.centre.x, asset.floor, asset.centre.z);
|
| 67 |
+
GROUND.scale.set(asset.radius * 8, asset.radius * 8, 1);
|
| 68 |
+
asset.scene.add(RIG_GROUP);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* -------------------------------------------------------------- assets */
|
| 72 |
+
// BB_ASSETS maps a key to either a gzipped-base64 glb (the self-contained
|
| 73 |
+
// page) or an assets/… path (the split copy for hosting). Same bytes, one
|
| 74 |
+
// fetch earlier.
|
| 75 |
+
const ASSETS = window.BB_ASSETS || {};
|
| 76 |
+
const cache = new Map(); // key -> {promise, asset, refs, last}
|
| 77 |
+
const loader = new ADD.GLTFLoader().setMeshoptDecoder(MeshoptDecoder);
|
| 78 |
+
const gunzip = buf => new Response(new Blob([buf]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
| 79 |
+
const PACK_KEY = Uint8Array.from("5c2f9e71d3a84b06e1f7c29a38d05b64a7193ce8f2046db95e81c73a2df6904b".match(/../g), h => parseInt(h,16));
|
| 80 |
+
async function bytesFor(key) {
|
| 81 |
+
const r = await fetch(key); if (!r.ok) throw new Error("HTTP " + r.status);
|
| 82 |
+
const a = new Uint8Array(await r.arrayBuffer());
|
| 83 |
+
for (let i=0;i<a.length;i++) a[i] ^= PACK_KEY[i&31] ^ (((i>>>5)*131)&255);
|
| 84 |
+
return a.buffer;
|
| 85 |
+
}
|
| 86 |
+
function parse(buf) { return new Promise((resolve, reject) => loader.parse(buf, "", resolve, reject)); }
|
| 87 |
+
function acquire(key) {
|
| 88 |
+
let entry = cache.get(key);
|
| 89 |
+
if (!entry) {
|
| 90 |
+
entry = { refs: 0, last: performance.now(), asset: null };
|
| 91 |
+
// A dropped connection is not a bad file: one retry, and a failure leaves
|
| 92 |
+
// the cache so the next mount can try again.
|
| 93 |
+
const attempt = () => bytesFor(key).then(parse);
|
| 94 |
+
entry.promise = attempt().catch(() => new Promise(r => setTimeout(r, 1500)).then(attempt)).then(gltf => {
|
| 95 |
+
const root = gltf.scene;
|
| 96 |
+
root.traverse(node => { if (node.isMesh) { node.castShadow = true; node.receiveShadow = true; } });
|
| 97 |
+
const box = new THREE.Box3(), pts=[];
|
| 98 |
+
root.traverse(o=>{if(o.isMesh){const b=new THREE.Box3().setFromObject(o);if(!b.isEmpty())pts.push(b);for(const m of [].concat(o.material||[]))if(m.specularIntensity!==undefined)m.specularIntensity=Math.min(m.specularIntensity,.5);}});
|
| 99 |
+
const q=(arr,t)=>arr.slice().sort((a,b)=>a-b)[Math.floor(t*(arr.length-1))];
|
| 100 |
+
if(pts.length>8){const cx=pts.map(b=>(b.min.x+b.max.x)/2),cy=pts.map(b=>(b.min.y+b.max.y)/2),cz=pts.map(b=>(b.min.z+b.max.z)/2);box.set(new THREE.Vector3(q(cx,.03),q(cy,.03),q(cz,.03)),new THREE.Vector3(q(cx,.97),q(cy,.97),q(cz,.97)));}else box.setFromObject(root);
|
| 101 |
+
const centre = box.getCenter(new THREE.Vector3());
|
| 102 |
+
const size = box.getSize(new THREE.Vector3());
|
| 103 |
+
const corners = [];
|
| 104 |
+
for (const x of [box.min.x, box.max.x]) for (const y of [box.min.y, box.max.y]) for (const z of [box.min.z, box.max.z]) corners.push(new THREE.Vector3(x, y, z));
|
| 105 |
+
const scene = new THREE.Scene();
|
| 106 |
+
scene.environment = ENV || (renderer(), ENV);
|
| 107 |
+
scene.environmentIntensity = RIG.environment_intensity ?? 0.8;
|
| 108 |
+
scene.background = new THREE.Color(0xe6edf0); scene.add(root);
|
| 109 |
+
const task=window.SITE.cases.find(c=>c.track==='i2s'&&(c.input_glb===key||c.gt_glb===key||c.agents.some(a=>a.glb===key)));
|
| 110 |
+
if(task){root.updateMatrixWorld(true);root.traverse(o=>{const duplicate=(task.duplicates||[]).includes(o.name);if(!duplicate&&!(task.targets||[]).includes(o.name))return;const b=new THREE.Box3().setFromObject(o);if(b.isEmpty())return;const h=new THREE.Box3Helper(b.expandByScalar(.08),duplicate?0xff6b5e:0x5ee08a);h.material.depthTest=false;h.material.transparent=true;h.renderOrder=999;scene.add(h);});}
|
| 111 |
+
entry.asset = { key, root, scene, box, centre, corners, radius: Math.max(size.length() / 2, 1), floor: box.min.y };
|
| 112 |
+
return entry.asset;
|
| 113 |
+
});
|
| 114 |
+
entry.promise.catch(() => { if (cache.get(key) === entry) cache.delete(key); });
|
| 115 |
+
cache.set(key, entry);
|
| 116 |
+
}
|
| 117 |
+
entry.refs++; entry.last = performance.now();
|
| 118 |
+
return entry;
|
| 119 |
+
}
|
| 120 |
+
function release(entry) { if (!entry) return; entry.refs = Math.max(0, entry.refs - 1); entry.last = performance.now(); evict(); }
|
| 121 |
+
const KEEP = 40;
|
| 122 |
+
function evict() {
|
| 123 |
+
const idle = [...cache.values()].filter(e => e.refs === 0 && e.asset);
|
| 124 |
+
if (cache.size <= KEEP) return;
|
| 125 |
+
idle.sort((a, b) => a.last - b.last);
|
| 126 |
+
for (const e of idle) {
|
| 127 |
+
if (cache.size <= KEEP) break;
|
| 128 |
+
e.asset.root.traverse(n => {
|
| 129 |
+
if (!n.isMesh) return;
|
| 130 |
+
n.geometry?.dispose();
|
| 131 |
+
for (const m of [].concat(n.material || [])) { for (const s of ["map", "normalMap", "roughnessMap", "metalnessMap", "emissiveMap", "aoMap", "alphaMap"]) m[s]?.dispose(); m.dispose(); }
|
| 132 |
+
});
|
| 133 |
+
cache.delete(e.asset.key);
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/* -------------------------------------------------------------- viewer */
|
| 138 |
+
const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
|
| 139 |
+
const reduced = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
| 140 |
+
class Viewer {
|
| 141 |
+
constructor(canvas, options = {}) {
|
| 142 |
+
this.canvas = canvas;
|
| 143 |
+
this.ctx = canvas.getContext("2d", { alpha: true });
|
| 144 |
+
this.rotationY = options.rotationY ?? -0.65;
|
| 145 |
+
this.rotationX = options.rotationX ?? 0.35;
|
| 146 |
+
this.zoom = options.zoom ?? 1;
|
| 147 |
+
this.centerX = options.centerX ?? 0.5;
|
| 148 |
+
this.speed = options.speed ?? 0.22;
|
| 149 |
+
this.group = options.group || null;
|
| 150 |
+
this.refCam = options.refCam; this.paused = !!options.refCam; this.dragging = false; this.lastPointer = null;
|
| 151 |
+
this.destroyed = false; this.hasDrawn = false; this.failed = null;
|
| 152 |
+
this.initialRotation = [this.rotationX,this.rotationY];
|
| 153 |
+
this.camera = new THREE.PerspectiveCamera(36, 1, 0.1, 5000);
|
| 154 |
+
this.entry = null; this.asset = null;
|
| 155 |
+
this.bind();
|
| 156 |
+
activeViewers.add(this);
|
| 157 |
+
if (options.assetKey) this.load(options.assetKey);
|
| 158 |
+
}
|
| 159 |
+
load(key) {
|
| 160 |
+
release(this.entry);
|
| 161 |
+
this.entry = acquire(key); this.asset = null; this.failed = null;
|
| 162 |
+
const entry = this.entry;
|
| 163 |
+
entry.promise.then(asset => { if (this.entry === entry && !this.destroyed) { this.asset = asset; this.hasDrawn = false; } },
|
| 164 |
+
err => { if (this.entry === entry) { this.failed = err; console.error("Code4Scene: submission failed to load", key, err); } });
|
| 165 |
+
return entry.promise;
|
| 166 |
+
}
|
| 167 |
+
bind() {
|
| 168 |
+
this.onDown = e => { this.paused = true; this.dragging = true; this.lastPointer = [e.clientX, e.clientY]; this.canvas.setPointerCapture?.(e.pointerId); };
|
| 169 |
+
this.onMove = e => { if (!this.dragging) return; const dx = e.clientX - this.lastPointer[0], dy = e.clientY - this.lastPointer[1]; this.rotationY += dx * .012; this.rotationX = clamp(this.rotationX + dy * .008, -.05, 1.3); this.lastPointer = [e.clientX, e.clientY]; if (this.group) { this.group.rotationX = this.rotationX; this.group.rotationY = this.rotationY; } };
|
| 170 |
+
this.onUp = () => { this.dragging = false; this.lastPointer = null; };
|
| 171 |
+
this.onWheel = e => { e.preventDefault(); this.zoom = clamp(this.zoom - e.deltaY * .0007, .6, 2.2); if (this.group) this.group.zoom = this.zoom; };
|
| 172 |
+
this.onKey = e => { const keys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "+", "=", "-"]; if (!keys.includes(e.key)) return; e.preventDefault(); this.paused = true; if (e.key === "ArrowLeft") this.rotationY -= .12; if (e.key === "ArrowRight") this.rotationY += .12; if (e.key === "ArrowUp") this.rotationX = clamp(this.rotationX + .1, -.05, 1.3); if (e.key === "ArrowDown") this.rotationX = clamp(this.rotationX - .1, -.05, 1.3); if (e.key === "+" || e.key === "=") this.zoom = clamp(this.zoom + .08, .6, 2.2); if (e.key === "-") this.zoom = clamp(this.zoom - .08, .6, 2.2); if (this.group) Object.assign(this.group, { rotationX: this.rotationX, rotationY: this.rotationY, zoom: this.zoom, paused: true }); };
|
| 173 |
+
this.canvas.addEventListener("wheel", this.onWheel, { passive: false }); this.canvas.addEventListener("keydown", this.onKey);
|
| 174 |
+
this.canvas.addEventListener("pointerdown", this.onDown); this.canvas.addEventListener("pointermove", this.onMove); this.canvas.addEventListener("pointerup", this.onUp); this.canvas.addEventListener("pointercancel", this.onUp);
|
| 175 |
+
}
|
| 176 |
+
resize() {
|
| 177 |
+
const rect = this.canvas.getBoundingClientRect();
|
| 178 |
+
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
| 179 |
+
const w = Math.max(1, Math.round(rect.width * dpr)), h = Math.max(1, Math.round(rect.height * dpr));
|
| 180 |
+
if (this.canvas.width !== w || this.canvas.height !== h) { this.canvas.width = w; this.canvas.height = h; }
|
| 181 |
+
this.w = rect.width; this.h = rect.height; this.dpr = dpr;
|
| 182 |
+
}
|
| 183 |
+
// Orbit the model's centre. The distance is fitted to the bounding box
|
| 184 |
+
// seen from this direction, not to the sphere, so a wide flat building
|
| 185 |
+
// fills its card the way a tower does.
|
| 186 |
+
aim() {
|
| 187 |
+
const a = this.asset, cam = this.camera;
|
| 188 |
+
if(this.refCam){
|
| 189 |
+
const rc=this.refCam,target=new THREE.Vector3(...rc.target),offset=new THREE.Vector3(...rc.pos).sub(target);
|
| 190 |
+
const spherical=new THREE.Spherical().setFromVector3(offset);
|
| 191 |
+
spherical.theta += this.rotationY-this.initialRotation[1]; spherical.phi -= this.rotationX-this.initialRotation[0]; spherical.makeSafe(); spherical.radius /= this.zoom;
|
| 192 |
+
cam.aspect=this.w/this.h;cam.fov=2*Math.atan(Math.tan(rc.hfov*Math.PI/360)/cam.aspect)*180/Math.PI;
|
| 193 |
+
cam.near=.05;cam.far=Math.max(2000,a.radius*24);cam.position.copy(target).add(new THREE.Vector3().setFromSpherical(spherical));cam.lookAt(target);cam.updateProjectionMatrix();return;
|
| 194 |
+
}
|
| 195 |
+
const az = this.rotationY, el = this.rotationX;
|
| 196 |
+
const dir = new THREE.Vector3(Math.cos(el) * Math.sin(az), Math.sin(el), Math.cos(el) * Math.cos(az)).normalize();
|
| 197 |
+
const aspect = this.w / this.h;
|
| 198 |
+
cam.aspect = aspect; cam.fov = 34;
|
| 199 |
+
const vfov = THREE.MathUtils.degToRad(cam.fov), tanV = Math.tan(vfov / 2), tanH = tanV * aspect;
|
| 200 |
+
const probe = new THREE.Object3D();
|
| 201 |
+
probe.position.copy(a.centre).add(dir); probe.up.set(0, 1, 0); probe.lookAt(a.centre); probe.updateMatrixWorld();
|
| 202 |
+
const right = new THREE.Vector3().setFromMatrixColumn(probe.matrixWorld, 0);
|
| 203 |
+
const up = new THREE.Vector3().setFromMatrixColumn(probe.matrixWorld, 1);
|
| 204 |
+
let dist = 0;
|
| 205 |
+
for (const c of a.corners) { const q = c.clone().sub(a.centre); const z = q.dot(dir); dist = Math.max(dist, z + Math.abs(q.dot(right)) / tanH, z + Math.abs(q.dot(up)) / tanV); }
|
| 206 |
+
dist = Math.max(dist * 1.08, a.radius * 0.2) / this.zoom;
|
| 207 |
+
const target = a.centre.clone().addScaledVector(right, -(this.centerX - 0.5) * 2 * dist * tanH);
|
| 208 |
+
cam.near = Math.max(0.1, dist / 200); cam.far = Math.max(2000, dist * 20 + a.radius * 4);
|
| 209 |
+
cam.position.copy(target).addScaledVector(dir, dist);
|
| 210 |
+
cam.up.set(0, 1, 0); cam.lookAt(target); cam.updateProjectionMatrix();
|
| 211 |
+
}
|
| 212 |
+
draw(dt) {
|
| 213 |
+
if (this.destroyed || !this.canvas.isConnected) return;
|
| 214 |
+
const rect = this.canvas.getBoundingClientRect();
|
| 215 |
+
if (rect.width < 2 || rect.height < 2 || document.hidden) return;
|
| 216 |
+
if (rect.bottom < 0 || rect.top > window.innerHeight) return;
|
| 217 |
+
this.resize();
|
| 218 |
+
if (this.group) { this.rotationX = this.group.rotationX; this.rotationY = this.group.rotationY; this.zoom = this.group.zoom; }
|
| 219 |
+
if (!this.group && !this.paused && !this.dragging && !reduced()) this.rotationY += this.speed * dt;
|
| 220 |
+
const ctx = this.ctx, W = this.canvas.width, H = this.canvas.height;
|
| 221 |
+
if (!this.asset) {
|
| 222 |
+
if (this.hasDrawn) return;
|
| 223 |
+
ctx.clearRect(0, 0, W, H);
|
| 224 |
+
if (this.failed) { ctx.fillStyle = "#93673f"; ctx.font = `${Math.max(9, Math.round(10 * this.dpr))}px Arial`; ctx.textAlign = "center"; ctx.fillText("mesh unavailable", W / 2, H / 2); this.hasDrawn = true; }
|
| 225 |
+
return;
|
| 226 |
+
}
|
| 227 |
+
const g = renderer();
|
| 228 |
+
g.setSize(W, H, false);
|
| 229 |
+
this.aim();
|
| 230 |
+
rigFor(this.asset);
|
| 231 |
+
g.render(this.asset.scene, this.camera);
|
| 232 |
+
ctx.clearRect(0, 0, W, H);
|
| 233 |
+
ctx.drawImage(g.domElement, 0, 0, W, H, 0, 0, W, H);
|
| 234 |
+
this.hasDrawn = true; this.canvas.dataset.rendered="true"; this.canvas.parentElement.querySelector(".scene-loading")?.remove();
|
| 235 |
+
}
|
| 236 |
+
destroy() {
|
| 237 |
+
this.destroyed = true; activeViewers.delete(this);
|
| 238 |
+
release(this.entry); this.entry = null; this.asset = null;
|
| 239 |
+
this.canvas.removeEventListener("pointerdown", this.onDown); this.canvas.removeEventListener("pointermove", this.onMove); this.canvas.removeEventListener("pointerup", this.onUp); this.canvas.removeEventListener("pointercancel", this.onUp); this.canvas.removeEventListener("wheel", this.onWheel); this.canvas.removeEventListener("keydown", this.onKey);
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
window.GLBViewer = Viewer;
|
| 243 |
+
window.destroyViewersWithin = root => { activeViewers.forEach(v => { if (root.contains(v.canvas)) v.destroy(); }); };
|
| 244 |
+
window.BB_ENGINE = { cache, renderer, preload: key => acquire(key).promise.then(a => (release(cache.get(key)), a)) };
|
| 245 |
+
|
| 246 |
+
/* ------------------------------------------------------------- the clock */
|
| 247 |
+
function loop(now) {
|
| 248 |
+
requestAnimationFrame(loop);
|
| 249 |
+
if (now - lastFrame < 32) return;
|
| 250 |
+
const dt = Math.min(.05, (now - lastFrame) / 1000); lastFrame = now;
|
| 251 |
+
const groups = new Set([...activeViewers].filter(v => v.group && !v.destroyed).map(v => v.group));
|
| 252 |
+
if (!document.hidden && !reduced()) groups.forEach(g => { if (!g.paused && ![...activeViewers].some(v => v.group === g && v.dragging)) g.rotationY += dt * .14; });
|
| 253 |
+
activeViewers.forEach(v => { try { v.draw(dt); } catch (err) { v.failed = err; v.asset = null; console.error('Code4Scene: viewer draw failed', err); } });
|
| 254 |
+
}
|
| 255 |
+
requestAnimationFrame(loop);
|
| 256 |
+
})();
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
// Mount only near the viewport; repeated appearances share one decoded asset and WebGL renderer.
|
| 260 |
+
const observer=new IntersectionObserver(entries=>entries.forEach(entry=>{
|
| 261 |
+
if(!entry.isIntersecting)return;observer.unobserve(entry.target);
|
| 262 |
+
const el=entry.target,c=window.SITE.cases.find(c=>c.id===el.dataset.case),a=c.agents.find(a=>a.key===el.dataset.agent);
|
| 263 |
+
const viewer=new window.GLBViewer(el.querySelector('canvas'),{assetKey:a.glb,refCam:c.ref_cam,rotationX:.55,rotationY:-.62,speed:.1});
|
| 264 |
+
const loading=el.querySelector('.scene-loading');viewer.entry.promise.catch(()=>{if(loading)loading.textContent='Scene unavailable — open the case to retry.';});
|
| 265 |
+
const pause=el.querySelector('.scene-motion');if(c.ref_cam){pause.textContent='▶';pause.setAttribute('aria-label','Resume scene rotation');}
|
| 266 |
+
pause.addEventListener('click',()=>{viewer.paused=!viewer.paused;pause.textContent=viewer.paused?'▶':'Ⅱ';pause.setAttribute('aria-label',viewer.paused?'Resume scene rotation':'Pause scene rotation');});
|
| 267 |
+
el.querySelector('canvas').addEventListener('pointerdown',()=>{pause.textContent='▶';pause.setAttribute('aria-label','Resume scene rotation');});
|
| 268 |
+
el.parentElement.querySelectorAll('.scene-versions button').forEach(b=>b.addEventListener('click',()=>{
|
| 269 |
+
const url=b.dataset.state==='input'?c.input_glb:b.dataset.state==='gt'?c.gt_glb:a.glb;
|
| 270 |
+
el.parentElement.querySelectorAll('.scene-versions button').forEach(x=>x.classList.toggle('on',x===b));
|
| 271 |
+
const status=document.createElement('span');status.className='scene-loading';status.setAttribute('role','status');status.textContent='Loading '+b.textContent.toLowerCase()+'…';el.querySelector('.scene-loading')?.remove();el.append(status);
|
| 272 |
+
el.querySelector('canvas').dataset.rendered='false';el.querySelector('.scene-hint').textContent=b.textContent+' · Drag to orbit';
|
| 273 |
+
viewer.load(url).catch(()=>status.textContent='Scene unavailable — open the case to retry.');el.dataset.state=b.dataset.state;
|
| 274 |
+
}));
|
| 275 |
+
}),{rootMargin:'180px'});
|
| 276 |
+
document.querySelectorAll('.live-scene').forEach(el=>observer.observe(el));
|
cases.html
CHANGED
|
@@ -83,7 +83,7 @@ table.cs td,table.cs th{white-space:nowrap}.panel code{font-size:.82em;backgroun
|
|
| 83 |
.in-open:hover{background:var(--primary);color:#fff}
|
| 84 |
@media(max-width:900px){.in-i2s{grid-template-columns:1fr}}
|
| 85 |
</style><script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"}}</script><link href="assets/buildingbench.css?v=20261001" rel="stylesheet"/></head><body class="case-page"><a class="skip-link" href="#casebar">Skip to benchmark explorer</a>
|
| 86 |
-
<header class="site-header"><div class="brand"><a aria-label="Code4Scene home" class="brand-home" href="index.html#top"><svg aria-hidden="true" fill="none" viewbox="0 0 30 32"><path d="M15 2 27 9v14l-12 7L3 23V9L15 2Z M3 9l12 7 12-7 M15 16v14 M9 5.5l12 7v14 M21 5.5l-12 7v14" stroke="currentColor" stroke-linejoin="round" stroke-width="1.6"></path></svg><span>Code4Scene</span></a><a class="brand-by" href="https://simworld.org/">by SimWorld</a></div><nav aria-label="Main navigation"><a href="index.html#top">Benchmark</a><a href="index.html#leaderboard">Leaderboard</a><a class="nav-active" href="
|
| 87 |
<section class="alt" style="padding-top:34px;padding-bottom:40px"><div class="container">
|
| 88 |
<div class="section-header" style="margin-bottom:1.6rem"><span class="section-label">Cases</span><h2 class="section-title">Every scene in 3D, with its scores</h2>
|
| 89 |
<p class="section-desc">Each agent's result is the engine-native scene it saved, exported from Unreal Engine so you can turn it in the browser. Beside it, how the
|
|
|
|
| 83 |
.in-open:hover{background:var(--primary);color:#fff}
|
| 84 |
@media(max-width:900px){.in-i2s{grid-template-columns:1fr}}
|
| 85 |
</style><script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"}}</script><link href="assets/buildingbench.css?v=20261001" rel="stylesheet"/></head><body class="case-page"><a class="skip-link" href="#casebar">Skip to benchmark explorer</a>
|
| 86 |
+
<header class="site-header"><div class="brand"><a aria-label="Code4Scene home" class="brand-home" href="index.html#top"><svg aria-hidden="true" fill="none" viewbox="0 0 30 32"><path d="M15 2 27 9v14l-12 7L3 23V9L15 2Z M3 9l12 7 12-7 M15 16v14 M9 5.5l12 7v14 M21 5.5l-12 7v14" stroke="currentColor" stroke-linejoin="round" stroke-width="1.6"></path></svg><span>Code4Scene</span></a><a class="brand-by" href="https://simworld.org/">by SimWorld</a></div><nav aria-label="Main navigation"><a href="index.html#top">Benchmark</a><a href="index.html#leaderboard">Leaderboard</a><a class="nav-active" href="index.html#cases">Visualization</a><a href="https://arxiv.org/abs/2609.36777" rel="noopener" target="_blank">Paper ↗</a><a href="https://github.com/SimWorld-AI/Code4Scene" rel="noopener" target="_blank">Github ↗</a></nav></header>
|
| 87 |
<section class="alt" style="padding-top:34px;padding-bottom:40px"><div class="container">
|
| 88 |
<div class="section-header" style="margin-bottom:1.6rem"><span class="section-label">Cases</span><h2 class="section-title">Every scene in 3D, with its scores</h2>
|
| 89 |
<p class="section-desc">Each agent's result is the engine-native scene it saved, exported from Unreal Engine so you can turn it in the browser. Beside it, how the
|
data/pareto.json
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"overall": [
|
| 3 |
+
{
|
| 4 |
+
"key": "astra",
|
| 5 |
+
"name": "GPT-6 Astra (max)",
|
| 6 |
+
"logo": "openai",
|
| 7 |
+
"open": false,
|
| 8 |
+
"overall": 0.6193352866666667,
|
| 9 |
+
"t2s": 0.72382,
|
| 10 |
+
"i2s": 0.5148505733333334,
|
| 11 |
+
"indoor": 0.78546656,
|
| 12 |
+
"outdoor": 0.37954258,
|
| 13 |
+
"score": 0.6193352866666667,
|
| 14 |
+
"cost": 12.896991822966507
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"key": "gemini",
|
| 18 |
+
"name": "Gemini 3.8 Flash (high)",
|
| 19 |
+
"logo": "gemini",
|
| 20 |
+
"open": false,
|
| 21 |
+
"overall": 0.6189750266666667,
|
| 22 |
+
"t2s": 0.65689,
|
| 23 |
+
"i2s": 0.5810600533333334,
|
| 24 |
+
"indoor": 0.71653332,
|
| 25 |
+
"outdoor": 0.5133234200000001,
|
| 26 |
+
"score": 0.6189750266666667,
|
| 27 |
+
"cost": 1.9235185771258503
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"key": "fable",
|
| 31 |
+
"name": "Claude Fable 5.1 (max)",
|
| 32 |
+
"logo": "claude",
|
| 33 |
+
"open": false,
|
| 34 |
+
"overall": 0.60604898,
|
| 35 |
+
"t2s": 0.78775,
|
| 36 |
+
"i2s": 0.4243479600000001,
|
| 37 |
+
"indoor": 0.53523332,
|
| 38 |
+
"outdoor": 0.36890528000000006,
|
| 39 |
+
"score": 0.60604898,
|
| 40 |
+
"cost": 10.623258766403161
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"key": "opus",
|
| 44 |
+
"name": "Claude Opus 5 (max)",
|
| 45 |
+
"logo": "claude",
|
| 46 |
+
"open": false,
|
| 47 |
+
"overall": 0.5931299933333334,
|
| 48 |
+
"t2s": 0.7181599999999999,
|
| 49 |
+
"i2s": 0.46809998666666675,
|
| 50 |
+
"indoor": 0.61843384,
|
| 51 |
+
"outdoor": 0.39293306,
|
| 52 |
+
"score": 0.5931299933333334,
|
| 53 |
+
"cost": 19.47789116793412
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"key": "sol",
|
| 57 |
+
"name": "GPT-5.6 Sol (high)",
|
| 58 |
+
"logo": "openai",
|
| 59 |
+
"open": false,
|
| 60 |
+
"overall": 0.5499994666666667,
|
| 61 |
+
"t2s": 0.70704,
|
| 62 |
+
"i2s": 0.3929589333333333,
|
| 63 |
+
"indoor": 0.49742972,
|
| 64 |
+
"outdoor": 0.34072354,
|
| 65 |
+
"score": 0.5499994666666667,
|
| 66 |
+
"cost": 2.9749956842592593
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
"key": "muse",
|
| 70 |
+
"name": "Muse Spark 1.3 (medium)",
|
| 71 |
+
"logo": "meta",
|
| 72 |
+
"open": false,
|
| 73 |
+
"overall": 0.5022053666666666,
|
| 74 |
+
"t2s": 0.646195,
|
| 75 |
+
"i2s": 0.35821573333333334,
|
| 76 |
+
"indoor": 0.63253332,
|
| 77 |
+
"outdoor": 0.22105694,
|
| 78 |
+
"score": 0.5022053666666666,
|
| 79 |
+
"cost": 0.0861066423076923
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"key": "glm",
|
| 83 |
+
"name": "GLM-5.3 Flash (max)",
|
| 84 |
+
"logo": "zai",
|
| 85 |
+
"open": true,
|
| 86 |
+
"overall": 0.4147088666666666,
|
| 87 |
+
"t2s": 0.5094299999999999,
|
| 88 |
+
"i2s": 0.3199877333333333,
|
| 89 |
+
"indoor": 0.46533411999999996,
|
| 90 |
+
"outdoor": 0.24731454,
|
| 91 |
+
"score": 0.4147088666666666,
|
| 92 |
+
"cost": 0.40130584861111107
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"key": "qwen-off",
|
| 96 |
+
"name": "Qwen 3.8 27B (thinking off)",
|
| 97 |
+
"logo": "qwen",
|
| 98 |
+
"open": true,
|
| 99 |
+
"overall": 0.37818169333333335,
|
| 100 |
+
"t2s": 0.55666,
|
| 101 |
+
"i2s": 0.19970338666666668,
|
| 102 |
+
"indoor": 0.26629816,
|
| 103 |
+
"outdoor": 0.166406,
|
| 104 |
+
"score": 0.37818169333333335,
|
| 105 |
+
"cost": 0.38413493183103564
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"key": "grok",
|
| 109 |
+
"name": "Grok 4.6 (high)",
|
| 110 |
+
"logo": "grok",
|
| 111 |
+
"open": false,
|
| 112 |
+
"overall": 0.37567506,
|
| 113 |
+
"t2s": 0.56721,
|
| 114 |
+
"i2s": 0.18414012,
|
| 115 |
+
"indoor": 0.1968008,
|
| 116 |
+
"outdoor": 0.17780978,
|
| 117 |
+
"score": 0.37567506,
|
| 118 |
+
"cost": 2.2948689296296294
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"key": "qwen-on",
|
| 122 |
+
"name": "Qwen 3.8 27B (thinking on)",
|
| 123 |
+
"logo": "qwen",
|
| 124 |
+
"open": true,
|
| 125 |
+
"overall": 0.37094399333333333,
|
| 126 |
+
"t2s": 0.51571,
|
| 127 |
+
"i2s": 0.2261779866666667,
|
| 128 |
+
"indoor": 0.29651112,
|
| 129 |
+
"outdoor": 0.19101142,
|
| 130 |
+
"score": 0.37094399333333333,
|
| 131 |
+
"cost": 0.29748765575757574
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"key": "inkling",
|
| 135 |
+
"name": "Inkling (high)",
|
| 136 |
+
"logo": "thinkingmachines",
|
| 137 |
+
"open": false,
|
| 138 |
+
"overall": 0.31150237333333336,
|
| 139 |
+
"t2s": 0.42498500000000006,
|
| 140 |
+
"i2s": 0.19801974666666666,
|
| 141 |
+
"indoor": 0.1690288,
|
| 142 |
+
"outdoor": 0.21251522,
|
| 143 |
+
"score": 0.31150237333333336,
|
| 144 |
+
"cost": 0.4783280191269841
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"key": "gemma-on",
|
| 148 |
+
"name": "Gemma 4 31B (thinking on)",
|
| 149 |
+
"logo": "gemini",
|
| 150 |
+
"open": true,
|
| 151 |
+
"overall": 0.29812257999999997,
|
| 152 |
+
"t2s": 0.470705,
|
| 153 |
+
"i2s": 0.12554015999999998,
|
| 154 |
+
"indoor": 0.12704028,
|
| 155 |
+
"outdoor": 0.1247901,
|
| 156 |
+
"score": 0.29812257999999997,
|
| 157 |
+
"cost": 0.026867125396825398
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"key": "gemma-off",
|
| 161 |
+
"name": "Gemma 4 31B (thinking off)",
|
| 162 |
+
"logo": "gemini",
|
| 163 |
+
"open": true,
|
| 164 |
+
"overall": 0.28498897333333334,
|
| 165 |
+
"t2s": 0.45494,
|
| 166 |
+
"i2s": 0.11503794666666667,
|
| 167 |
+
"indoor": 0.11239600000000001,
|
| 168 |
+
"outdoor": 0.11635892,
|
| 169 |
+
"score": 0.28498897333333334,
|
| 170 |
+
"cost": 0.017148714965986397
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"key": "deepseek",
|
| 174 |
+
"name": "DeepSeek V4.1 Flash (high)",
|
| 175 |
+
"logo": "deepseek",
|
| 176 |
+
"open": true,
|
| 177 |
+
"overall": 0.22658958,
|
| 178 |
+
"t2s": 0.24269,
|
| 179 |
+
"i2s": 0.21048916,
|
| 180 |
+
"indoor": 0.18933412,
|
| 181 |
+
"outdoor": 0.22106668,
|
| 182 |
+
"score": 0.22658958,
|
| 183 |
+
"cost": 0.1240297601010101
|
| 184 |
+
}
|
| 185 |
+
],
|
| 186 |
+
"t2s": [
|
| 187 |
+
{
|
| 188 |
+
"key": "fable",
|
| 189 |
+
"name": "Claude Fable 5.1 (max)",
|
| 190 |
+
"logo": "claude",
|
| 191 |
+
"open": false,
|
| 192 |
+
"overall": 0.60604898,
|
| 193 |
+
"t2s": 0.78775,
|
| 194 |
+
"i2s": 0.4243479600000001,
|
| 195 |
+
"indoor": 0.53523332,
|
| 196 |
+
"outdoor": 0.36890528000000006,
|
| 197 |
+
"score": 0.78775,
|
| 198 |
+
"cost": 18.1576316
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"key": "astra",
|
| 202 |
+
"name": "GPT-6 Astra (max)",
|
| 203 |
+
"logo": "openai",
|
| 204 |
+
"open": false,
|
| 205 |
+
"overall": 0.6193352866666667,
|
| 206 |
+
"t2s": 0.72382,
|
| 207 |
+
"i2s": 0.5148505733333334,
|
| 208 |
+
"indoor": 0.78546656,
|
| 209 |
+
"outdoor": 0.37954258,
|
| 210 |
+
"score": 0.72382,
|
| 211 |
+
"cost": 22.472260736842106
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"key": "opus",
|
| 215 |
+
"name": "Claude Opus 5 (max)",
|
| 216 |
+
"logo": "claude",
|
| 217 |
+
"open": false,
|
| 218 |
+
"overall": 0.5931299933333334,
|
| 219 |
+
"t2s": 0.7181599999999999,
|
| 220 |
+
"i2s": 0.46809998666666675,
|
| 221 |
+
"indoor": 0.61843384,
|
| 222 |
+
"outdoor": 0.39293306,
|
| 223 |
+
"score": 0.7181599999999999,
|
| 224 |
+
"cost": 34.49611078947368
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"key": "sol",
|
| 228 |
+
"name": "GPT-5.6 Sol (high)",
|
| 229 |
+
"logo": "openai",
|
| 230 |
+
"open": false,
|
| 231 |
+
"overall": 0.5499994666666667,
|
| 232 |
+
"t2s": 0.70704,
|
| 233 |
+
"i2s": 0.3929589333333333,
|
| 234 |
+
"indoor": 0.49742972,
|
| 235 |
+
"outdoor": 0.34072354,
|
| 236 |
+
"score": 0.70704,
|
| 237 |
+
"cost": 4.07260365
|
| 238 |
+
},
|
| 239 |
+
{
|
| 240 |
+
"key": "gemini",
|
| 241 |
+
"name": "Gemini 3.8 Flash (high)",
|
| 242 |
+
"logo": "gemini",
|
| 243 |
+
"open": false,
|
| 244 |
+
"overall": 0.6189750266666667,
|
| 245 |
+
"t2s": 0.65689,
|
| 246 |
+
"i2s": 0.5810600533333334,
|
| 247 |
+
"indoor": 0.71653332,
|
| 248 |
+
"outdoor": 0.5133234200000001,
|
| 249 |
+
"score": 0.65689,
|
| 250 |
+
"cost": 2.49471265
|
| 251 |
+
},
|
| 252 |
+
{
|
| 253 |
+
"key": "muse",
|
| 254 |
+
"name": "Muse Spark 1.3 (medium)",
|
| 255 |
+
"logo": "meta",
|
| 256 |
+
"open": false,
|
| 257 |
+
"overall": 0.5022053666666666,
|
| 258 |
+
"t2s": 0.646195,
|
| 259 |
+
"i2s": 0.35821573333333334,
|
| 260 |
+
"indoor": 0.63253332,
|
| 261 |
+
"outdoor": 0.22105694,
|
| 262 |
+
"score": 0.646195,
|
| 263 |
+
"cost": 0.10048539999999999
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"key": "grok",
|
| 267 |
+
"name": "Grok 4.6 (high)",
|
| 268 |
+
"logo": "grok",
|
| 269 |
+
"open": false,
|
| 270 |
+
"overall": 0.37567506,
|
| 271 |
+
"t2s": 0.56721,
|
| 272 |
+
"i2s": 0.18414012,
|
| 273 |
+
"indoor": 0.1968008,
|
| 274 |
+
"outdoor": 0.17780978,
|
| 275 |
+
"score": 0.56721,
|
| 276 |
+
"cost": 4.326270533333333
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"key": "qwen-off",
|
| 280 |
+
"name": "Qwen 3.8 27B (thinking off)",
|
| 281 |
+
"logo": "qwen",
|
| 282 |
+
"open": true,
|
| 283 |
+
"overall": 0.37818169333333335,
|
| 284 |
+
"t2s": 0.55666,
|
| 285 |
+
"i2s": 0.19970338666666668,
|
| 286 |
+
"indoor": 0.26629816,
|
| 287 |
+
"outdoor": 0.166406,
|
| 288 |
+
"score": 0.55666,
|
| 289 |
+
"cost": 0.49154169999999997
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"key": "qwen-on",
|
| 293 |
+
"name": "Qwen 3.8 27B (thinking on)",
|
| 294 |
+
"logo": "qwen",
|
| 295 |
+
"open": true,
|
| 296 |
+
"overall": 0.37094399333333333,
|
| 297 |
+
"t2s": 0.51571,
|
| 298 |
+
"i2s": 0.2261779866666667,
|
| 299 |
+
"indoor": 0.29651112,
|
| 300 |
+
"outdoor": 0.19101142,
|
| 301 |
+
"score": 0.51571,
|
| 302 |
+
"cost": 0.3344125
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"key": "glm",
|
| 306 |
+
"name": "GLM-5.3 Flash (max)",
|
| 307 |
+
"logo": "zai",
|
| 308 |
+
"open": true,
|
| 309 |
+
"overall": 0.4147088666666666,
|
| 310 |
+
"t2s": 0.5094299999999999,
|
| 311 |
+
"i2s": 0.3199877333333333,
|
| 312 |
+
"indoor": 0.46533411999999996,
|
| 313 |
+
"outdoor": 0.24731454,
|
| 314 |
+
"score": 0.5094299999999999,
|
| 315 |
+
"cost": 0.710521125
|
| 316 |
+
},
|
| 317 |
+
{
|
| 318 |
+
"key": "gemma-on",
|
| 319 |
+
"name": "Gemma 4 31B (thinking on)",
|
| 320 |
+
"logo": "gemini",
|
| 321 |
+
"open": true,
|
| 322 |
+
"overall": 0.29812257999999997,
|
| 323 |
+
"t2s": 0.470705,
|
| 324 |
+
"i2s": 0.12554015999999998,
|
| 325 |
+
"indoor": 0.12704028,
|
| 326 |
+
"outdoor": 0.1247901,
|
| 327 |
+
"score": 0.470705,
|
| 328 |
+
"cost": 0.0253001
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"key": "gemma-off",
|
| 332 |
+
"name": "Gemma 4 31B (thinking off)",
|
| 333 |
+
"logo": "gemini",
|
| 334 |
+
"open": true,
|
| 335 |
+
"overall": 0.28498897333333334,
|
| 336 |
+
"t2s": 0.45494,
|
| 337 |
+
"i2s": 0.11503794666666667,
|
| 338 |
+
"indoor": 0.11239600000000001,
|
| 339 |
+
"outdoor": 0.11635892,
|
| 340 |
+
"score": 0.45494,
|
| 341 |
+
"cost": 0.0151612
|
| 342 |
+
},
|
| 343 |
+
{
|
| 344 |
+
"key": "inkling",
|
| 345 |
+
"name": "Inkling (high)",
|
| 346 |
+
"logo": "thinkingmachines",
|
| 347 |
+
"open": false,
|
| 348 |
+
"overall": 0.31150237333333336,
|
| 349 |
+
"t2s": 0.42498500000000006,
|
| 350 |
+
"i2s": 0.19801974666666666,
|
| 351 |
+
"indoor": 0.1690288,
|
| 352 |
+
"outdoor": 0.21251522,
|
| 353 |
+
"score": 0.42498500000000006,
|
| 354 |
+
"cost": 0.20252835
|
| 355 |
+
},
|
| 356 |
+
{
|
| 357 |
+
"key": "deepseek",
|
| 358 |
+
"name": "DeepSeek V4.1 Flash (high)",
|
| 359 |
+
"logo": "deepseek",
|
| 360 |
+
"open": true,
|
| 361 |
+
"overall": 0.22658958,
|
| 362 |
+
"t2s": 0.24269,
|
| 363 |
+
"i2s": 0.21048916,
|
| 364 |
+
"indoor": 0.18933412,
|
| 365 |
+
"outdoor": 0.22106668,
|
| 366 |
+
"score": 0.24269,
|
| 367 |
+
"cost": 0.193865
|
| 368 |
+
}
|
| 369 |
+
],
|
| 370 |
+
"i2s": [
|
| 371 |
+
{
|
| 372 |
+
"key": "gemini",
|
| 373 |
+
"name": "Gemini 3.8 Flash (high)",
|
| 374 |
+
"logo": "gemini",
|
| 375 |
+
"open": false,
|
| 376 |
+
"overall": 0.6189750266666667,
|
| 377 |
+
"t2s": 0.65689,
|
| 378 |
+
"i2s": 0.5810600533333334,
|
| 379 |
+
"indoor": 0.71653332,
|
| 380 |
+
"outdoor": 0.5133234200000001,
|
| 381 |
+
"score": 0.5810600533333334,
|
| 382 |
+
"cost": 1.3523245042517007
|
| 383 |
+
},
|
| 384 |
+
{
|
| 385 |
+
"key": "astra",
|
| 386 |
+
"name": "GPT-6 Astra (max)",
|
| 387 |
+
"logo": "openai",
|
| 388 |
+
"open": false,
|
| 389 |
+
"overall": 0.6193352866666667,
|
| 390 |
+
"t2s": 0.72382,
|
| 391 |
+
"i2s": 0.5148505733333334,
|
| 392 |
+
"indoor": 0.78546656,
|
| 393 |
+
"outdoor": 0.37954258,
|
| 394 |
+
"score": 0.5148505733333334,
|
| 395 |
+
"cost": 3.3217229090909095
|
| 396 |
+
},
|
| 397 |
+
{
|
| 398 |
+
"key": "opus",
|
| 399 |
+
"name": "Claude Opus 5 (max)",
|
| 400 |
+
"logo": "claude",
|
| 401 |
+
"open": false,
|
| 402 |
+
"overall": 0.5931299933333334,
|
| 403 |
+
"t2s": 0.7181599999999999,
|
| 404 |
+
"i2s": 0.46809998666666675,
|
| 405 |
+
"indoor": 0.61843384,
|
| 406 |
+
"outdoor": 0.39293306,
|
| 407 |
+
"score": 0.46809998666666675,
|
| 408 |
+
"cost": 4.459671546394558
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"key": "fable",
|
| 412 |
+
"name": "Claude Fable 5.1 (max)",
|
| 413 |
+
"logo": "claude",
|
| 414 |
+
"open": false,
|
| 415 |
+
"overall": 0.60604898,
|
| 416 |
+
"t2s": 0.78775,
|
| 417 |
+
"i2s": 0.4243479600000001,
|
| 418 |
+
"indoor": 0.53523332,
|
| 419 |
+
"outdoor": 0.36890528000000006,
|
| 420 |
+
"score": 0.4243479600000001,
|
| 421 |
+
"cost": 3.0888859328063245
|
| 422 |
+
},
|
| 423 |
+
{
|
| 424 |
+
"key": "sol",
|
| 425 |
+
"name": "GPT-5.6 Sol (high)",
|
| 426 |
+
"logo": "openai",
|
| 427 |
+
"open": false,
|
| 428 |
+
"overall": 0.5499994666666667,
|
| 429 |
+
"t2s": 0.70704,
|
| 430 |
+
"i2s": 0.3929589333333333,
|
| 431 |
+
"indoor": 0.49742972,
|
| 432 |
+
"outdoor": 0.34072354,
|
| 433 |
+
"score": 0.3929589333333333,
|
| 434 |
+
"cost": 1.8773877185185188
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"key": "muse",
|
| 438 |
+
"name": "Muse Spark 1.3 (medium)",
|
| 439 |
+
"logo": "meta",
|
| 440 |
+
"open": false,
|
| 441 |
+
"overall": 0.5022053666666666,
|
| 442 |
+
"t2s": 0.646195,
|
| 443 |
+
"i2s": 0.35821573333333334,
|
| 444 |
+
"indoor": 0.63253332,
|
| 445 |
+
"outdoor": 0.22105694,
|
| 446 |
+
"score": 0.35821573333333334,
|
| 447 |
+
"cost": 0.07172788461538461
|
| 448 |
+
},
|
| 449 |
+
{
|
| 450 |
+
"key": "glm",
|
| 451 |
+
"name": "GLM-5.3 Flash (max)",
|
| 452 |
+
"logo": "zai",
|
| 453 |
+
"open": true,
|
| 454 |
+
"overall": 0.4147088666666666,
|
| 455 |
+
"t2s": 0.5094299999999999,
|
| 456 |
+
"i2s": 0.3199877333333333,
|
| 457 |
+
"indoor": 0.46533411999999996,
|
| 458 |
+
"outdoor": 0.24731454,
|
| 459 |
+
"score": 0.3199877333333333,
|
| 460 |
+
"cost": 0.09209057222222222
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"key": "qwen-on",
|
| 464 |
+
"name": "Qwen 3.8 27B (thinking on)",
|
| 465 |
+
"logo": "qwen",
|
| 466 |
+
"open": true,
|
| 467 |
+
"overall": 0.37094399333333333,
|
| 468 |
+
"t2s": 0.51571,
|
| 469 |
+
"i2s": 0.2261779866666667,
|
| 470 |
+
"indoor": 0.29651112,
|
| 471 |
+
"outdoor": 0.19101142,
|
| 472 |
+
"score": 0.2261779866666667,
|
| 473 |
+
"cost": 0.2605628115151515
|
| 474 |
+
},
|
| 475 |
+
{
|
| 476 |
+
"key": "deepseek",
|
| 477 |
+
"name": "DeepSeek V4.1 Flash (high)",
|
| 478 |
+
"logo": "deepseek",
|
| 479 |
+
"open": true,
|
| 480 |
+
"overall": 0.22658958,
|
| 481 |
+
"t2s": 0.24269,
|
| 482 |
+
"i2s": 0.21048916,
|
| 483 |
+
"indoor": 0.18933412,
|
| 484 |
+
"outdoor": 0.22106668,
|
| 485 |
+
"score": 0.21048916,
|
| 486 |
+
"cost": 0.054194520202020195
|
| 487 |
+
},
|
| 488 |
+
{
|
| 489 |
+
"key": "qwen-off",
|
| 490 |
+
"name": "Qwen 3.8 27B (thinking off)",
|
| 491 |
+
"logo": "qwen",
|
| 492 |
+
"open": true,
|
| 493 |
+
"overall": 0.37818169333333335,
|
| 494 |
+
"t2s": 0.55666,
|
| 495 |
+
"i2s": 0.19970338666666668,
|
| 496 |
+
"indoor": 0.26629816,
|
| 497 |
+
"outdoor": 0.166406,
|
| 498 |
+
"score": 0.19970338666666668,
|
| 499 |
+
"cost": 0.27672816366207137
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"key": "inkling",
|
| 503 |
+
"name": "Inkling (high)",
|
| 504 |
+
"logo": "thinkingmachines",
|
| 505 |
+
"open": false,
|
| 506 |
+
"overall": 0.31150237333333336,
|
| 507 |
+
"t2s": 0.42498500000000006,
|
| 508 |
+
"i2s": 0.19801974666666666,
|
| 509 |
+
"indoor": 0.1690288,
|
| 510 |
+
"outdoor": 0.21251522,
|
| 511 |
+
"score": 0.19801974666666666,
|
| 512 |
+
"cost": 0.7541276882539681
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"key": "grok",
|
| 516 |
+
"name": "Grok 4.6 (high)",
|
| 517 |
+
"logo": "grok",
|
| 518 |
+
"open": false,
|
| 519 |
+
"overall": 0.37567506,
|
| 520 |
+
"t2s": 0.56721,
|
| 521 |
+
"i2s": 0.18414012,
|
| 522 |
+
"indoor": 0.1968008,
|
| 523 |
+
"outdoor": 0.17780978,
|
| 524 |
+
"score": 0.18414012,
|
| 525 |
+
"cost": 0.2634673259259259
|
| 526 |
+
},
|
| 527 |
+
{
|
| 528 |
+
"key": "gemma-on",
|
| 529 |
+
"name": "Gemma 4 31B (thinking on)",
|
| 530 |
+
"logo": "gemini",
|
| 531 |
+
"open": true,
|
| 532 |
+
"overall": 0.29812257999999997,
|
| 533 |
+
"t2s": 0.470705,
|
| 534 |
+
"i2s": 0.12554015999999998,
|
| 535 |
+
"indoor": 0.12704028,
|
| 536 |
+
"outdoor": 0.1247901,
|
| 537 |
+
"score": 0.12554015999999998,
|
| 538 |
+
"cost": 0.028434150793650796
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"key": "gemma-off",
|
| 542 |
+
"name": "Gemma 4 31B (thinking off)",
|
| 543 |
+
"logo": "gemini",
|
| 544 |
+
"open": true,
|
| 545 |
+
"overall": 0.28498897333333334,
|
| 546 |
+
"t2s": 0.45494,
|
| 547 |
+
"i2s": 0.11503794666666667,
|
| 548 |
+
"indoor": 0.11239600000000001,
|
| 549 |
+
"outdoor": 0.11635892,
|
| 550 |
+
"score": 0.11503794666666667,
|
| 551 |
+
"cost": 0.01913622993197279
|
| 552 |
+
}
|
| 553 |
+
]
|
| 554 |
+
}
|
index.html
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|