Add release-date fit controls to root WVS map

Co-Authored-By: PI[gpt-5.6-terra] <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
wassname
2026-09-17 13:59:58 +08:00
co-authored by PI[gpt-5.6-terra]
parent 25e2543af5
commit da2e70f3bb
22 changed files with 184 additions and 94 deletions
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
:root{--ink:#333;--muted:#8a857a;--rule:#eceadf;--canvas:#faf8f2}*{box-sizing:border-box}body{background:var(--canvas);color:var(--ink);margin:0;font:16px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}main{max-width:1200px;margin:auto;padding:1.5rem 1rem 3rem}h1{margin:0 0 .35rem;font-size:1.65rem;line-height:1.2}.lede{color:#59544b;max-width:75ch}.controls{flex-wrap:wrap;gap:.35rem;margin:1rem 0;display:flex}.chip{color:var(--ink);cursor:pointer;background:#fff;border:1px solid #d9d5ca;border-radius:999px;align-items:center;gap:.3rem;padding:.22rem .48rem;font:600 .78rem/1 inherit;display:flex}.chip img{width:13px;height:13px}.chip:hover{border-color:#8a857a}.chip:focus-visible,.model-mark:focus-visible{outline-offset:2px;outline:2px solid #2563eb}.chip[aria-pressed=false]{color:#8a857a;background:#f6f4ef;text-decoration:line-through}.chip[aria-pressed=false] img{opacity:.3}.chart-shell{position:relative}.chart-shell svg{background:var(--canvas);border:1px solid #ded9cc;width:100%;height:auto;display:block}.canvas{fill:var(--canvas)}.grid line{stroke:var(--rule);stroke-width:.7px}.median{stroke:#c9c4b4;stroke-width:1.2px}.zone{fill:none;stroke-width:2px;opacity:.9}.country{stroke:#fff;stroke-width:.7px;opacity:.88}.country-label,.model-label,.zone-label,.poles text{paint-order:stroke;stroke:var(--canvas);stroke-width:4px;stroke-linejoin:round}.country-label{fill:#222;font-size:11px}.model-ring{fill:#fff;stroke-width:2px}.model-mark{cursor:default}.model-mark:focus{outline:none}.model-label{fill:#222;font-size:13px;font-weight:700}.leader{stroke:#aaa398;stroke-width:1px}.zone-label{font-size:15px;font-style:italic;font-weight:700}.poles line{stroke:#999;stroke-width:1.8px}.arrow{fill:#999}.poles text{fill:#555;font-size:18px;font-weight:700}.map-title{fill:#333;font-size:14px;font-weight:700}.map-note{fill:var(--muted);font-size:10px}.release-panels{grid-template-columns:1fr;gap:1rem;margin-top:1.5rem;display:grid}.release-panel{border-top:1px solid #ded9cc;padding-top:1rem}.release-panel h2{margin:0;font-size:1rem}.release-panel p{color:#756f64;margin:.2rem 0 .5rem;font-size:.82rem}.scatter-shell{position:relative}.scatter-shell svg{background:var(--canvas);border:1px solid #ded9cc;width:100%;height:auto;display:block}.scatter-grid line{stroke:var(--rule);stroke-width:.7px}.scatter-axis{stroke:#aaa398;stroke-width:1px}.scatter-tick{fill:#756f64;font-size:11px}.release-mark{cursor:default}.release-mark:focus{outline:none}.tooltip{z-index:2;pointer-events:none;background:#fffffff7;border:1px solid #ddd7ca;border-radius:5px;max-width:275px;padding:.45rem .6rem;font-size:.82rem;line-height:1.35;position:absolute;transform:translate(14px,14px);box-shadow:0 2px 8px #0002}.tooltip strong,.tooltip span{display:block}.tooltip span{color:#5b554b}@media (width<=700px){main{padding:.9rem .5rem 2rem}.chip{font-size:.7rem}.poles text{font-size:14px}.country-label,.model-label{font-size:10px}.tooltip{max-width:230px;font-size:.75rem}}
+1
View File
@@ -0,0 +1 @@
:root{--ink:#333;--muted:#8a857a;--rule:#eceadf;--canvas:#faf8f2}*{box-sizing:border-box}body{background:var(--canvas);color:var(--ink);margin:0;font:16px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}main{max-width:1200px;margin:auto;padding:1.5rem 1rem 3rem}h1{margin:0 0 .35rem;font-size:1.65rem;line-height:1.2}.lede{color:#59544b;max-width:75ch}.controls{flex-wrap:wrap;gap:.35rem;margin:1rem 0;display:flex}.chip{color:var(--ink);cursor:pointer;background:#fff;border:1px solid #d9d5ca;border-radius:999px;align-items:center;gap:.3rem;padding:.22rem .48rem;font:600 .78rem/1 inherit;display:flex}.chip img{width:13px;height:13px}.chip:hover{border-color:#8a857a}.chip:focus-visible,.model-mark:focus-visible{outline-offset:2px;outline:2px solid #2563eb}.chip[aria-pressed=false]{color:#8a857a;background:#f6f4ef;text-decoration:line-through}.chip[aria-pressed=false] img{opacity:.3}.chart-shell{position:relative}.chart-shell svg{background:var(--canvas);border:1px solid #ded9cc;width:100%;height:auto;display:block}.canvas{fill:var(--canvas)}.grid line{stroke:var(--rule);stroke-width:.7px}.median{stroke:#c9c4b4;stroke-width:1.2px}.zone{fill:none;stroke-width:2px;opacity:.9}.country{stroke:#fff;stroke-width:.7px;opacity:.88}.country-label,.model-label,.zone-label,.poles text{paint-order:stroke;stroke:var(--canvas);stroke-width:4px;stroke-linejoin:round}.country-label{fill:#222;font-size:11px}.model-ring{fill:#fff;stroke-width:1.3px}.model-mark{cursor:default}.model-mark:focus{outline:none}.model-label{fill:#222;font-size:13px;font-weight:700}.leader{stroke:#aaa398;stroke-width:1px}.zone-label{font-size:15px;font-style:italic;font-weight:700}.poles line{stroke:#999;stroke-width:1.8px}.arrow{fill:#999}.poles text{fill:#555;font-size:18px;font-weight:700}.map-title{fill:#333;font-size:14px;font-weight:700}.map-note{fill:var(--muted);font-size:10px}.release-panels{grid-template-columns:1fr;gap:1rem;margin-top:1.5rem;display:grid}.release-panel{border-top:1px solid #ded9cc;padding-top:1rem}.release-panel h2{margin:0;font-size:1rem}.release-panel p{color:#756f64;margin:.2rem 0 .5rem;font-size:.82rem}.scatter-shell{position:relative}.scatter-shell svg{background:var(--canvas);border:1px solid #ded9cc;width:100%;height:auto;display:block}.scatter-grid line{stroke:var(--rule);stroke-width:.7px}.scatter-axis{stroke:#aaa398;stroke-width:1px}.scatter-arrow{fill:#aaa398}.scatter-y-label{fill:#555;font-size:12px;font-weight:700}.scatter-tick{fill:#756f64;font-size:11px}.release-fit line{stroke:#56514a;stroke-width:1.4px;stroke-dasharray:4 3}.release-fit text,.release-fit-unavailable{fill:#56514a;font-size:11px;font-weight:700}.release-mark{cursor:default}.release-mark:focus{outline:none}.tooltip{z-index:2;pointer-events:none;background:#fffffff7;border:1px solid #ddd7ca;border-radius:5px;max-width:275px;padding:.45rem .6rem;font-size:.82rem;line-height:1.35;position:absolute;transform:translate(14px,14px);box-shadow:0 2px 8px #0002}.tooltip strong,.tooltip span{display:block}.tooltip span{color:#5b554b}@media (width<=700px){main{padding:.9rem .5rem 2rem}.chip{font-size:.7rem}.poles text{font-size:14px}.country-label,.model-label{font-size:10px}.tooltip{max-width:230px;font-size:.75rem}}
+2 -2
View File
@@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frontier LLMs on the World Values Survey</title>
<script type="module" crossorigin src="./assets/index-CpA1DfjE.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-Ctfw88gw.css">
<script type="module" crossorigin src="./assets/index-Co4wqFEb.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CyPTsa3p.css">
</head>
<body>
<div id="root"></div>
+12 -42
View File
@@ -1,43 +1,13 @@
<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Frontier LLMs on the World Values Survey</title>
<style>
body { margin: 0; background: #faf8f2; color: #292524; font: 16px system-ui, sans-serif; }
main { max-width: 1100px; margin: auto; padding: 1rem; } h1 { margin: .2rem 0; } p { max-width: 78ch; }
#controls { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1rem 0; }
button { border: 2px solid var(--color); border-radius: 1rem; padding: .3rem .7rem; background: var(--color); color: white; cursor: pointer; font-weight: 600; }
button.off { background: white; color: #292524; opacity: .5; text-decoration: line-through; }
svg { width: 100%; height: auto; background: #faf8f2; border: 1px solid #292524; }
.zone { fill: none; stroke: #94a3b8; stroke-width: 2; stroke-dasharray: 5 3; } .country { fill: #64748b; stroke: white; stroke-width: .6; }
.star { stroke: white; stroke-width: 1; } .zone-label { font-weight: 700; font-style: italic; fill: #475569; }
</style>
<main>
<h1>Frontier LLMs on the World Values Survey</h1>
<p>Rated sampling, 12 items x 12 samples for new points. Filled chips are visible; an outlined, struck-through chip hides that familys stars. Each chip carries the familys latest-release name. Grey dots are WVS countries, coloured stars are models, and dashed hulls are cultural regions. Coordinates, labels, family membership and colours come from <code>wvs_map_data.json</code>, the generated artifact shared with the static map.</p>
<p><a href="react/">Try the matching React/SVG renderer.</a></p>
<div id="controls" aria-label="Model family visibility"></div>
<svg id="map" viewBox="0 0 1000 720" role="img" aria-label="WVS map of model and country coordinates"></svg>
<p>Historical coordinates are recovered rounded display values. Coder and vision-language Qwen variants are visible but are specialized variants, not direct-instruct size-trend evidence. See the repository CI table and request ledger for sample and protocol evidence.</p>
</main>
<script>
const NS = 'http://www.w3.org/2000/svg';
const el = (tag, attrs = {}, text) => { const node = document.createElementNS(NS, tag); for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, value); if (text) node.textContent = text; return node; };
const hull = pts => { const p = [...pts].sort((a,b) => a.x-b.x || a.y-b.y); const cross = (o,a,b) => (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x); const half = a => { const out=[]; for (const x of a) { while (out.length > 1 && cross(out.at(-2),out.at(-1),x) <= 0) out.pop(); out.push(x); } return out; }; return [...half(p), ...half([...p].reverse()).slice(1,-1)]; };
fetch('wvs_map_data.json').then(r => { if (!r.ok) throw new Error(`data: ${r.status}`); return r.json(); }).then(data => {
const svg = document.querySelector('#map'), margin = 70, all = [...data.countries, ...data.models];
const minX=Math.min(...all.map(p=>p.x)), maxX=Math.max(...all.map(p=>p.x)), minY=Math.min(...all.map(p=>p.y)), maxY=Math.max(...all.map(p=>p.y));
const x=v=>margin+(v-minX)/(maxX-minX)*(1000-2*margin), y=v=>720-margin-(v-minY)/(maxY-minY)*(720-2*margin);
svg.append(el('line',{x1:margin,y1:y((minY+maxY)/2),x2:1000-margin,y2:y((minY+maxY)/2),class:'axis'})); svg.append(el('line',{x1:x((minX+maxX)/2),y1:margin,x2:x((minX+maxX)/2),y2:720-margin,class:'axis'}));
for (const [name,members] of Object.entries(data.zones)) { const points=data.countries.filter(p=>members.includes(p.name)); if(points.length<3) continue; const h=hull(points); svg.append(el('polygon',{points:h.map(p=>`${x(p.x)},${y(p.y)}`).join(' '),class:'zone'})); const c=h.reduce((sum,p)=>({x:sum.x+p.x/h.length,y:sum.y+p.y/h.length}),{x:0,y:0}); svg.append(el('text',{x:x(c.x),y:y(c.y),class:'zone-label','text-anchor':'middle'},name)); }
for (const p of data.countries) { const c=el('circle',{cx:x(p.x),cy:y(p.y),r:3,class:'country'}); c.append(el('title',{},p.name)); svg.append(c); }
const groups=new Map(); for(const p of data.models) groups.set(p.family,[...(groups.get(p.family)||[]),p]); const hidden=new Set(new URLSearchParams(location.search).get('hide')?.split(',').filter(Boolean));
for (const [family,points] of groups) { const group=el('g',{'data-family':family}); for(const p of points) { const star=el('path',{d:`M ${x(p.x)} ${y(p.y)-8} L ${x(p.x)+2.4} ${y(p.y)-2.4} L ${x(p.x)+8} ${y(p.y)-2.4} L ${x(p.x)+3.6} ${y(p.y)+1.6} L ${x(p.x)+5.2} ${y(p.y)+7} L ${x(p.x)} ${y(p.y)+4} L ${x(p.x)-5.2} ${y(p.y)+7} L ${x(p.x)-3.6} ${y(p.y)+1.6} L ${x(p.x)-8} ${y(p.y)-2.4} L ${x(p.x)-2.4} ${y(p.y)-2.4} Z`,fill:p.color,class:'star'}); star.append(el('title',{},p.name)); group.append(star); } svg.append(group);
const latest=points.find(p=>p.label)?.label ?? points[0].name, button=document.createElement('button'); button.textContent=`${family}: ${latest}`; button.style.setProperty('--color',points[0].color);
const labelOffsets={grok:{dx:-72,dy:-30},muse:{dx:12,dy:-11},mistral:{dx:-96,dy:-26},llama:{dx:-96,dy:12}};
for (const p of points.filter(p=>p.label)) { const {dx,dy}=labelOffsets[family]??{dx:11,dy:-11}; group.append(el('line',{x1:x(p.x),y1:y(p.y),x2:x(p.x)+dx*.82,y2:y(p.y)+dy*.82,stroke:p.color,'stroke-width':1})); group.append(el('text',{x:x(p.x)+dx,y:y(p.y)+dy,fill:p.color,'font-size':10,'font-weight':700},p.label)); }
let visible = !hidden.has(family); const setVisible=on=>{visible=on;group.setAttribute('display',on?'inline':'none');button.classList.toggle('off',!on);button.setAttribute('aria-pressed',String(on));}; setVisible(visible); button.onclick=()=>setVisible(!visible); document.querySelector('#controls').append(button);
}
for(const [text,px,py,anchor] of [[data.axis.x[0],margin,690,'start'],[data.axis.x[1],1000-margin,690,'end'],[data.axis.y[0],500,700,'middle'],[data.axis.y[1],500,28,'middle']]) svg.append(el('text',{x:px,y:py,'text-anchor':anchor,fill:'#57534e','font-weight':700},text));
}).catch(error=>{document.body.append(`Could not load map data: ${error.message}`);});
</script>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="0; url=../">
<link rel="canonical" href="../">
<title>Frontier LLMs on the World Values Survey</title>
</head>
<body>
<p>The WVS map moved to <a href="../">the site root</a>.</p>
</body>
</html>