diff --git a/docs/design/site-polish-2026-10-04.md b/docs/design/site-polish-2026-10-04.md new file mode 100644 index 000000000..06cc5c202 --- /dev/null +++ b/docs/design/site-polish-2026-10-04.md @@ -0,0 +1,101 @@ +# Site polish, 4 October 2026 + +Branch `site-polish`. The brief: one header on every page, the litepaper's tabs fixed, every element of every page checked at 390, 768 and 1440 px in light and dark, performance measured before and after, copy law on every sentence, the build green. This file records what was broken, what changed, the numbers, and what was left alone. + +## 1. What was broken + +| # | Where | Fault | Root cause | +|---|---|---|---| +| 1 | Litepaper, whole-paper mode | Every contents click, pager click and back press landed on the section for a moment and then slid back to the Abstract | `show()` always scrolled to the top of `
`, never to the section. In one-section mode the section is the top of the article, so the fault was invisible; in whole-paper mode the browser's own fragment jump landed first and the smooth scroll then dragged the reader to the top | +| 2 | Litepaper, one-section mode | A deep link (`/litepaper#limits`) opened on the cover, not the section | The browser's fragment scroll ran while the section was still `display:none`; the router then showed the section with `scroll=false` | +| 3 | Litepaper, phone | The sticky contents row covered the heading after a jump | No `scroll-margin-top`; the hand-tuned 70 px offset did not match the row's real height (99 px) | +| 4 | Litepaper, keyboard and screen readers | After choosing a section, focus stayed in the contents list | Focus was never moved | +| 5 | Litepaper | 29 subsection headings had no ids, so only the 17 sections were addressable by URL | Never generated | +| 6 | Header, every page | Five different headers: 11 links on the homepage, 10 on the live page (section anchors into the homepage), 6 plain links on the evidence and log pages, no header at all on the litepaper (a cover with two arrow links) | Each page carried its own copy | +| 7 | Header, mobile | The menu on the live page closed on tap-outside but not on Escape and not on a link tap; the evidence, log and litepaper pages had no menu, their links wrapped | Three different scripts, two pages without one | +| 8 | Header, every page | The mark was the bare flame, not the master mark in its black square | Pre-dates the brand master of 4 October | +| 9 | Live page, phone | The page scrolled sideways to 420 px at 390 px | Three legend captions were `white-space:nowrap` spans ("one lane per miner, colour from its id; hover or tap a block") | +| 10 | Live page, phone | The hash-rate cell clipped to "264.1 M…" | 20 px Unbounded in a 125 px cell with `text-overflow:ellipsis` | +| 11 | Homepage, 390 px and 1440 px | The headline wrapped to four lines with "fire." alone on the last | `clamp(40px, 7vw, 76px)` never fitted "Mined by GPUs." in the column at either end | +| 12 | Homepage | The journey block arrived after a fetch of `journey.json`, after first paint, and pushed the page down | Rendered from a fetch | +| 13 | Every page | A render-blocking stylesheet from fonts.googleapis.com, then the woff2 files from a second origin; no font fallback metrics, so the swap moved every line | Google Fonts link in each `` | +| 14 | 404 | Vercel's plain text "NOT_FOUND" | No `404.html` | +| 15 | Sitemap | `/evidence` missing; every lastmod 3 October | Not updated | +| 16 | Log page share card | `og.png?v=2` while every other page was on `?v=3` | The build template was not bumped with the pages | +| 17 | Evidence table | Column sort only by mouse (the `` was the click target, not focusable); filter chips had no pressed state | Markup | + +Items 9, 10, 11 and 13 were found by the checks in this round, not by eye. + +## 2. What changed + +### Shared chrome (one source, injected by the build) + +`site/partials/head.html`, `nav.html`, `footer.html`. `site/build.mjs` injects them into every page between ``, `` and `` markers, marks the active link with `aria-current="page"`, and inlines `journey.json` into the homepage between `` markers. The committed pages carry the injected copy, so they are right with or without a build; CI runs the build and the link check on every push. + +- Header: the master mark (black square, no ring) at 36 px, the wordmark, five links in one order on every page (Litepaper, Live devnet, Engineering log, Evidence, GitHub) and the Get the miner button. Sticky, 68 px, blurred backdrop. Under 901 px a menu: opens on the button, closes on any link, a tap outside, Escape (focus returns to the button) or a resize past 900 px; `aria-expanded` and `aria-controls` set. A skip link to `#main` on every page. +- Footer: one footer, six Read links and four Follow links, the same everywhere. Page-specific lines (the evidence "as of" date, the log's "generated at build time") moved into the page body above it. +- Litepaper: the chrome follows the paper's scheme (light by default, dark with the system) through `--ui-*` tokens; every other page is obsidian. +- Fonts: self-hosted latin subsets in `site/fonts/` (Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500; OFL), 139 KB for all eight, 118 KB for a typical page, `font-display:swap`, the two first-paint faces preloaded. Fallback faces (`Unbounded Fallback` on Arial Black, `Plex Sans Fallback` on Arial, `Plex Mono Fallback` on Courier New) carry `size-adjust`, `ascent-override` and `descent-override` computed from the font tables with fonttools, so the swap does not move the layout (a deep link into the litepaper lands within 3 px before and after the fonts arrive, and is re-aimed on `document.fonts.ready`). +- Site-wide: `text-wrap:balance` on h1 to h3, `text-wrap:pretty` on paragraphs and list items; one `:focus-visible` ring; one `prefers-reduced-motion` rule that stops every animation and transition. + +### Litepaper + +New section router. The hash names a section or any heading inside one, in both reading modes. In-page links are routed by a click delegate (`pushState` + `go()`), never by the browser's fragment jump; back and forward replay through `popstate`; every scroll clears the sticky bar and, on a phone, the contents row (`--lp-off`, measured from the real heights; `[id]{scroll-margin-top:var(--lp-off)}` so a native jump lands in the same place); focus moves to the heading with `preventScroll`; every h3 gets an id from its text (29 added, so `/litepaper#what-is-not-here` works). The mode buttons carry `aria-pressed` and stack vertically in the desktop sidebar (they wrapped to two lines before). The cover lost its duplicate brand block and arrow links. + +### Homepage + +Header reduced to the five links; the in-page sections are still there for scrolling. The headline is capped at `9cqw` of its column so it is two lines at every width. Journey data is inlined by the build (no fetch, no shift); dates read "4 Oct 2026" with the day shown once per group; the toggle carries `aria-expanded`; the NOW label lists the active phases with commas and balances its lines. A preconnect to cdn.jsdelivr.net for the light client's libraries. + +### Live page + +Legend captions wrap. The hash-rate value shows its unit in small mono beside the number. Idle, the scene is drawn 30 times a second instead of 60 (a pointer or a pinned block gets every frame); the DAG canvas backing store is capped at 1.5x. The proving strip's "not yet activated" line breaks at its semicolon when wider than the strip on a phone. `?perf=1` exposes `window.__igneumPerf` (frames, draw milliseconds) for the next measurement. + +### Evidence + +Column headings are real buttons (keyboard sort, `aria-sort` kept); filter chips carry `aria-pressed`; a "scroll sideways" hint above the 1,100 px table under 1,140 px; the "as of" line moved into the page. + +### Engineering log (build template) + +Contents in a labelled box: sticky and scrollable beside the article on desktop, a 40 vh scroll box on a phone (57 entries). Headings land under the bar (`scroll-margin-top`). `og.png?v=3`. + +### 404 + +`site/404.html`: the four pages as cards. Vercel serves it for any unknown path (checked locally with the same clean-URL rules; `noindex`). + +### Headers and sitemap + +`vercel.json`: fonts `immutable` for a year, images and the manifest a day with a week of stale-while-revalidate; HTML stays `must-revalidate`. `sitemap.xml`: `/evidence` added, lastmod 4 October. + +## 3. Checks + +`check.mjs` (scratchpad, Chrome for Testing 154, never the owner's Chrome) over `/`, `/litepaper`, `/live`, `/bench`, `/evidence` and a 404 path at 390, 768 and 1440 px: no horizontal overflow, no console errors, the five links in order and the right one active, the square mark present, the menu opens, closes on tap-outside and on Escape with focus back on the button; on the litepaper in both modes at 390 and 1440: a contents click, a pager click, back, a deep link to a section and to an h3 on reload, and Enter on a focused pill each land within 2 px of the measured offset with focus on the heading. `node site/build.mjs` and `tools/ci/link-check.mjs` (245 internal links, 0 broken) pass. + +## 4. Numbers + +Static, from the files (before = the committed site at 8fd492c, after = this branch): + +| Page | HTML before (gzip) | HTML after (gzip) | Third-party requests before | After | +|---|---|---|---|---| +| / | 57,261 B (17,265) | 74,065 B (21,810) | 3 (fonts CSS, 2 preconnects) + the woff2 files | 1 (jsdelivr, light client only) | +| /litepaper | 63,628 B (20,556) | 79,208 B (24,957) | 1 + woff2 | 0 | +| /live | 47,680 B (15,640) | 56,357 B (17,777) | 3 + woff2 | 0 | +| /evidence | 56,729 B (18,899) | 69,890 B (22,493) | 1 + woff2 | 0 | +| /bench | 267,259 B (94,723) | 280,179 B (98,289) | 1 + woff2 | 0 | + +The HTML grew by the inlined font-face block, the shared chrome and, on the homepage, the inlined journey (about 4 KB gzipped a page). In exchange every page lost a render-blocking stylesheet from a third origin and two DNS lookups. + +Live page, idle draw cost (Chrome for Testing, 2x display, canvas in view, 10 s, `?perf=1`; taken while cargo builds and a reliability run held the Mac, so an upper bound): 1440 px, 30.0 draws/s, 69 ms of draw in 10 s = 0.7% of one core; 390 px, 30.0 draws/s, 60 ms = 0.6%. Before the change the loop drew at the display rate (60/s) with a 2x backing store, so the same work was about 2.6x this, approximate. Off screen or in a hidden tab the loop stops, as before. + +Lighthouse (mobile simulation, performance only, before on a frozen copy of the committed site at port 4174, after on port 4173, Chrome for Testing 154 downloaded into the scratchpad): queued at 19:45Z under `tools/lock/with-lock.sh measure` and not run by the time this was written. The measure lock was held by reliability runs from 19:16Z onwards (pid 66963, then pid 5534 from 20:18Z) with three cargo builds beside them and a load average of 258, and a paint time taken under that is not a number. The runner is `scratchpad/lh.sh` (before and after, five pages, score, FCP, LCP, TBT, CLS, speed index, bytes, requests, render-blocking resources); run it under the measure lock on a quiet machine and paste the table here. What can be stated without a timer: every page lost its only render-blocking third-party stylesheet and the two origins behind it; the fonts a page needs are one origin, preloaded, cached a year; the homepage lost the post-paint journey fetch; the fallback metrics hold the layout within 3 px across the swap. + +Deep-link landing: within 2 px of the measured offset in every case but one. In one-section mode at 1440 px the Finality section is short, "What is not here" is its last heading, and the page cannot scroll far enough to put it under the bar; it lands at the page's maximum scroll, 3 px short. A padding trick would add a blank screen under every section, so it is left as it is. + +## 5. Left alone, and why + +- `site/api/live.mjs`, `checkpoint.mjs`, `log.mjs`: the observer agent's. The homepage light-client card currently reads "could not verify: voter 0 key does not hash to its vote_key_hash" on production as well as locally; that is the checkpoint data, not the page, and is reported, not fixed here. +- `site/verify/`: the light client, unchanged. +- The GitHub link (`github.com/igneum-network/spec`, 200 on 4 October) stays; `docs/fud-fixes.md` X1 asked for it to go only while private. +- Download buttons: the homepage's Windows, macOS, Linux and HiveOS buttons link to `#journey` as before (no public build yet); no `dl.` URL exists on the site, the scrub replaces the host name on the log page. +- The litepaper's light scheme by default: the paper is the one light surface on purpose. +- Three glowing active phase cards on the homepage: kept, stopped under reduced motion. +- The evidence table's 1,100 px minimum width: it is a 7-column reference table; it scrolls inside its box and says so on narrow screens. diff --git a/site/404.html b/site/404.html new file mode 100644 index 000000000..ee977c9f4 --- /dev/null +++ b/site/404.html @@ -0,0 +1,177 @@ + + + + + +Page not found. Igneum + + + + + + + + + + + + + + + + + + + +
+
+
404
+

Nothing is mined here.

+

That address is not on igneum.network. It may have moved, or the link had a typo. These four pages are everything the site has.

+ +
+
+ + + + + diff --git a/site/bench.html b/site/bench.html index b54d940b3..427ef5ea3 100644 --- a/site/bench.html +++ b/site/bench.html @@ -12,14 +12,14 @@ - + - + @@ -28,48 +28,153 @@ - + + + + + -
-
IGNEUM
+ + + + + +
+
+
57 entries, newest at the bottom

Engineering log

Every measurement the project has made, newest at the bottom, written by the people and agents who ran it, with the commands and hardware. Prototype numbers are not mining numbers and say so.

+
- +

Igneum bench log

Append-only. Every number here was measured on the machine named, on the date given.

2026-10-03 proto-metal / igneum-bench, first run

@@ -309,7 +414,39 @@ footer{border-top:1px solid var(--line);padding-block:32px 48px;font-size:13px;c

4 October 2026, first machine in the United States: a Windows laptop on an Intel integrated GPU, synced and voting

A colleague's Windows laptop in the United States installed Igneum Miner 0.3.3 from the downloads link at about 18:52 UTC. Its node took the 38,000 headers and blocks from one peer, the seed node, in about eight minutes across the Atlantic. The only card is an Intel UHD integrated GPU: the OpenCL worker runs at 1.46 MH/s and found one block in its first four minutes; the identity's votes on checkpoints 1202 and 1203 were accepted by the network, so a laptop with no discrete card takes part in finality. Machine id 37ba0461 in the console; app log run win-37ba0461-20261004-185342.

-
© 2026 Igneum. Generated from the repository at build time. Nothing on this page is an offer to sell anything.
-
+

Generated from the repository at build time. Times are UTC. Machine names are model names.

+ + + + \ No newline at end of file diff --git a/site/build.mjs b/site/build.mjs index d94e6175f..93ac85bdc 100644 --- a/site/build.mjs +++ b/site/build.mjs @@ -43,7 +43,22 @@ function md(src) { return { html: out.join('\n'), toc }; } -const mark = ``; +// Shared chrome: fonts and tokens (head), the nav bar and the footer live once in site/partials/ and are injected into every +// page between HTML comment markers ( ... , nav, footer; journey on the homepage). +// The committed pages carry the injected copy, so they are right with or without a build; the build keeps them in step. +const partial = name => readFileSync(join(here, 'partials', name), 'utf8').trim(); +const HEAD = partial('head.html'), NAV = partial('nav.html'), FOOT = partial('footer.html'); +function navFor(active) { + if (!active) return NAV; + const re = new RegExp(`([\\s\\S]*?`); + if (!re.test(html)) throw new Error(`${file}: missing ... markers`); + return html.replace(re, () => `\n${content}\n`); +} const ORIGIN = 'https://igneum.network'; const svgIcon = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E"; // Search and share metadata. Same set as the hand-written pages (index, litepaper, live); keep them in step. @@ -58,14 +73,14 @@ function meta(title, desc, path) { - + - + @@ -75,60 +90,77 @@ function meta(title, desc, path) { `; } -function page(title, desc, bodyHtml, toc, note, { path = '/bench', heading = title } = {}) { - const nav = toc.filter(t => t.lvl === 2).map(t => `
  • ${esc(t.t)}
  • `).join(''); +function page(title, desc, bodyHtml, toc, note, { path = '/bench', heading = title, active = 'bench' } = {}) { + const h2s = toc.filter(t => t.lvl === 2); + const nav = h2s.map(t => `
  • ${esc(t.t)}
  • `).join(''); return ` ${meta(title, desc, path)} - + +${HEAD} + -
    -
    ${mark}IGNEUM
    + +${navFor(active)} + +
    +
    +
    ${h2s.length} entries, newest at the bottom

    ${esc(heading)}

    ${note}

    +
    - +
    ${bodyHtml}
    -
    © 2026 Igneum. Generated from the repository at build time. Nothing on this page is an offer to sell anything.
    -
    +

    Generated from the repository at build time. Times are UTC. Machine names are model names.

    + + +${FOOT} + `; } @@ -208,4 +240,20 @@ if (existsSync(join(docs, 'bench-log.md'))) { writeFileSync(jp, JSON.stringify(j, null, 2) + '\n'); built.push('journey.json (' + j.log.length + ' entries)'); } + +// The hand-written pages: shared head, nav (with the active link marked) and footer injected in place; the homepage also +// gets journey.json inlined so the phases and the log render without a fetch and without a layout shift. +const journey = JSON.parse(readFileSync(join(here, 'journey.json'), 'utf8')); +const PAGES = [['index.html', ''], ['litepaper.html', 'litepaper'], ['live.html', 'live'], ['evidence.html', 'evidence'], ['404.html', '']]; +for (const [file, active] of PAGES) { + const p = join(here, file); + if (!existsSync(p)) throw new Error(`missing page ${file}`); + let html = readFileSync(p, 'utf8'); + html = inject(html, 'head', HEAD, file); + html = inject(html, 'nav', navFor(active), file); + html = inject(html, 'footer', FOOT, file); + if (file === 'index.html') html = inject(html, 'journey', ``, file); + writeFileSync(p, html); + built.push(file); +} console.log('built: ' + built.join(', ')); diff --git a/site/evidence.html b/site/evidence.html index cd6fbda69..22e219674 100644 --- a/site/evidence.html +++ b/site/evidence.html @@ -28,49 +28,153 @@ - + + + + + -
    -
    IGNEUM
    + + + + + +
    +
    +
    30 claims · 5 labels · 4 Oct 2026

    Evidence

    +

    Every claim the homepage and the litepaper make, one row each, with one of five labels: designed (a decision, no code), implemented (code with passing test vectors), tested by the team (measured by the project on a named machine, in the engineering log), reproduced externally (a third party ran the published command and got the published result) and reviewed independently (a named outside reviewer published a finding on that version). Nothing on this chain has been reproduced externally or reviewed independently; every row says so. A label belongs to the exact version in the row, and an audit of one version never covers a newer one. The 12-node cloud network of 4 October 2026 is the project's own, so its rows are tested by the team, not reproduced externally.

    designed
    6

    A decision in the design document or the specification. No code, or a stub

    @@ -79,7 +183,8 @@ footer{border-top:1px solid var(--line);padding-block:32px 48px;font-size:13px;c
    reproduced externally
    0

    None yet. The repository is private until January 2027

    reviewed independently
    0

    None yet. What review would cost and who pays is in the funding plan

    -
    +
    +

    The table is wider than this screen. Scroll it sideways.

    @@ -123,15 +228,49 @@ footer{border-top:1px solid var(--line);padding-block:32px 48px;font-size:13px;c
    #ClaimStatusVersion or commitReproducible testResult, date, machineIndependent verification
    reproduced externallyreviewed independentlyA named reviewer's published finding on that version. Funding for review is docs/plans/funding.md
    anythe row's status falls backA new version of the code or rule the row names
    -
    © 2026 Igneum. Statuses are honest as of 4 October 2026 and change only through this page. Nothing on this page is an offer to sell anything.
    -
    +

    Statuses are honest as of 4 October 2026 and change only through this page.

    + + + + - - - + + + + + + + + + + +
    @@ -470,12 +524,14 @@ footer .wrap{padding-block:48px 32px} Litepaper
    +
    -
    + - - + + + diff --git a/site/live.html b/site/live.html index d2d0f5ae9..69e86d14b 100644 --- a/site/live.html +++ b/site/live.html @@ -28,9 +28,72 @@ - - - + + + + + + + + + -
    +
    devnet v0

    Live devnet

    @@ -184,9 +236,9 @@ footer{border-top:1px solid var(--line);padding-block:48px 32px}
    -
    blockschainincluded, paidpendingexcludedjust arrivedselected chainone lane per miner, colour from its id; hover or tap a block
    -
    finalityfinallocked checkpointproposedreads "paused" whenever under two thirds of the weight is signing
    -
    provingshard plannedprovingverified, prover colourpaidwhere proofs land behind the tiphover or tap a cell
    +
    blockschainincluded, paidpendingexcludedjust arrivedselected chainone lane per miner, colour from its id; hover or tap a block
    +
    finalityfinallocked checkpointproposedreads "paused" whenever under two thirds of the weight is signing
    +
    provingshard plannedprovingverified, prover colourpaidwhere proofs land behind the tiphover or tap a cell
    @@ -214,11 +266,12 @@ footer{border-top:1px solid var(--line);padding-block:48px 32px}
    -