const $ = id => document.getElementById(id); const node = (tag, text, cls) => {const e=document.createElement(tag); if(text!==undefined)e.textContent=text; if(cls)e.className=cls; return e;}; const name = d => d === 'nova_anima' ? 'Nova' : 'Qwen'; const num = n => Number.isFinite(n) ? n.toFixed(4) : '—'; let data; function pictures(target, row, columns) { $(target).replaceChildren(...columns.map(([key,label])=>{ const figure=node('figure'),link=node('a'),img=node('img'); link.href=row.images[key];link.target='_blank';link.rel='noopener'; img.src=row.images[key];img.alt=`${label}: ${row.label || row.prompt}`;img.className='sample-image'; link.append(img);figure.append(link,node('figcaption',label));return figure; })); } function drawCharacter() { const row=data.characters.cases.find(r=>r.id===$('character').value&&r.domain===$('start').value); const p=row.policies.find(p=>p.policy===$('policy').value),kind=p.policy.replaceAll('_','-'); const route=[row.domain,...p.audit.switches.map(s=>s.target)].map(name).join(' → '); $('prompt').textContent=row.prompt; $('trajectory').replaceChildren(...p.domains.map((d,i)=>node('span',`${i+1} ${name(d)}`,d==='nova_anima'?'sd15':'sana'))); $('schedule').textContent=`${row.resolution}px · seed ${row.seed} · 24 denoising steps. ${p.audit.switches.map(s=>`After step ${s.after_call}: ${name(s.source)} → ${name(s.target)}`).join('. ')}.`; pictures('pictures',row,[['shared-single',`${name(row.domain)} only · same noise grid`],[kind,`${route} · learned bridges`],[kind+'-codec',`${route} · full decode/encode reference`]]); $('metrics').textContent=`Learned versus matching reference: LPIPS ${num(p.lpips_vs_matched_full_codec)}. Difference from ${name(row.domain)} only: learned ${num(p.lpips_vs_single_model)}; reference ${num(p.full_codec_lpips_vs_single_model)}. Exact repeat: ${p.repeat_bitwise_equal?'passed':'unverified'}.`; } function drawBridge() { const row=data.reconstructions.find(r=>r.domain===$('direction').value); $('bridge-prompt').textContent=row.prompt; $('bridge-step').textContent=`${row.training_step.toLocaleString()} resumed updates · ${row.kind} · seed ${row.seed}`; pictures('bridge-pictures',row,[['source',`${name(row.domain)} · source`],['prediction',`Learned bridge → ${name(row.other_domain)}`],['target',`Full-codec target → ${name(row.other_domain)}`]]); $('bridge-metrics').textContent=`Learned LPIPS ${num(row.metrics.lpips)}; full-codec target ${num(row.metrics.teacher_lpips)}; learned versus target ${num(row.metrics.lpips_vs_teacher)}.`; } function chart(metric) { const ns='http://www.w3.org/2000/svg',svg=document.createElementNS(ns,'svg'); svg.setAttribute('viewBox','0 0 620 280');svg.setAttribute('role','img');svg.setAttribute('aria-label',`Validation ${metric} versus resumed updates`); const values=data.runs.flatMap(r=>r.validation.filter(v=>Number.isFinite(v.metrics[metric]))); if(!values.length)return; const xmax=Math.max(...values.map(v=>v.step),1), ymax=Math.max(...values.map(v=>v.metrics[metric]),.001)*1.08; const x=v=>52+550*v/xmax,y=v=>236-210*v/ymax; function add(tag,attrs,text){const e=document.createElementNS(ns,tag);for(const [k,v]of Object.entries(attrs))e.setAttribute(k,v);if(text!==undefined)e.textContent=text;svg.append(e);return e;} for(let i=0;i<=4;i++){const v=ymax*i/4;add('line',{x1:52,x2:602,y1:y(v),y2:y(v),class:'gridline'});add('text',{x:45,y:y(v)+4,'text-anchor':'end'},v.toFixed(3));const step=xmax*i/4;add('text',{x:x(step),y:259,'text-anchor':'middle'},`${Math.round(step/1000)}k`);} data.runs.forEach((r,i)=>{const rows=r.validation.filter(v=>Number.isFinite(v.metrics[metric])),color=i?'#edb784':'#88e0c0'; add('polyline',{points:rows.map(v=>`${x(v.step)},${y(v.metrics[metric])}`).join(' '),fill:'none',stroke:color,'stroke-width':2}); rows.forEach(v=>{const c=add('circle',{cx:x(v.step),cy:y(v.metrics[metric]),r:3,fill:color}),t=document.createElementNS(ns,'title');t.textContent=`${r.label}: ${v.step} updates, ${metric} ${v.metrics[metric]}`;c.append(t);}); });$(metric).replaceChildren(svg); } fetch('archive.json').then(r=>{if(!r.ok)throw Error(`HTTP ${r.status}`);return r.json();}).then(value=>{ data=value; data.runs.forEach(r=>{r.validation=r.validation.map(v=>({...v,metrics:v.metrics||v}));}); $('status').textContent=data.stopped?'Training stopped · experiment preserved':'Experiment snapshot · publication in progress'; $('snapshot').textContent=`Archived ${data.created_at}. Full-codec supervision is preserved for reference; the next experiment will investigate latent-only preparation and training.`; if(data.stopped){const s=data.stop_record;$('snapshot').textContent+=` Stopped at ${s.checkpoints.forward.step.toLocaleString()} forward / ${s.checkpoints.reverse.step.toLocaleString()} reverse resumed updates, with ${s.total_training_prompts_prepared.toLocaleString()} / ${s.planned_training_prompts.toLocaleString()} training prompts prepared.`;} const cps=data.characters.checkpoints;$('checkpoints').textContent=`Character snapshot: Nova → Qwen ${cps.forward.step.toLocaleString()} updates; Qwen → Nova ${cps.reverse.step.toLocaleString()} updates. Latest/best archived weights and curves are labeled separately.`; const cases=[...new Map(data.characters.cases.map(r=>[r.id,r])).values()];$('character').replaceChildren(...cases.map(r=>{const o=node('option',r.label);o.value=r.id;return o;})); $('summary').replaceChildren(...data.runs.map(r=>{const card=node('div',undefined,'stat'),last=r.validation.at(-1);card.append(node('label',r.label),node('strong',num(last?.metrics.lpips)),node('span',`Validation LPIPS at ${last?.step.toLocaleString()} updates. Selected best: ${num(r.best?.lpips)} at ${r.best?.step.toLocaleString()}.`));return card;})); drawCharacter();drawBridge();chart('lpips');chart('latent_nmse'); }).catch(e=>{$('status').textContent=`Unable to load archive: ${e.message}`;}); for(const id of ['character','start','policy'])$(id).addEventListener('change',drawCharacter); $('direction').addEventListener('change',drawBridge);