// Snapped Labels, "Voxel exact" tab: per-scroll claim levels (Measured, Certified, Not shown), tolerance bars, abstain
// strata, residual histograms and controls, read from vx/summary.json (schema snapped-labels/voxel-exact@1, checked by
// python -m kit vxsummary check). ?vx=URL reads another summary; ?vx=fixture reads the synthetic fixture, always under a
// banner. The tab stays hidden until a summary loads and validates. Loaded after app.js and uses its helpers.
'use strict';
const VX = { doc: null, url: null, fixture: false, show: null, showIdx: 0, mode: 'signed', pick: {} };
const VX_SCHEMA = 'snapped-labels/voxel-exact@1';
const VX_CLAIMS = { measured: 'Measured', certified: 'Certified', not_shown: 'Not shown' };
const VX_ORDER = { measured: 0, certified: 1, not_shown: 2 };
const VX_TOLS = ['0.5', '1', '2'];
// a verdict is text plus a shape, never color alone
const VX_ICON = { PASS: '✓', FAIL: '✕', 'NOT SHOWN': '○', UNANSWERABLE: '?', VOID: '⊘' };
const VX_STRATUM_NAME = { C0: 'snapped (code 0)', C0L: 'snapped, placed in the label scan (code 0)', C2: 'filled (code 2)', C1: 'left in place (code 1)' };
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
const p1 = (x) => (x == null || !Number.isFinite(x) ? 'n/a' : `${(100 * x).toFixed(1)}%`);
const sgn = (x) => (x > 0 ? `+${x.toFixed(2)}` : x.toFixed(2));
const VX_BASIS = { itt: 'every selected site', scorable: 'scorable sites', covered: 'covered sites' };
function vxURL() {
const q = params.get('vx');
if (q === 'fixture') return new URL('vx/fixture/summary.json', location.href).href;
return new URL(q || 'vx/summary.json', location.href).href;
}
// The page's own check, a subset of kit/vxsummary.py: enough that a broken file never draws as numbers.
function vxValid(d) {
const bad = [];
if (!d || d.schema !== VX_SCHEMA) bad.push(`schema is not ${VX_SCHEMA}`);
if (!d || !Array.isArray(d.scrolls) || !d.scrolls.length) bad.push('no scrolls');
// every count drawn into the page must be an integer and every share a number in 0..1, so a file from ?vx=URL
// cannot carry markup into the cards
const cnt = (x) => Number.isInteger(x) && x >= 0;
const frac = (x) => x == null || (typeof x === 'number' && x >= 0 && x <= 1);
const slotOK = (w) => !w || (cnt(w.k) && cnt(w.n) && w.k <= w.n && frac(w.share) && frac(w.lower) && frac(w.upper) && w.basis in VX_BASIS);
for (const s of (d && d.scrolls) || []) {
if (!(s.claim in VX_CLAIMS)) bad.push(`${s.scroll}: claim ${s.claim}`);
for (const st of s.strata || []) {
if (!cnt(st.n_selected) || !cnt(st.n_scorable)) bad.push(`${s.scroll} ${st.id} counts`);
const c = st.coverage;
if (c && !(cnt(c.k) && cnt(c.n) && c.k <= c.n && frac(c.share) && frac(c.lower) && frac(c.upper) && frac(c.bar))) bad.push(`${s.scroll} ${st.id} coverage`);
if (st.single_truth && !slotOK(st.single_truth.within_1)) bad.push(`${s.scroll} ${st.id} single_truth`);
for (const t of VX_TOLS) if (!slotOK(st.within && st.within[t])) bad.push(`${s.scroll} ${st.id} within ${t} slot`);
if (st.median_abs != null && typeof st.median_abs !== 'number') bad.push(`${s.scroll} ${st.id} median`);
}
for (const st of s.strata || []) for (const t of VX_TOLS) {
const w = st.within && st.within[t];
if (w && !(w.n >= w.k && w.k >= 0 && w.share >= 0 && w.share <= 1)) bad.push(`${s.scroll} ${st.id} within ${t}`);
if (w && w.basis === 'covered' && !(st.coverage && st.coverage.k === w.n)) bad.push(`${s.scroll} ${st.id} covered ${t}`);
}
if ((s.strata || []).some((st) => st.coverage) && !s.scope) bad.push(`${s.scroll}: a two-scan test without its scope`);
}
if (d && typeof d.fixture !== 'boolean') bad.push('fixture flag missing');
return bad;
}
// ---------------------------------------------------------------- small charts
function tolBars(st, rule) {
const bar = rule && rule.bar != null ? rule.bar : 0.9;
return `
${VX_TOLS.map((t) => {
const w = st.within[t];
const label = `${t === '1' ? '1 voxel' : `${t} voxels`}`;
if (!w) return `
${label} not measured n/a
`;
const lo = w.lower != null ? w.lower : null, hi = w.upper != null ? w.upper : null;
const whisk = lo != null ? `
` : '';
const line = t === '1' ? `
` : '';
return `
${label}
${whisk}${line}
${p1(w.share)} ${esc(w.k)} of ${esc(w.n)}, ${VX_BASIS[w.basis] || w.basis}
`;
}).join('')}
`;
}
// a two-scan test: the share of drawn sites the two scans cover, with its interval and bar
function coverageBar(st) {
const c = st.coverage;
if (!c) return '';
const whisk = c.lower != null ? ` ` : '';
return `covered
${whisk}
${p1(c.share)} ${esc(c.k)} of ${esc(c.n)} drawn sites
Covered: ${esc(c.what)}. ${esc(c.verdict)} (lower bound ${p1(c.lower)}, bar ${p1(c.bar)}). The shares below count covered sites only; a site that is not covered is neither a hit nor a miss.
`;
}
function singleTruth(st, s) {
const o = st.single_truth;
if (!o) return '';
const w = o.within_1;
return `Against the ${esc(s.truth ? s.truth.voxel_um : '')} µm scan alone: ${VX_ICON[o.verdict] || ''} ${esc(o.verdict)}${w ? `, ${p1(w.share)} within 1 voxel (${esc(w.k)} of ${esc(w.n)}, ${VX_BASIS[w.basis] || w.basis}; lower bound ${p1(w.lower)})` : ''}
${esc(o.why)}${o.instrument_limited ? ' (limited by the instrument)' : ''}.
Controls against the one scan ${controls({ controls: o.controls })} `;
}
function earlierTests(s) {
if (!s.earlier || !s.earlier.length) return '';
return `Earlier frozen test${s.earlier.length > 1 ? 's' : ''} on this scroll (spent) ${s.earlier.map((e) => `${esc(e.scope)} : ${esc(e.summary)} Preregistration ${esc(String(e.prereg.sha256).slice(0, 12))}, frozen ${esc(e.prereg.frozen)}. `).join('')} `;
}
function hist(st, showPub) {
const h = st.residual_hist, ph = st.published_hist;
if (!h || !h.edges || h.edges.length < 2) return 'No residual distribution for this stratum.
';
const W = 360, H = 130, L = 8, B = 22, T = 10;
const e = h.edges, lo = e[0], hi = e[e.length - 1];
const X = (v) => L + (W - 2 * L) * (v - lo) / (hi - lo);
const all = [...h.counts, ...(showPub && ph && ph.counts ? ph.counts : [])];
const max = Math.max(1, ...all);
const Y = (c) => H - B - (H - B - T) * c / max;
let bars = '';
h.counts.forEach((c, i) => {
if (!c) return;
const x0 = X(e[i]) + 1, x1 = X(e[i + 1]) - 1;
bars += `${e[i]} to ${e[i + 1]} voxels: ${c} sites `;
});
let pub = '';
if (showPub && ph && ph.counts && ph.edges && ph.edges.length === ph.counts.length + 1) {
let d = `M${X(ph.edges[0]).toFixed(1)},${Y(0).toFixed(1)}`;
ph.counts.forEach((c, i) => { d += `L${X(ph.edges[i]).toFixed(1)},${Y(c).toFixed(1)}L${X(ph.edges[i + 1]).toFixed(1)},${Y(c).toFixed(1)}`; });
d += `L${X(ph.edges[ph.edges.length - 1]).toFixed(1)},${Y(0).toFixed(1)}`;
pub = `published label `;
}
const ticks = [-4, -2, -1, 0, 1, 2, 4].filter((v) => v >= lo && v <= hi)
.map((v) => `${v > 0 ? '+' + v : v} `).join('');
const out = (h.under || h.over) ? `${h.under} below ${lo}, ${h.over} above +${hi} ` : '';
return `
within 1 voxel
${bars}${pub}
${ticks}${out} `;
}
function meter(s) {
const v = s.vertices, by = v.by_code, tot = Math.max(1, v.released + v.held_back);
const part = (n, color) => (n ? ` ` : '');
return `${part(by['0'], 'var(--snap)')}${part(by['2'], 'var(--fill)')}${part(by['1'], 'var(--pub)')}${part(v.held_back, 'var(--held)')}
snapped ${p1(by['0'] / tot)} filled ${p1(by['2'] / tot)} left in place ${p1(by['1'] / tot)} held back ${p1(v.held_back / tot)}
`;
}
function chip(st, on, scroll) {
const icon = VX_ICON[st.verdict] || '';
return `
${esc(st.id)} ${esc(VX_STRATUM_NAME[st.id] || '')} ${icon} ${esc(st.verdict)} `;
}
function controls(st) {
if (!st.controls || !st.controls.length) return '';
return `${st.controls.map((c) => {
const state = c.holds == null ? 'not measured' : c.holds ? 'holds' : 'does not hold';
return `${c.holds == null ? '·' : c.holds ? '✓' : '✕'} ${esc(c.name)}: ${p1(c.observed)} within 1 voxel, required ${esc(c.require)} ${p1(c.limit)}: ${state} `;
}).join('')} `;
}
function numbers(s) {
const rows = [];
for (const st of s.strata || []) {
if (st.coverage) {
const c = st.coverage;
rows.push(`${esc(st.id)} ${esc(c.verdict)} covered ${esc(c.k)} ${esc(c.n)} ${p1(c.share)} ${p1(c.lower)} ${p1(c.upper)} drawn sites `);
}
if (st.single_truth && st.single_truth.within_1) {
const w = st.single_truth.within_1;
rows.push(`${esc(st.id)}, one scan ${esc(st.single_truth.verdict)} 1 ${esc(w.k)} ${esc(w.n)} ${p1(w.share)} ${w.lower != null ? p1(w.lower) : ''} ${w.upper != null ? p1(w.upper) : ''} ${esc(w.basis)} `);
}
for (const t of VX_TOLS) {
const w = st.within[t];
rows.push(`${esc(st.id)} ${esc(st.verdict)} ${t} ${w ? w.k : ''} ${w ? w.n : ''} ${w ? p1(w.share) : 'not measured'} ${w && w.lower != null ? p1(w.lower) : ''} ${w && w.upper != null ? p1(w.upper) : ''} ${w ? esc(w.basis) : ''} `);
}
}
const v = s.vertices;
return `Show numbers
Vertices released ${fmt(v.released)} (code 0: ${fmt(v.by_code['0'])}, code 2: ${fmt(v.by_code['2'])}, code 1: ${fmt(v.by_code['1'])}), held back ${fmt(v.held_back)}. Label scan ${esc(s.label_scan.voxel_um)} µm${s.truth ? `; truth ${esc(s.truth.voxel_um)} µm scan` : ''}${s.second_truth ? `; second truth ${esc(s.second_truth.voxel_um)} µm scan` : ''}${s.oracle ? `; positive control ${esc(s.oracle.voxel_um)} µm scan` : ''}.${s.void && s.void.length ? ` Void: ${esc(s.void.join('; '))}.` : ''}
${rows.length ? `Stratum Verdict Voxels k n Share Lower Upper Basis ${rows.join('')}
` : ''}
${s.certificate ? `Certificate: ${esc(s.certificate.method)}, lower bound ${p1(s.certificate.lower)} at ${p1(s.certificate.level)} over ${fmt(s.certificate.n)} vertices.
` : ''} `;
}
// ---------------------------------------------------------------- cards
function stratumOrder(strata) {
const rank = { C0: 0, C0L: 1, C2: 2, C1: 3 };
return strata.slice().sort((a, b) => (rank[a.id] ?? 9) - (rank[b.id] ?? 9));
}
function strataBody(s, rule) {
const strata = stratumOrder(s.strata || []);
const prim = strata.find((x) => x.primary) || strata[0];
const cur = strata.find((x) => x.id === VX.pick[s.scroll]) || prim;
const one = prim && prim.within['1'];
const pubc = prim && (prim.controls || []).find((c) => /^published/.test(c.name));
const cov = prim && prim.coverage;
const head2 = one ? `${cov ? `The two scans agree on the face at ${p1(cov.share)} of drawn sites (${esc(cov.k)} of ${esc(cov.n)}). On those, ${p1(one.share)} of snapped vertices lie within 1 voxel (${esc(prim.id)}, ${VX_ICON[prim.verdict] || ''} ${esc(prim.verdict)}). One-sided 95% lower bounds ${p1(cov.lower)} (bar ${p1(cov.bar)}) and ${p1(one.lower)} (bar ${p1(rule.bar)}).
` : `${p1(one.share)} within 1 voxel (${esc(prim.id)}, ${VX_ICON[prim.verdict] || ''} ${esc(prim.verdict)}). One-sided 95% lower bound ${p1(one.lower)} (bar ${p1(rule.bar)}).
`}
${s.scope ? `${esc(s.scope)}
` : ''}
${pubc ? `${esc(pubc.name.replace(/^published label/, 'Published label'))}: ${p1(pubc.observed)}.` : ''}${s.void && s.void.length ? ` The test is void: ${esc(s.void.join('; '))}.` : ''}
` : '';
const pubOn = !!VX.pick[`${s.scroll}:pub`];
return `${head2}
${meter(s)}
${strata.map((x) => chip(x, x.id === cur.id, s.scroll)).join('')}
${esc(cur.id)}: share within each tolerance ${coverageBar(cur)}${tolBars(cur, rule)}
${esc(cur.verdict)}: ${esc(cur.why)}${cur.instrument_limited ? ' (limited by the instrument)' : ''}. ${esc(cur.n_selected)} sites selected${cur.coverage ? `, ${esc(cur.coverage.k)} covered` : `, ${esc(cur.n_scorable)} scorable`}. Whiskers: one-sided 95% interval. Dashed line: the bar.
Controls (each must be able to fail) ${controls(cur)}
${singleTruth(cur, s)}
What this does not show: labels that follow the wrong wrap, sheets that touch with no gap, and any scroll, segment or region not scored here${cur.coverage ? ', and any site the two scans do not cover' : ''}.
${earlierTests(s)}
${numbers(s)}`;
}
function scrollCard(s) {
const rule = VX.doc.rule || {};
const twoScan = (s.strata || []).some((x) => x.coverage);
const badge = { measured: twoScan ? 'Model output, measured where two finer scans agree' : 'Model output, measured against an independent finer scan', certified: 'Model output, truth-free certificate', not_shown: (s.strata || []).length ? 'tested; no claim' : 'no claim' }[s.claim];
const head = `
${esc(s.scroll)} label scan ${esc(s.label_scan.voxel_um)} µm voxels${s.truth ? `, truth from a ${esc(s.truth.voxel_um)} µm scan` : ''}${s.second_truth ? ` and a ${esc(s.second_truth.voxel_um)} µm scan` : ''}
${VX_CLAIMS[s.claim]} ${badge} `;
if (s.claim === 'not_shown') {
const tested = (s.strata || []).length > 0;
return `${head}Not shown: ${esc(s.why_not_shown)}.${tested ? ' The numbers below are what the test measured (model output); they make no claim.' : ''}
${tested ? strataBody(s, rule) : `${meter(s)}${numbers(s)}`} `;
}
if (s.claim === 'certified') {
const c = s.certificate;
return `${head}
One-sided ${p1(c.level)} lower bound ${p1(c.lower)} within 1 voxel (bar ${p1(rule.bar)}).
No truth scan; lower bound from the certificate, over ${fmt(c.n)} vertices. It rests on these assumptions:
${c.assumptions.map((a) => `${esc(a)} `).join('')}
${meter(s)}${numbers(s)} `;
}
return `${head}${strataBody(s, rule)} `;
}
function renderCards() {
const d = VX.doc;
const sc = d.scrolls.slice().sort((a, b) => VX_ORDER[a.claim] - VX_ORDER[b.claim]);
const count = (c) => d.scrolls.filter((s) => s.claim === c).length;
$('vx-tiles').innerHTML = ['measured', 'certified', 'not_shown'].map((c) => `${count(c)} scrolls ${VX_CLAIMS[c].toLowerCase()}
`).join('');
$('vx-cards').innerHTML = sc.map(scrollCard).join('');
$('vx-cards').querySelectorAll('.vx-chip').forEach((b) => { b.onclick = () => { VX.pick[b.dataset.scroll] = b.dataset.stratum; renderCards(); }; });
$('vx-cards').querySelectorAll('input[data-pub]').forEach((c) => { c.onchange = () => { VX.pick[`${c.dataset.pub}:pub`] = c.checked; renderCards(); }; });
const pre = d.prereg || {};
$('vx-prereg').textContent = `${pre.sha256 || 'n/a'}, frozen ${pre.frozen || 'n/a'}`;
const pr = d.prizes_read || {};
$('vx-elig').innerHTML = d.fixture ? 'The fixture\'s scrolls are made up.' : `Sourced fact: none of these scrolls is on the prize lists at scrollprize.org/prizes (read ${esc(pr.date)}).`;
$('vx-src').textContent = `${d.dataset.repo} ${d.dataset.release} at ${d.dataset.revision.slice(0, 12)}, summary ${d.generated}${d.fixture ? ', synthetic fixture' : ''}`;
}
// ---------------------------------------------------------------- showcase: residual heatmap and CT with the truth face
const RS = 12; // floats per showcase line piece: published, snapped, truth (ax ay bx by each)
async function openShowcase(segment) {
const list = (VX.doc && VX.doc.showcase) || [];
const e = list.find((x) => x.segment === segment) || list[0];
if (!e) throw new Error('no showcase segment');
const base = new URL(e.file, VX.url).href;
const meta = await getJSON(base);
// the grids are plain number lists (null: no value)
const res = Float32Array.from(meta.residual, (v) => (v == null ? NaN : v)), state = Uint8Array.from(meta.state);
const xyz = Float32Array.from(meta.xyz), rows = Float32Array.from(meta.rows);
VX.show = { meta, res, state, xyz, rows, plane: 0, cx: 0, cy: 0, win: Number($('vx-win').value) || 192, ct: null,
mode: (document.querySelector('input[name="vx-mode"]:checked') || {}).value || 'signed' };
$('vx-show-title').textContent = `${meta.scroll} · ${meta.segment}`;
$('vx-truth-note').textContent = meta.truth_note;
const mid = Math.floor(meta.planes.length / 2);
pickPlane(mid);
heat();
await showDraw();
}
function pickPlane(i) {
// center on a piece a quarter of the way along the plane's line
const V = VX.show, p = V.meta.planes[i];
V.plane = i;
if (!p || !p.count) return;
const q = RS * (p.first + Math.floor(p.count / 4));
V.cx = V.rows[q + 4]; V.cy = V.rows[q + 5];
}
function divColor(v, css) {
// diverging: blue (negative) to a neutral gray to orange (positive), clamped at +-2 voxels
const t = Math.max(-1, Math.min(1, v / 2));
const hex = (s) => { const m = s.trim().replace('#', ''); return [0, 2, 4].map((i) => parseInt(m.slice(i, i + 2), 16)); };
const neg = hex(css.getPropertyValue('--neg') || '#2f7bf6'), pos = hex(css.getPropertyValue('--pos') || '#e0701a'), mid = hex(css.getPropertyValue('--neutral') || '#c9ccd6');
const a = t < 0 ? neg : pos, k = Math.abs(t);
return `rgb(${mid.map((m, i) => Math.round(m + (a[i] - m) * k)).join(',')})`;
}
function heat() {
const V = VX.show; if (!V) return;
const [h, w] = V.meta.shape, cv2 = $('vx-heat'), g = cv2.getContext('2d');
const cw = Math.max(2, Math.floor(Math.min(900, cv2.parentNode.clientWidth || 600) / w));
cv2.width = w * cw; cv2.height = h * cw;
const css = getComputedStyle(document.documentElement);
const surf = css.getPropertyValue('--panel').trim() || '#fff', line = css.getPropertyValue('--line').trim() || '#ccc';
const tol = V.mode === 'signed' ? null : Number(V.mode);
g.fillStyle = surf; g.fillRect(0, 0, cv2.width, cv2.height);
for (let i = 0; i < h; i++) for (let j = 0; j < w; j++) {
const k = i * w + j, s = V.state[k], x = j * cw, y = i * cw;
if (s === 2) { g.fillStyle = css.getPropertyValue('--heldcell').trim() || '#ddd'; g.fillRect(x, y, cw, cw); continue; } // held back: never drawn
if (s === 1 || !Number.isFinite(V.res[k])) { // no value: hatched
g.strokeStyle = line; g.lineWidth = 1; g.beginPath(); g.moveTo(x, y + cw); g.lineTo(x + cw, y); g.stroke(); continue;
}
const v = V.res[k];
g.fillStyle = tol == null ? divColor(v, css) : (Math.abs(v) <= tol ? css.getPropertyValue('--snap').trim() : css.getPropertyValue('--pub').trim());
g.fillRect(x, y, cw, cw);
}
const p = V.meta.planes[V.plane];
if (p) { const i = V.meta.planes.indexOf(p); g.strokeStyle = css.getPropertyValue('--ink').trim(); g.lineWidth = 2; g.strokeRect(1, i * cw + 1, cv2.width - 2, cw - 2); }
V.cw = cw;
$('vx-heat-legend').innerHTML = tol == null
? `-2 0 +2 voxels (clamped) no value held back for evaluation `
: ` within ${tol} voxel${tol === 1 ? '' : 's'} not within no value held back for evaluation `;
}
async function showDraw() {
const V = VX.show; if (!V) return;
const cvs = $('vx-cv'), g = cvs.getContext('2d'), W = cvs.width, n = V.win, k = W / n;
const p = V.meta.planes[V.plane], z = p ? p.z : 0;
const x0 = Math.round(V.cx - n / 2), y0 = Math.round(V.cy - n / 2);
$('vx-z').textContent = `z ${z}`;
if (V.meta.volume) {
const key = `${z}|${y0}|${x0}|${n}`;
if (!V.ct || V.ct.key !== key) {
const buf = await ctWindow(V.meta.volume, z, y0, x0, n);
const img = new ImageData(n, n);
for (let i = 0; i < n * n; i++) { img.data[4 * i] = img.data[4 * i + 1] = img.data[4 * i + 2] = buf[i]; img.data[4 * i + 3] = 255; }
const off = document.createElement('canvas'); off.width = off.height = n; off.getContext('2d').putImageData(img, 0, 0);
V.ct = { key, img: off };
}
g.imageSmoothingEnabled = false; g.drawImage(V.ct.img, 0, 0, W, W);
} else {
g.fillStyle = '#15171f'; g.fillRect(0, 0, W, W);
g.fillStyle = 'rgba(255,255,255,.55)'; g.font = '14px system-ui, sans-serif'; g.fillText('Synthetic fixture: no CT', 14, 24);
}
const X = (x) => (x - x0 + 0.5) * k, Y = (y) => (y - y0 + 0.5) * k;
const css = getComputedStyle(document.documentElement);
const piece = (o, color, width, dash) => {
g.strokeStyle = color; g.lineWidth = width; g.setLineDash(dash || []); g.lineCap = 'round'; g.beginPath();
for (let q = p.first; q < p.first + p.count; q++) { const a = RS * q + o; g.moveTo(X(V.rows[a]), Y(V.rows[a + 1])); g.lineTo(X(V.rows[a + 2]), Y(V.rows[a + 3])); }
g.stroke(); g.setLineDash([]);
};
if (p && p.count && !V.meta.volume) {
// no CT in the fixture: a made-up sheet, drawn as a band along the made-up face
piece(8, css.getPropertyValue('--band').trim() || '#d9c6a3', 7 * k);
}
if (p && p.count) {
if ($('vx-l-pub').checked) piece(0, css.getPropertyValue('--pub').trim(), 2.5);
if ($('vx-l-snap').checked) piece(4, css.getPropertyValue('--snap').trim(), 2.5);
if ($('vx-l-truth').checked) { piece(8, '#11131c', 4.5, [7, 5]); piece(8, '#ffffff', 2, [7, 5]); }
}
g.fillStyle = '#fff'; g.fillRect(16, W - 22, 10 * k, 4);
g.font = '13px system-ui, sans-serif'; g.fillText(V.meta.voxel_um ? `10 voxels (${Math.round(10 * V.meta.voxel_um)} µm)` : '10 voxels', 16, W - 30);
}
function heatCell(ev) {
const V = VX.show; if (!V) return null;
const b = $('vx-heat').getBoundingClientRect(), [h, w] = V.meta.shape;
const j = Math.floor((ev.clientX - b.left) / b.width * w), i = Math.floor((ev.clientY - b.top) / b.height * h);
if (i < 0 || j < 0 || i >= h || j >= w) return null;
return { i, j, k: i * w + j };
}
// ---------------------------------------------------------------- wiring
function wireShowcase() {
const heatCv = $('vx-heat'), tip = $('vx-tip');
heatCv.addEventListener('mousemove', (ev) => {
const c = heatCell(ev), V = VX.show; if (!c) { tip.hidden = true; return; }
const s = V.state[c.k], v = V.res[c.k];
tip.textContent = s === 2 ? 'held back for evaluation' : (s === 1 || !Number.isFinite(v)) ? 'no value here' : `${sgn(v)} voxels (row ${c.i}, column ${c.j})`;
tip.hidden = false; tip.style.left = `${ev.offsetX + 14}px`; tip.style.top = `${ev.offsetY + 10}px`;
});
heatCv.addEventListener('mouseleave', () => { tip.hidden = true; });
heatCv.addEventListener('click', (ev) => {
const c = heatCell(ev), V = VX.show; if (!c || V.state[c.k] === 2) return;
const x = V.xyz[3 * c.k], y = V.xyz[3 * c.k + 1], z = V.xyz[3 * c.k + 2];
let best = Infinity, bi = 0;
V.meta.planes.forEach((p, i) => { const d = Math.abs(p.z - z); if (d < best) { best = d; bi = i; } });
V.plane = bi; V.cx = x; V.cy = y; heat(); showDraw();
});
document.querySelectorAll('input[name="vx-mode"]').forEach((r) => { r.onchange = () => { VX.show.mode = r.value; heat(); }; });
['vx-l-pub', 'vx-l-snap', 'vx-l-truth'].forEach((id) => { $(id).onchange = () => showDraw(); });
$('vx-win').onchange = () => { VX.show.win = Number($('vx-win').value); showDraw(); };
window.addEventListener('resize', () => heat());
}
async function vxInit() {
VX.url = vxURL();
let d;
try {
const r = await fetch(VX.url, { credentials: 'omit' });
if (!r.ok) { if (params.get('vx')) throw new Error(`${r.status} ${VX.url}`); return; } // no results yet: the tab stays hidden
d = await r.json();
} catch (e) {
if (!params.get('vx')) return;
$('vx-tabbtn').hidden = false; $('vx-error').hidden = false; $('vx-error').textContent = `Could not load the voxel-exact summary: ${e.message}`; return;
}
const bad = vxValid(d);
if (bad.length) {
if (!params.get('vx')) return;
$('vx-tabbtn').hidden = false; $('vx-error').hidden = false; $('vx-error').textContent = `The voxel-exact summary does not validate: ${bad.slice(0, 3).join('; ')}`; return;
}
VX.doc = d; VX.fixture = d.fixture === true;
$('vx-tabbtn').hidden = false;
// a summary from ?vx=URL is someone else's file: say so, so a shared link cannot pass as this Space's results
if (params.get('vx') && params.get('vx') !== 'fixture') { $('vx-error').hidden = false; $('vx-error').textContent = `Loaded from ${VX.url} (the vx parameter), not this Space's own results.`; }
document.querySelectorAll('.vx-fixture').forEach((b) => { b.hidden = !VX.fixture; });
document.body.classList.toggle('vx-fx', VX.fixture);
renderCards();
if (typeof table === 'function') table();
const sc = d.showcase || [];
$('vx-show-none').hidden = sc.length > 0; $('vx-show').hidden = !sc.length;
if (sc.length) {
$('vx-show-pick').innerHTML = sc.map((s) => `${esc(s.scroll)} · ${esc(s.segment)} `).join('');
$('vx-show-pick').onchange = () => openShowcase($('vx-show-pick').value).catch((e) => { $('vx-show-title').textContent = e.message; });
wireShowcase();
await openShowcase(sc[0].segment).catch((e) => { $('vx-show-title').textContent = e.message; });
}
if (params.get('tab') === 'exact') tab('exact');
}
// the scroll's claim level for the All segments table (app.js)
window.vxClaim = (scroll) => {
if (!VX.doc) return null;
const s = VX.doc.scrolls.find((x) => x.scroll === scroll);
return s ? VX_CLAIMS[s.claim] : 'Not scored';
};
Object.assign(window.snappedLabels, {
voxelExact: () => (VX.doc ? JSON.parse(JSON.stringify(VX.doc)) : null),
openShowcase: (segment) => openShowcase(segment),
});
window.vxReady = vxInit();