import {bindChartTooltip} from "./chart-interactions.js?v=20261004kit"; // Adapted from BuildingBench's figure-kit/pareto-frontier/render.py and live SVG. // Domain, costs and scores are exclusively Code4Scene's historical paper evaluation. const NS='http://www.w3.org/2000/svg'; const colors={openai:'#10A37F',claude:'#D97757',gemini:'#7b1fa2',meta:'#42a5f5',deepseek:'#3f51e0',zai:'#96650b',grok:'#111111',qwen:'#fe7016',thinkingmachines:'#686868'}; const data=await fetch('data/pareto.json?v=20261001b').then(r=>r.json()); await Promise.all([document.fonts.load('400 13px Inter'),document.fonts.load('700 16px Inter')]); const measure=document.createElement('canvas').getContext('2d'); 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;} 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];}; 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);} for(const svg of document.querySelectorAll('.pareto-svg')){ const rows=data[svg.dataset.mode],front=rows.filter(a=>!rows.some(b=>b.cost<=a.cost&&b.score>=a.score&&(b.costa.score))).sort((a,b)=>b.cost-a.cost),on=new Set(front.map(d=>d.key)); const lo=Math.min(...rows.map(d=>-Math.log10(d.cost)))-.30,hi=Math.max(...rows.map(d=>-Math.log10(d.cost)))+.30; const x=c=>96+(-Math.log10(c)-lo)/(hi-lo)*1074,y=s=>473.2-s/.96*448; const add=(tag,attrs,text)=>{const n=node(tag,attrs,text);svg.append(n);return n;}; add('rect',{x:0,y:0,width:1200,height:560,fill:'#fffefb'}); 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));} 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)(i?'L':'M')+x(d.cost)+','+y(d.score)).join(' '); add('path',{d:path,class:'frontier-halo'});add('path',{d:path,class:'frontier-line'}); 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]); const linePoints=[];for(let i=1;i(on.has(b.key)-on.has(a.key))||b.score-a.score)){ 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.replace(/\b\w/g,c=>c.toUpperCase())+')'),size=font; 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; 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']);} 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; for(let i=0;i1180)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