igneum/site/explorer.html
igneum-labs 3e72c9a386 Home page redrawn: the scene is the page; a 56 px header, one statement, two buttons; three facts, the downloads, one line to the ledger
The owner, 6 October 2026, on the live home page: "too left and text heavy ... we want the home page to suck people in and let
the litepaper carry the weight; also minimise the header." The home page only; nothing else above the fold.

Header (this page only, a page-block override of the shared nav): the wordmark, Litepaper, Live devnet and Download the miner,
56 px, transparent over the hero; the phone sheet shows the same three.
Hero: one statement, eleven words ("A proof-of-work chain for graphics cards, whose miners prove the blocks."), two buttons,
then the step scene (site/live-steps.js on the shared feed) full bleed with its one caption line. Hero copy 17 words with the
buttons. At 1440 by 900 the hero ends at 849 px; at 390 by 844 at 699 px.
Below the fold: three facts, each one number and one sentence: the live hash rate with the vote keys of the last ten
minutes, the shards proven and paid on the chain (with the last ten minutes), and the chip model's one line with its link;
a note under them says the chain's state in the ledger's words (tonight: finality paused) and that the chip figures are a
cost model, not a measurement. Then the downloads row (three platforms) with the devnet and testnet notices and the dev-fee
sentence, then one line to the ledger and to what Igneum does not claim. The footer is unchanged.
Moved, nothing cut: the light-client card to /live (its verifier module with it); the testnet terms to the litepaper's For
miners section (with an id for the metamask page's link); "Live rows arrive with the public testnet, August 2027" to the
litepaper's proving section; "since 2019 (approximate)" onto the litepaper's RandomX date; the journey, economics, wallet,
build and RandomX sections were already in the litepaper (roadmap, economics, wallet, building, vs RandomX). The footer's
Journey link points at the litepaper's roadmap. tools/ci/ledger-text-check.mjs: the home page is checked for E5, X2 and
X7; G4, C2, X3 and X8 are checked on the litepaper (G4 and X8 were already there). The ledger's own "stated on" notes for
those four rows are owed an update by the ledger owner.
Polish lane Q5: the word "final" is drawn and captioned only while finality is active (site/live-steps.js), so nothing on
the page says final while finality is paused; the hero is under 40 words; the Open Graph card is the 1200 by 630 image.

Measured headless at 1440 and 390, dark and light: header 56 px with three items, no "final" anywhere, no horizontal
overflow, no console errors; the caption advanced on every capture. Captures: docs/plans/site-ui-3-shots/after/
home-{1440,390}-{dark,light}.jpg (full page) and home-{1440,390}-{dark,light}-fold.jpg (above the fold).
Checks: link check 912 links across 16 pages 0 broken, ledger text 50 of 50, contrast 32 pairs 0 under 4.5:1, orphan check
0 site headings, api tests 5 pass. The identity grep's one hit is docs/analysis/horizon/polish.md line 433 on master,
untouched here (the polish lane's own table of regex literals); it is main's to route.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:30:09 +00:00

303 lines
26 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Igneum explorer</title>
<meta name="description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
<link rel="canonical" href="https://igneum.network/explorer">
<meta name="theme-color" content="#0C0C0E">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Igneum">
<meta property="og:title" content="Igneum explorer">
<meta property="og:description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
<meta property="og:url" content="https://igneum.network/explorer">
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Igneum explorer">
<meta name="twitter:description" content="The Igneum block DAG, block by block, with the network numbers and the supply.">
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
<link rel="manifest" href="/site.webmanifest">
<!-- head:start -->
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/site.css">
<style>
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
</style>
<script>
/* theme before first paint: the footer control stores "light" or "dark" under igneum-theme; nothing stored means the system setting */
(function(){try{var t=localStorage.getItem("igneum-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t);}catch(e){}})();
</script>
<!-- head:end -->
<style>
/* page block; tokens, type and components are in /site.css */
/* the explorer pages share this block with block.html and address.html; same tokens as live.html */
--card-pad:clamp(18px,3vw,28px);--card-r:18px;--tile-pad:18px 20px;--tile-r:14px;--gap:24px;--gap-tile:12px;
--fs-h1:clamp(32px,5.5vw,56px);--fs-h3:clamp(18px,2vw,22px);--fs-tile:clamp(20px,2.2vw,26px)}
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px}
.mono{font-family:var(--f-mono)}
h1,h2{font-family:var(--f-display);margin:0;line-height:1.08;text-wrap:balance}
.head{padding-block:var(--head) var(--gap);display:flex;flex-direction:column;gap:14px}
.head p{color:var(--ink-2);max-width:64ch;font-size:16px}
.search{display:flex;gap:10px;max-width:760px;margin-top:4px}
.search input{flex:1;min-width:0;min-height:48px;padding:10px 14px;border-radius:10px;border:1px solid var(--line-2);background:var(--graphite);color:var(--bone);font:500 15px/1.3 var(--f-mono)}
.search input::placeholder{color:var(--ash)}
.btn.primary:hover{background:#FF6A2B;border-color:#FF6A2B;color:var(--ember-ink)}
.msg{font-family:var(--f-mono);font-size:13px;color:var(--molten);min-height:18px}
.strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--gap-tile)}
@media (max-width:700px){.strip{grid-template-columns:repeat(2,minmax(0,1fr))}}
.cell{background:var(--graphite);border:1px solid var(--line);border-radius:var(--tile-r);padding:var(--tile-pad);display:flex;flex-direction:column;gap:6px;min-width:0}
.cell .k{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash)}
.cell .v{font-family:var(--f-display);font-weight:700;font-size:var(--fs-tile);line-height:1.1;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cell .v small{font-family:var(--f-mono);font-weight:500;font-size:13px;color:var(--ash);margin-left:4px;letter-spacing:.04em}
@media (max-width:700px){.cell .v{font-size:19px}}
.cell .s{font-family:var(--f-mono);font-size:12px;color:var(--ash);text-wrap:balance}
.cell.status .v{display:flex;align-items:center;gap:10px}
.off .dot{background:var(--ash);animation:none}.off .cell.status .v{color:var(--ash)}.on .cell.status .v{color:var(--molten)}
@media (prefers-reduced-motion:reduce){.dot{animation:none}}
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
tbody tr:hover td{background:rgba(255,255,255,.025)}
.id{font-family:var(--f-mono);color:var(--molten)}
.hash{font-family:var(--f-mono)}
.sw.chain{background:var(--ember);border-color:var(--blue)}.sw.blue{background:rgba(92,184,255,.7);border-color:var(--blue)}.sw.red{background:linear-gradient(45deg,transparent 44%,var(--ash) 44%,var(--ash) 56%,transparent 56%) center/8px 8px no-repeat}
.chip{display:inline-block;font-family:var(--f-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 8px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin-right:6px}
.chip.hot{border-color:var(--molten);color:var(--molten)}.chip.ok{border-color:var(--green);color:var(--green)}
dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 20px;margin:12px 0 0;font-size:14px}
dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash);padding-top:3px}
dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
@media (max-width:640px){dl{grid-template-columns:1fr;gap:2px 0}dd{margin-bottom:8px}}
.two{display:grid;gap:var(--gap);grid-template-columns:1fr}
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
.two-wrap{margin-top:var(--gap)}
main{padding-bottom:var(--sec)}
</style>
</head>
<body class="off">
<!-- nav:start -->
<a class="skip" href="#main">Skip to content</a>
<nav class="nav" aria-label="Main">
<div class="wrap">
<a href="/" class="brand" aria-label="Igneum home">
<svg class="mark" viewBox="0 0 1024 1024" width="28" height="28" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
<span class="word">IGNEUM</span>
</a>
<div class="links" id="nav-links">
<a href="/litepaper" data-nav="litepaper">Litepaper</a>
<a href="/live" data-nav="live" aria-current="page">Live devnet</a>
<a href="/bench" data-nav="bench">Engineering log</a>
<a href="/miner" data-nav="miner">Miner</a>
<a href="/wallet" data-nav="wallet">Wallet</a>
<a href="/evidence" data-nav="evidence">Evidence</a>
<a href="https://github.com/igneum-network/spec" rel="noopener">GitHub</a>
</div>
<a href="/miner#get" class="btn primary small cta">Download the miner</a>
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Menu"><span class="bars"></span></button>
<div class="nav-sheet" id="nav-sheet">
<a href="/litepaper" data-nav="litepaper">Litepaper</a>
<a href="/live" data-nav="live">Live devnet</a>
<a href="/bench" data-nav="bench">Engineering log</a>
<a href="/miner" data-nav="miner">Miner</a>
<a href="/wallet" data-nav="wallet">Wallet</a>
<a href="/evidence" data-nav="evidence">Evidence</a>
<a href="/explorer">Explorer</a>
<a href="/ledger">Ledger</a>
<a href="https://github.com/igneum-network/spec" rel="noopener">GitHub</a>
<a href="/miner#get" class="btn primary">Download the miner</a>
</div>
</div>
</nav>
<script>
(function(){
// the menu: open on the button, closed by any link, Escape (focus back on the button) or a resize past 900 px
var n=document.querySelector('.nav'),b=document.getElementById('nav-burger'),s=document.getElementById('nav-sheet');if(!n||!b||!s)return;
function set(o){n.classList.toggle('open',o);b.setAttribute('aria-expanded',o?'true':'false');document.documentElement.style.overflow=o?'hidden':'';}
b.addEventListener('click',function(){set(!n.classList.contains('open'));});
s.addEventListener('click',function(e){if(e.target.closest('a'))set(false);});
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('open')){set(false);b.focus();}});
var mq=window.matchMedia('(min-width:901px)');if(mq.addEventListener)mq.addEventListener('change',function(){set(false);});
})();
</script>
<!-- nav:end -->
<main id="main" class="wrap">
<div class="head">
<div class="eyebrow">devnet, last 24 hours</div>
<h1>Explorer</h1>
<p>Every block the devnet made in the last day, read from a node by the observer. Paste a block hash, a transaction hash, a chain block number or an address.</p>
<form class="search" id="search" role="search">
<input id="q" type="search" autocomplete="off" spellcheck="false" placeholder="block hash, transaction hash, chain block number, 0x address or igneumdev:… address" aria-label="Search the explorer">
<button class="btn primary" type="submit">Search</button>
</form>
<div class="msg" id="msg" aria-live="polite"></div>
</div>
<div class="strip" aria-live="polite">
<div class="cell status"><div class="k">Status</div><div class="v"><span class="dot"></span><span id="st-status">OFFLINE</span></div><div class="s" id="st-age">no observer update yet</div></div>
<div class="cell"><div class="k">Height</div><div class="v" id="st-height">0</div><div class="s" id="st-count">chain block number, 0 blocks in the DAG</div></div>
<div class="cell"><div class="k">DAA score</div><div class="v" id="st-daa">0</div><div class="s" id="st-blue">blue score 0</div></div>
<div class="cell"><div class="k">Difficulty</div><div class="v" id="st-diff">0</div><div class="s" id="st-bt">target per block</div></div>
<div class="cell"><div class="k">Hash rate</div><div class="v" id="st-hps">0</div><div class="s">network estimate</div></div>
<div class="cell"><div class="k">Block reward</div><div class="v" id="st-reward">0<small>IGN</small></div><div class="s" id="st-split">80% miner, 20% proving pool</div></div>
<div class="cell"><div class="k">Circulating</div><div class="v" id="st-supply">0<small>IGN</small></div><div class="s" id="st-cap">of 4,000,000,000 by the rule</div></div>
<div class="cell"><div class="k">Next halving</div><div class="v" id="st-halving">0<small>d</small></div><div class="s" id="st-ramp">ramp</div></div>
</div>
<div class="card" aria-label="Latest blocks">
<div class="viz-head"><h2>Latest blocks</h2><div class="eyebrow" id="blk-eyebrow">newest first, every 5 s</div></div>
<div class="tbl">
<table>
<thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Miner</th><th class="n">Txs</th><th class="n">Proof records</th><th>Time</th></tr></thead>
<tbody id="blocks"><tr><td colspan="8" class="empty">Loading.</td></tr></tbody>
</table>
</div>
<div class="legend"><span><i class="sw chain"></i>chain block</span><span><i class="sw blue"></i>blue, merged and paid</span><span><i class="sw red"></i>red, excluded</span><span><i class="sw"></i>pending, not merged yet</span><span>★ locked checkpoint</span></div>
<p class="note">Number is the chain block number, the same number the EVM reports; a block off the selected chain has none. Miner is the payout address the coinbase names. Proof records is how many shard proofs the block carries for earlier blocks. Click a row for the block.</p>
<button class="btn" id="more" type="button" style="margin-top:14px">Older blocks</button>
</div>
<div class="card" aria-label="Public API">
<div class="viz-head"><h2>Public API</h2><div class="eyebrow">JSON, cached 10 s</div></div>
<dl>
<dt>/api/stats</dt><dd><a href="/api/stats" class="hash">network hash rate, difficulty, block time, block reward now, blocks per day, DAA, blue score, height, last block, chain id, version</a></dd>
<dt>/api/supply</dt><dd><a href="/api/supply" class="hash">circulating by the emission rule, the 4,000,000,000 cap, the halving table, the 30-day ramp, the observer's coinbase check</a></dd>
<dt>/api/explorer</dt><dd><a href="/api/explorer?blocks=20" class="hash">?blocks=N, ?block=hash, ?height=N, ?address=addr, ?search=q</a></dd>
</dl>
<p class="note">Reward and supply come from the emission rule of the specification (section 2.5) at the node's DAA score; the observer checks the chain's coinbase sums against it every hour and the result is in /api/supply under check.</p>
</div>
</main>
<!-- footer:start -->
<footer class="foot">
<div class="wrap">
<div class="foot-grid">
<div class="foot-brand">
<a href="/" class="brand" aria-label="Igneum home"><svg class="mark" viewBox="0 0 1024 1024" width="26" height="26" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span></a>
<p>Mined by GPUs. Proven by fire.</p>
</div>
<nav class="foot-col" aria-label="Read">
<div class="eyebrow">Read</div>
<a href="/litepaper">Litepaper</a>
<a href="/litepaper#limits">What Igneum does not claim</a>
<a href="/litepaper#randomx">Igneum vs RandomX</a>
<a href="/litepaper#shoulders">Built on the shoulders</a>
<a href="/bench">Engineering log</a>
<a href="/evidence">Evidence</a>
<a href="/ledger">Ledger: every criticism</a>
</nav>
<nav class="foot-col" aria-label="Run">
<div class="eyebrow">Run</div>
<a href="/miner">The miner</a>
<a href="/wallet">The wallet</a>
<a href="/miners">GPU bench table</a>
<a href="/miner#fee">The dev fee</a>
<a href="/faucet">Testnet faucet</a>
</nav>
<nav class="foot-col" aria-label="Follow">
<div class="eyebrow">Follow</div>
<a href="/live">Live devnet</a>
<a href="/explorer">Explorer</a>
<a href="/litepaper#roadmap">Journey</a>
<a href="/metamask">Add Igneum to MetaMask</a>
<a href="https://github.com/igneum-network/spec" rel="noopener"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2.1c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2.9-.3 1.9-.4 2.9-.4s2 .1 2.9.4c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.2c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"></path></svg>GitHub, spec and vectors</a>
<a href="/miner#get">Miner downloads: devnet build</a>
<a href="mailto:hello@igneum.network">Report a flaw: hello@igneum.network</a>
<a href="https://github.com/igneum-network/spec/issues" rel="noopener">Or open an issue on the spec</a>
</nav>
</div>
<div class="foot-base">
<span class="foot-imprint">Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre · <a href="mailto:hello@igneum.network">hello@igneum.network</a></span>
<span>© 2026 Igneum. Nothing on this page is an offer to sell anything.</span>
<span class="theme" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></span>
<span class="mono">igneum.network</span>
</div>
</div>
</footer>
<script>
(function(){
// theme control: stores light or dark under igneum-theme; system clears it. The head applied the stored value before paint.
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
function cur(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
function paint(){var c=cur();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});}
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}
if(v==='system')document.documentElement.removeAttribute('data-theme');else document.documentElement.setAttribute('data-theme',v);paint();});});
paint();
})();
</script>
<!-- footer:end -->
<script type="module">
import { classify, hrefFor, ign, shortHash, hashrate, rel, int } from '/lib/explorer.mjs';
const $ = id => document.getElementById(id);
const esc = s => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
let oldest = 0, serverNow = 0, serverAt = 0;
const vnow = () => serverNow + (performance.now() - serverAt);
$('search').addEventListener('submit', async e => {
e.preventDefault();
const c = classify($('q').value);
if (c.type === 'none') { $('msg').textContent = 'Not a block hash, a transaction hash, a chain block number or an address.'; return; }
if (c.type === 'address') { location.href = hrefFor(c); return; }
$('msg').textContent = 'Looking.';
try {
const r = await fetch('/api/explorer?search=' + encodeURIComponent($('q').value.trim()));
const j = await r.json();
if (j.ok && j.href) location.href = j.href; else $('msg').textContent = j.error || 'Not found.';
} catch { $('msg').textContent = 'The API did not answer.'; }
});
function rowHtml(b) {
const sw = b.chain ? 'chain' : b.color;
const miner = b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}" title="${esc(b.evm_miner)}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : (b.miner ? `<a class="hash" href="/address/${esc(b.miner)}">${esc(shortHash(b.miner, 14, 4))}</a>` : '<span class="id">' + esc(b.miner_id || '?') + '</span>');
return `<tr data-href="/block/${b.hash}"><td><i class="sw ${sw}" title="${b.chain ? 'chain block' : b.color}"></i><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a>${b.locked ? ' ★' : ''}</td><td class="n">${b.number === null ? '<span style="color:var(--ash)">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${miner}<span class="id" style="margin-left:8px;font-size:12px">${esc(b.miner_id || '')}</span></td><td class="n">${b.tx_count === null ? 'n/a' : b.tx_count}</td><td class="n">${b.proof_records === null ? 'n/a' : b.proof_records}</td><td title="${new Date(b.ts).toISOString()}">${rel(vnow() - b.ts)}</td></tr>`;
}
async function loadBlocks(before) {
const r = await fetch('/api/explorer?blocks=50' + (before ? '&before=' + before : ''));
const j = await r.json(); if (!j.ok) throw new Error(j.error);
serverNow = new Date(j.now).getTime(); serverAt = performance.now();
const html = j.blocks.map(rowHtml).join('');
if (before) $('blocks').insertAdjacentHTML('beforeend', html); else $('blocks').innerHTML = html || '<tr><td colspan="8" class="empty">No blocks in the last 24 hours.</td></tr>';
if (j.blocks.length) oldest = j.blocks[j.blocks.length - 1].rx;
$('blk-eyebrow').textContent = (j.stale ? 'observer offline, last known' : 'newest first, every 5 s') + (j.network ? ', ' + j.network : '');
}
$('blocks').addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
$('more').addEventListener('click', () => { $('more').disabled = true; loadBlocks(oldest).catch(() => {}).finally(() => { $('more').disabled = false; clearInterval(timer); }); });
async function loadStats() {
const [s, p] = await Promise.all([fetch('/api/stats').then(r => r.json()), fetch('/api/supply').then(r => r.json())]);
document.body.classList.toggle('on', !s.stale); document.body.classList.toggle('off', !!s.stale);
$('st-status').textContent = s.stale ? 'OFFLINE' : 'LIVE';
$('st-age').textContent = s.age_s === null ? 'no observer update yet' : (s.stale ? `last update ${rel(s.age_s * 1000)}` : `${s.network || ''}, node ${s.node_version || '?'}`);
$('st-height').textContent = s.height === null ? 'n/a' : int(s.height);
$('st-count').textContent = `chain block number, ${int(s.block_count)} blocks in the DAG`;
$('st-daa').textContent = int(s.daa); $('st-blue').textContent = 'blue score ' + int(s.blue_score);
$('st-diff').textContent = s.difficulty === null ? 'n/a' : (s.difficulty >= 1e6 ? (s.difficulty / 1e6).toFixed(2) + ' M' : int(s.difficulty));
$('st-bt').textContent = s.block_time_measured_s === null ? 'target 1 s per block' : `${s.block_time_measured_s} s per block over 60 s, target 1 s`;
$('st-hps').textContent = hashrate(s.hashrate);
if (s.block_reward) { $('st-reward').innerHTML = esc(Number(s.block_reward.ign).toFixed(4)) + '<small>IGN</small>'; $('st-split').textContent = `${Number(s.block_reward.miner_ign).toFixed(4)} miner, ${Number(s.block_reward.proving_pool_ign).toFixed(4)} proving pool`; }
if (p.ok) {
$('st-supply').innerHTML = esc(int(Number(p.circulating_ign))) + '<small>IGN</small>';
$('st-cap').textContent = `of ${int(Number(p.max_supply_ign))}, ${(Number(p.circulating_ign) / Number(p.max_supply_ign) * 100).toFixed(3)}% by the rule`;
const d = p.halving.next_halving_in_s / 86400;
$('st-halving').innerHTML = esc(d >= 1 ? Math.floor(d).toLocaleString('en-GB') : (p.halving.next_halving_in_s / 3600).toFixed(1)) + '<small>' + (d >= 1 ? 'days' : 'h') + '</small>';
$('st-ramp').textContent = p.ramp.complete ? 'launch ramp complete' : `launch ramp at ${(p.ramp.factor_now * 100).toFixed(1)}%, full at DAA ${int(p.ramp.length_daa_s)}`;
}
}
const timer = setInterval(() => { loadBlocks().catch(() => {}); }, 5000);
setInterval(() => { loadStats().catch(() => {}); }, 10000);
loadBlocks().catch(e => { $('blocks').innerHTML = `<tr><td colspan="8" class="empty">${esc(e.message)}</td></tr>`; });
loadStats().catch(() => {});
</script>
</body>
</html>