miner-ui-5: live-dag.js 2.0.1 (the site lane's real-data options, byte-identical), window 60 on both scenes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit efb3cc441c)
This commit is contained in:
igneum-labs 2026-10-07 09:09:54 +00:00
parent f1b7eb170e
commit f88de854de
4 changed files with 21 additions and 12 deletions

View file

@ -1594,7 +1594,7 @@ if (typeof document !== 'undefined') (function () {
function mountFull() {
if (dagFull || typeof IgneumDag === 'undefined') return;
if (typeof IgneumProof !== 'undefined' && !proof) proof = IgneumProof.mount($('proof'));
dagFull = IgneumDag.mount($('dag-full'), { poll: false, window: 90, mine: mineFn, tooltip: $('dag-tip-full'), chip: $('dag-chip-full'), pauseButton: $('dag-pause-full'),
dagFull = IgneumDag.mount($('dag-full'), { poll: false, window: 60, mine: mineFn, tooltip: $('dag-tip-full'), chip: $('dag-chip-full'), pauseButton: $('dag-pause-full'),
onWindow: function (w) { setText('z-pct', w + ' s'); },
onSelect: function (b) { if (b) inspect(b); else uninspect(); },
onPause: function (p) { $('dag-follow').classList.toggle('on', !p); if (proof) proof.setPaused(p || dagFull.getState().state !== 'live'); },

View file

@ -220,7 +220,7 @@
<div class="chain-full" id="chain-full" hidden>
<div class="cf-bar">
<div class="seg small" id="dag-filter" role="radiogroup" aria-label="Which blocks"><button class="seg-b on" data-filter="all" role="radio" aria-checked="true">All blocks</button><button class="seg-b" data-filter="chain" role="radio" aria-checked="false">Selected chain</button><button class="seg-b" data-filter="mine" role="radio" aria-checked="false">Your blocks</button></div>
<span class="cf-right"><span class="zoom"><button type="button" id="z-out" aria-label="Wider window">&minus;</button><span id="z-pct" class="mono">90 s</span><button type="button" id="z-in" aria-label="Narrower window">+</button></span><button class="btn tiny ghost on" id="dag-follow">Follow</button><button class="btn tiny ghost" id="dag-pause-full" aria-pressed="false">Pause</button></span>
<span class="cf-right"><span class="zoom"><button type="button" id="z-out" aria-label="Wider window">&minus;</button><span id="z-pct" class="mono">60 s</span><button type="button" id="z-in" aria-label="Narrower window">+</button></span><button class="btn tiny ghost on" id="dag-follow">Follow</button><button class="btn tiny ghost" id="dag-pause-full" aria-pressed="false">Pause</button></span>
</div>
<div class="cf-graph">
<div class="cf-scene">

View file

@ -1,4 +1,7 @@
/* Igneum DAG / Ember 2.0
/* Igneum DAG / Ember 2.0 (the EMBER 02 renderer pack, 7 Oct 2026) with the real-data presentation options of 2.0.1:
* maxLanes (own key + top keys + others, default 7), minNode (node half-size floor, default 9.5), hairlineAlpha (non-chain
* edges, default .12, drawn only within laneReach lanes, default 2, and only a merged block's first parent unless selected),
* othersScale (the others lane's size and alpha, default .75), provenGlow (a glow and ring on proven blocks, default on).
* Replacement for the supplied live-dag.js. No framework, network writes or synthetic records.
* Existing mount/push options and public methods are retained; see README.md for additions.
* Every node, parent edge, proof segment and checkpoint is derived from the observer reply.
@ -47,6 +50,7 @@
var maxBlocks=clamp(finite(opts.maxBlocks)?opts.maxBlocks:6000,100,20000);
var lag=finite(opts.lagMs)?clamp(opts.lagMs,0,10000):2500;
var fps=clamp(finite(opts.fps)?opts.fps:30,10,60), minFrame=1000/fps;
var maxLanes=clamp(finite(opts.maxLanes)?opts.maxLanes:7,2,12), minNode=finite(opts.minNode)?opts.minNode:9.5, hairAlpha=finite(opts.hairlineAlpha)?opts.hairlineAlpha:.12, laneReach=finite(opts.laneReach)?opts.laneReach:2, othersScale=finite(opts.othersScale)?opts.othersScale:.75, provenGlow=opts.provenGlow!==false;
var mq=root.matchMedia?root.matchMedia('(prefers-reduced-motion: reduce)'):null;
var reduced=mq?mq.matches:false, manualMotion=true;
var mediaTheme=root.matchMedia?root.matchMedia('(prefers-color-scheme: dark)'):null;
@ -93,7 +97,7 @@
padL=compact||W<510?14:W<750?84:106;padR=compact?12:24;padT=compact?29:58;padB=compact?22:38;
var start=rightTime()-windowS*1000, end=rightTime()+lag+1000,counts=new Map(),mineKeys=new Set();
blocks.forEach(function(b){if(b.ts>=start && b.ts<=end){counts.set(b.miner,(counts.get(b.miner)||0)+1);if(own(b))mineKeys.add(b.miner);}});
var capacity=Math.max(2,Math.floor((H-padT-padB)/(compact?26:46))),ids=Array.from(counts.keys());
var capacity=Math.min(maxLanes,Math.max(2,Math.floor((H-padT-padB)/(compact?26:46)))),ids=Array.from(counts.keys());
ids.sort(function(a,b){return (mineKeys.has(b)?1:0)-(mineKeys.has(a)?1:0)||(counts.get(b)-counts.get(a))||a.localeCompare(b);});
var chosen=ids.slice(0,ids.length>capacity?capacity-1:capacity);
// Preserve existing key order instead of re-ranking every poll. Always keep the user's lane visible.
@ -214,19 +218,22 @@
// Animate lane transitions without changing their underlying key identity.
blocks.forEach(function(b){b.x=xOf(b.ts,rt);var progress=animate?clamp((clock-b.laneAt)/450,0,1):1;progress=1-Math.pow(1-progress,3);b.y=b.fromY+(b.targetY-b.fromY)*progress;b.on=b.ts>=left&&b.ts<=rt&&passes(b);if(b.on&&b.newArrival&&b.visibleAt===null){b.visibleAt=t;b.born=t;}});
ctx.save();ctx.beginPath();ctx.rect(padL-1,padT-15,plotW+2,plotH+25);ctx.clip();
blocks.forEach(function(b){if(!b.on)return;b.parents.forEach(function(hash){var p=view.get(hash);if(!p||!passes(p)||p.x>W-padR||p.x<padL-plotW*.2)return;
blocks.forEach(function(b){if(!b.on)return;var bSel=selected&&b.hash===selected;b.parents.forEach(function(hash,pi){var p=view.get(hash);if(!p||!passes(p)||p.x>W-padR||p.x<padL-plotW*.2)return;
var path=b.chain&&p.chain,selectedEdge=selected&&(b.hash===selected||p.hash===selected);
ctx.strokeStyle=rgba(path?col.ember:selectedEdge?col.bone:col.ash,path?.1:selectedEdge?.10:.04);ctx.lineWidth=path?8:selectedEdge?4:2;curve(b,p);ctx.stroke();
ctx.strokeStyle=rgba(path?col.ember:selectedEdge?col.bone:b.color==='red'?col.red:col.ash,path?.68:selectedEdge?.7:b.color==='red'?.3:.23);ctx.lineWidth=path?1.65:selectedEdge?1.4:1;curve(b,p);ctx.stroke();
if(!path&&!selectedEdge){if(pi>0)return;var li=laneOf.has(b.miner)?laneOf.get(b.miner):lanes.length-1,lp=laneOf.has(p.miner)?laneOf.get(p.miner):lanes.length-1;if(Math.abs(li-lp)>laneReach)return;}
if(path||selectedEdge){ctx.strokeStyle=rgba(path?col.ember:col.bone,path?.1:.10);ctx.lineWidth=path?8:4;curve(b,p);ctx.stroke();}
ctx.strokeStyle=rgba(path?col.ember:selectedEdge?col.bone:b.color==='red'?col.red:col.ash,path?.68:selectedEdge?.7:hairAlpha);ctx.lineWidth=path?1.65:selectedEdge?1.4:1;curve(b,p);ctx.stroke();
var age=t-b.born;if(animate&&age>=0&&age<1400){var f=clamp(age/1150,0,1),pt=pointOn(b,p,f);ctx.shadowBlur=10;ctx.shadowColor=path?col.ember:col.blue;ctx.fillStyle=path?col.molten:col.blue;ctx.beginPath();ctx.arc(pt.x,pt.y,path?2.2:1.65,0,TAU);ctx.fill();ctx.shadowBlur=0;}
});});
var density=blocks.filter(function(b){return b.on;}).length/Math.max(plotW,1), S=compact?6.5:density>.16?7:9.5;
var S=compact?6.5:clamp(lh*.22,minNode,13);
blocks.forEach(function(b){if(!b.on)return;
var age=t-b.born,newness=animate?Math.max(clamp(1-age/1700,0,1),clamp(1-(t-b.changed)/900,0,1)*.65):0;
var ink=b.color==='red'?col.red:b.chain?col.ember:b.color==='blue'?col.blue:col.ash;
var isOwn=own(b),isSelected=b.hash===selected||b.hash===hover,sz=S*(1+(newness*.15));
var isOwn=own(b),isSelected=b.hash===selected||b.hash===hover,inOthers=!laneOf.has(b.miner),sz=S*(1+(newness*.15))*(inOthers?othersScale:1);
if(newness>0||isOwn||isSelected){var glow=ctx.createRadialGradient(b.x,b.y,0,b.x,b.y,sz*3.8);glow.addColorStop(0,rgba(isOwn?col.molten:ink,newness*.26+(isSelected?.15:isOwn?.06:0)));glow.addColorStop(1,rgba(ink,0));ctx.fillStyle=glow;ctx.fillRect(b.x-sz*4,b.y-sz*4,sz*8,sz*8);}
ctx.globalAlpha=b.color==='red'?.78:1;
ctx.globalAlpha=(b.color==='red'?.78:1)*(inOthers&&!isSelected&&!isOwn?othersScale:1);
// a proven block glows and carries a ring, so the proof reads from across the room
if(provenGlow&&b.proven){var pg=ctx.createRadialGradient(b.x,b.y,0,b.x,b.y,sz*3.2);pg.addColorStop(0,rgba(ink,.26));pg.addColorStop(1,rgba(ink,0));ctx.fillStyle=pg;ctx.fillRect(b.x-sz*3.4,b.y-sz*3.4,sz*6.8,sz*6.8);ctx.strokeStyle=rgba(ink,.6);ctx.lineWidth=1;ctx.beginPath();ctx.arc(b.x,b.y,sz+5,0,TAU);ctx.stroke();}
// Inset tiles: inclusion is the outline; proof is the core, never the same status.
ctx.fillStyle=col.bg;ctx.strokeStyle=rgba(ink,b.chain?.95:.8);ctx.lineWidth=b.chain?1.75:1.25;rounded(ctx,b.x-sz,b.y-sz,2*sz,2*sz,3);ctx.fill();ctx.stroke();
var tile=ctx.createLinearGradient(b.x,b.y-sz,b.x,b.y+sz);tile.addColorStop(0,rgba(ink,b.proven?.5:.16));tile.addColorStop(1,rgba(ink,b.proven?.22:.025));ctx.fillStyle=tile;rounded(ctx,b.x-sz+2,b.y-sz+2,2*sz-4,2*sz-4,2);ctx.fill();
@ -338,5 +345,5 @@
getSnapshot:function(){return {ok:true,state:{stale:state!=='live'},blocks:blocks.map(cloneBlock),finality:{checkpoints:cps.map(function(c){return Object.assign({},c);})}};}};
instances.set(canvas,api);if(chip)chip.hidden=true;theme();size();emit('onState',state,reason);if(opts.poll!==false)poll();redraw();return api;
}
root.IgneumDag={mount:mount,version:'2.0.0'};
root.IgneumDag={mount:mount,version:'2.0.1'};
})(window);

View file

@ -25,7 +25,7 @@ listed in section 6.
## 2. The chain scene (EMBER 02, taken from the site lane)
the project lead's renderer pack (11:3x UK): `ui/live-dag.js` (sha256 582f2e73…, IgneumDag 2.0.0) and `ui/proof-core.js` (c2a094a6…,
the project lead's renderer pack (11:3x UK): `ui/live-dag.js` (sha256 e78f2d38…, IgneumDag 2.0.1: the site lane's real-data options, maxLanes 7 with the own key first and an OTHERS lane, minNode 9.5, merge hairlines within two lanes, provenGlow; 2.0.0 was 582f2e73…) and `ui/proof-core.js` (c2a094a6…,
IgneumProof 2.0.0) are byte-identical copies of the site-ui-4 files; the engine serves `proof-core.js` beside
`live-dag.js`. The Overview card mounts the compact mode (`compact: true, window: 60, poll: false`); Inspect, or a
click on a block, opens the full scene under it with the block inspector in the site's words (Proof in progress /
@ -37,6 +37,8 @@ machine's cards (the 8 hex the feed names as `b.miner`), never the payout addres
`:root` for both themes. The fallback strip (this machine's own blocks) draws after three failed reads. The legend
reads "Your blocks" as in the reference.
Caption fact from the site lane: the observer's per-block shard states read "planned" for every chain block in the window while its paid counters move (10:08 UK), so the live scene shows no proven block until the observer's read is fixed (the fleet lane has it); the mock's feed shows the proven state.
## 3. Gate results
| Gate | Result |