igneum/docs/plans/miner-ui-3.md
igneum-labs 6e9bd00dbb miner-ui-3: the banner only (the project lead: 'lets not actually change the miner page just sort the banner')
Variant C and the Earnings reshaping reverted: Mine and Earnings are exactly as shipped in 0.3.14. Kept from the
polish round: every strip, ask and clock card on the brand tokens (the row surface, a 1 px ember hairline on top,
ash text, ember only on the dot and the chevron; no filled brown or mustard field anywhere; the update strip and the
job strip share .notice), the plain-language strip and event sentences with the technical line behind the chevron,
the header baseline and the pill wording. 36 UI tests pass.

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

27 KiB
Raw Blame History

Igneum Miner UI 3: the card is the product

6 October 2026. the project lead, 18:00 UTC: "as gorgeous as possible and as simple as possible but not lacking any features, think of this as an Apple product in terms of UI and UX, with tuning easy, buttons to tune each card again, or if automated then fair enough." The audit is docs/plans/miner-ui-3-audit.md. Branch miner-ui-3, worktree ../igneum-wt-miner-ui-3 from master b79f2cb. The 0.3.14 cut takes it. Ember Tune's engine (branch ember-tune, agent a855dcc4bd05e0615) is not touched: this plan reads its fields and posts to its routes.

1. The one job of each screen

Screen Its one job What it holds What left it
Welcome, GPU, address, key get to mining in two taps with an address the user owns as miner-ui-2, shorter words, the mark instead of the coin, the key sheet alone the aphorism, "seed", "secp256k1", "worker", the devnet vote-key note
Mine is the machine mining, and what is it worth the big button, the live total (MH/s, W, £ a day), the card rows, the tuning card, the node line, activity the next-program tile (to the node details), the four bare counts, the JSON in the feed
Earnings what did it make, where does it go money and IGN first, blocks, the address, change address, show key, the dev fee, the wallet the balance placeholder, the "once" eyebrow
Prove can this machine prove, and is it one switch, one tier sentence per card, one counts sentence, Set up when needed; details behind a disclosure the 95-word lead, the four zero tiles, the two hashes on the surface
Settings the switches, one sentence each tuning (goal, Ember Tune, Power control, electricity price), this machine, updates (one card), remote jobs (one row, history behind it), logs, appearance, advanced the per-card controls (to the card), the spec paragraph, the second "Off" sentence
Node gone as a section one line on Mine; "Details" opens the chain numbers, digest, switches, finality, version, clock the eleven-number page
Updates gone as a section one card on Settings; the update card and the strip as they are the jobs table on the surface
Logs the engineer's view the drawer as it is nothing

Four sections in the rail: Mine, Earnings, Prove, Settings. Logs and Quit in the foot. The rail keeps the arrow keys and aria-current.

2. The card row, the hero object

One row per card, ordered by performance (branch card-order ffb2bfa, View.shownCards). Everything a card can say is on its row; everything a card can be told is on its row or one tap under it.

[NV]  NVIDIA GeForce RTX 5090   DISCRETE         122 MH/s    290 W      £1.95 a day   61 °C   [Tune]  (o)
      ● mining · 32 GB · 3 blocks                            0.42 MH/W  at 28p/kWh
      Tuned 2 h ago · 2470 MHz at 100% · next check Sunday                                        ⌄
Part Rule
Name and model cd.name, the kind pill (Discrete, Integrated, External, Apple silicon), the tooltip as today (View.cardTitle)
State word always present, with the reason: mining, tuning: step k of n (plus "about N min left"), paused, waiting for the node, restarting in N s (plus the engine's message), starting, off (plus the reason when the engine gives one), held for a remote job: <title>, stopped after repeated faults, failed, not usable (Code 43) (plus the reboot hint), removed
Rate hash_now as 122 MH/s (one decimal under 100); blank with the state word when not mining; never a 0
Power power_w as 290 W with 0.42 MH/W under it (eff_mhw, or rate over watts); a card that reports no draw (Apple silicon, an integrated card) hides the cell and the sub-line says no power or temperature reading on Apple silicon once
Money £1.95 a day = W × 24 / 1000 × price / 100 at the electricity price; with no price the cell reads set a price and taps to the price field; with no draw the cell is hidden
Temperature 61 °C, amber from 86 °C (memory 90), ember from 92 °C (memory 95); hidden when not reported
Switch the card on or off, as today (api/cards with the whole list)
Tune Tune queues api/sweep/start {key}; during a run the button is Stop (api/sweep/stop); hidden for a card with no control and no measurement (sweep_supported false and vendor other)
Tune line the schedule sentence, section 4
Disclosure the chevron opens the card's details: the power cap slider (NVIDIA, with the watt number, the applied or Retry line), identities (stepper, one sentence), pin or unpin, the memory temperature, the clocks, the device facts, the last tune's table (tune_curve) when there is one

The rule from ember-tune.md 6a holds everywhere: a card never shows 0 MH/s without a reason word. A paused miner's row says paused; the switch stays on because the card is on. The old n/a cells are gone: a cell is shown with a number or not shown.

3. The Mine page

[ Start mining ]            122 MH/s   ·   290 W   ·   £1.95 a day   ·   3 blocks today
  mining on 1 of 1 card

Your cards                                                          [Tune all]
  row
  row

Tuning  Efficiency | Balanced | Maximum       about £1.95 a day at this goal
        Ember Tune on: once after install, then every 7 days. Last tune 2 h ago, next check Sunday.
        Power control [switch] Lets the app set NVIDIA power and clock limits. Windows asks once.

Node synced · 6 peers · 109,859 blocks · read 5 s ago                                   Details ⌄

Activity                                                                          Open the log
  strip (today's blocks on a 10-minute line)
  the last 8 events, one line each
Element Rule
The big button the only primary (ember) control on the page. Start mining / Stop mining / Tuning (disabled, "mining again in about N min") / Held / Stopping. View.toggle, with ember-tune's tuning and held states.
The live total hash_total MH/s; W = the sum of power_w over present cards; £ a day from that sum; blocks today = found in the last 24 h is not on the state, so "N this run" (accepted_session) with the lifetime count in the sub-line
Tune all queues api/sweep/start for every present, enabled, tunable card in list order (the engine runs one at a time). Hidden when Ember Tune is off fleet-wide (settings.tuning_off), where the line says why.
Goal a three-way segmented control, settings.tune_goal efficiency / balanced / rate (labelled Maximum), POST /api/tune/goal {goal}. The consequence line: at Efficiency the tuned watts (sweep_watts summed) at the price; at Maximum the default watts (power_default_w summed); Balanced between. A build without the route (0.3.13) gets a toast and the control stays on its old value.
Schedule sweep_at and settings.tune_period_s (default 604,800): "Last tune 2 h ago, next check Sunday" per the last-tuned card; "Not tuned yet: the first tune starts 2 min into steady mining" when nothing has run; "Tuning now: RTX 5090, step 7 of 9" while one runs.
Power control one switch, one sentence. Shown on Mine only when an NVIDIA card is present and control is off (the fix where the problem is); always on Settings.
Node line View.nodeWords; Details opens the old Node page's content in place: the chain numbers (headers, DAA score, difficulty, tips, blue score, each with its one-line meaning), the digest with Copy, the switches with the next one, finality, the version, the clock card when the clock is off (the clock card also shows above the big button when it blocks mining).
Activity the blocks canvas at 110 px with "N blocks in the last 10 min · N in the last hour"; the feed shows the newest 8 events, a line cut at 140 characters, a JSON tail replaced by "(details in the log)"; a link opens the drawer

4. Tuning in words

State The row's tune line Where else
never run, Ember Tune on Not tuned yet: starts after 2 min of steady mining the Tuning card's schedule line
running Tuning: step 7 of 9 · about 4 min left with a thin progress bar (tune_step / tune_steps) and the Stop button; the state word reads tuning: step 7 of 9 and the rate stays live the strip (ember-tune's tuneNotice), the big button
tuned Tuned 2 h ago · 2470 MHz at 100% · next check Sunday, the Tuned line's numbers (tune_line: 122.3 MH/s at 290 W, 0.422 MH/W) in the details the Tuning card
from the fleet prior Tuned 2 min ago from the fleet prior, confirmed · next check Sunday
measure only (Apple, NVIDIA with Power control off, AMD on Linux) Measured 122 MH/s at 290 W (0.42 MH/W) as it runs and the reason from sweep_note (measure only on Apple silicon: the system sets the clocks and the power) Power control switch on Mine for the NVIDIA case
pinned Your cap stays pinned at 80% · measured ... with Unpin in the details
stopped Tuning stopped: a remote job took the GPU until the next run
fleet pause Tuning paused fleet-wide by the signed manifest on the Tuning card; the Tune buttons hidden Settings
no control, no measurement (an integrated card, vendor other) no tune line, no button

Next check = sweep_at + settings.tune_period_s, as the weekday when under 7 days away, else the date; "due now" when sweep_at is 0 and the card mines. The engine also re-tunes on a driver or program change; the line does not predict that.

5. Earnings

£0.00 earned     IGN: nothing is bought or sold on devnet
0.0000 IGN       from 0 proofs
23,056 blocks    lifetime · 0 this run · 1 in 100 to the dev fee (0 so far)   [dev fee switch]
£1.95 a day      electricity at 28p/kWh for 290 W                             Set the price

Rewards address  0xdd44…86E8  [Copy]   made on this machine
  Change address ⌄   → a box, Change, then in place: "Pay 0x12…34 from the next block?  Confirm  Cancel"
  Show my key ⌄      → in place: "Show the private key on screen? Anyone who sees it can spend."  Show  Cancel
                      then the key box, Copy, Hide, the file path
  [Open the wallet]  the balance is in the wallet

Money first, IGN second, as asked. Devnet has no price for IGN, so the £ earned line says why it is £0.00 instead of showing a placeholder; the electricity line is real money and is shown as a cost. When a market price exists the engine adds price_gbp_per_ign and the line fills in (owed, engine).

6. Prove

Prove on this machine  [switch]
  RTX 5090: proves while it mines (32 GB; a full shard needs 20.4 GB).
  RTX 4070: cannot prove a full shard (12 GB; a full shard needs 20.4 GB).
  Apple M5 Max: proves on the CPU, slowly.
  State: idle · nothing assigned · 0 assigned · 0 proven · 0 paid · 0.0000 IGN
  [Set up]  About 20 minutes, once.           (only when the prover is not installed)
  Details ⌄  verifier (word and reason), the program id and the aggregator id with Copy, the segments line

The tier sentence per card: NVIDIA with 24 GB or more "proves while it mines"; NVIDIA under 24 GB "cannot prove a full shard (N GB; a full shard needs 20.4 GB)"; Apple silicon "proves on the CPU, slowly"; AMD and other "cannot prove yet (the prover is CUDA only)". The 20.4 GB and the 24 GB rule are the app's own words today (index.html, Prove lead); the engine's proving.available and backend win when they disagree.

7. Settings

Plain rows, one sentence each, grouped:

Group Rows
Tuning goal (segmented) · Ember Tune (switch: "Tunes every card for hashes per watt: once after install, then every 7 days, and after a driver or program change.") · Power control (switch: "Lets the app set NVIDIA power and clock limits. Windows asks for administrator rights once. Off, NVIDIA cards are measured only.") · Electricity price (pence per kWh; the £ figures use it) · Hill climb (switch, Ember 2, when tune_climb is on the state)
This machine Start at login · Name · Allow remote jobs from Igneum ("Signed jobs run here once and report back.") with "History" opening the table and the signing key · Appearance: System / Light / Dark
Updates one card: "Igneum Miner 0.3.13 · up to date, checked 13 min ago" · Check · Install now when ready · "Install updates by itself" switch
Logs Copy the log · Show the log · the two folders
Advanced Vote on finality checkpoints · Trust proof records (devnet, confirm in place, restarts the node) · Open the live devnet page · the machine id

The dev fee moved to Earnings (it is money). Identities and the power cap moved to the card.

8. Confirmations in place

No confirm(), no dialogs (the viewer never shows them). A destructive or costly action turns its own row into a question with two buttons:

Action The row says
Quit Quit Igneum Miner? Mining stops first, then the node. Quit Cancel
Change address Pay 0x12…34 from the next block? The miner restarts. Confirm Cancel
Show my key Show the private key on screen? Anyone who sees it can spend what the address holds. Show Cancel
Trust mode Include unverified proof records? Devnet only; the node restarts. Turn on Cancel
Stop a tune, stop mining, switch a card off, Tune all, the dev fee, identities no question: each reverts in one tap and the toast says what happened

9. Type, spacing, colour

Token Value Use
--t-xs 11, --t-sm 12, --t-base 13, --t-md 14, --t-lg 15, --t-xl 17, --t-num 24, --t-hero 34, --t-h2 28, --t-h1 44 px eight sizes; Unbounded only for the page title, the big button, the hero numbers and the row's rate; IBM Plex Sans for words; IBM Plex Mono for labels, units and small numbers
--s-1 4, --s-2 8, --s-3 12, --s-4 16, --s-5 24, --s-6 32 px one spacing scale; cards pad --s-5, rows pad --s-4, gaps --s-3
radius 16 card, 12 row, 10 button, 999 pill
dark obsidian #0C0C0E page, graphite #16161A card, #111114 row, lines #2A2A30 the brand
light #F4F1EC (bone) page, #FFFFFF card, #FAF8F5 row, lines #E2DED8, ink #16161A, ash #6B6B70 prefers-color-scheme: light and [data-theme=light]; ember stays #F2541B, molten darkens to #B8731F for text on light
ember the big button, the one primary per view, the rate, errors one accent
molten live states (mining, synced), the pill

Contrast: every text on its background at 4.5:1 or more (ash on obsidian 5.9:1; ash on bone 5.2:1).

10. Phone width and the narrow window

Width Layout
1180 px and up rail 196 px, the hero in one row, the rows with every cell
900 to 1180 rail folds to icons, the hero wraps to two lines
720 to 900 rail 76 px, the row's money and temperature cells go under the name as a second line
under 720 the rail becomes a bottom tab bar (Mine, Earnings, Prove, Settings; Logs and Quit under Settings), the hero stacks, every row is two lines (name and state; numbers in a 2 by 2 grid), the big button full width, 16 px gutters, no horizontal scroll

11. What the engine is asked for (none of it built here)

Field or route Why Owner
settings.tune_goal, settings.power_price_pence, settings.tune_period_s, POST /api/tune/goal the goal, the price, the schedule ember-tune (exists at e9738dd)
tune_step, tune_steps, tune_eta_s, tune_plan, tune_curve, states tuning and held the running line, the details table ember-tune (exists)
watts_total on mining and pounds_per_day the tray tip and the menu bar; the UI sums the cards itself engine, owed
price_gbp_per_ign £ earned when a market exists engine, later
address.balance_wei the balance on Earnings (miner-ui-2 follow-up) engine, owed

Until a field arrives the UI treats it as unset: no goal control change is sent to a build without the route (the toast says "needs the Ember Tune update"), the price is kept in the page's own storage as a fallback, the schedule line says "not tuned yet".

12. Tests

view.test.mjs grows with: the row model for every state word (mining, tuning with step and eta, paused, waiting, restarting with the message, off with the reason, held, faulted, failed, unusable, removed), the money line at a price and without one, the power and temperature cells hidden when not reported, the tune line for never, running, tuned, prior, measured, pinned, stopped and fleet-paused, the next-check weekday, the prove tier sentence per vendor and memory, the node line, the goal consequence, the quit and address confirmations' words. tune-line.test.mjs is ember-tune's version (the row word, the button, the strip). notices.test.mjs and update-card.test.mjs are unchanged and pass.

13. The build (6 October 2026, evening)

Branch miner-ui-3, three UI files rewritten, nothing on the Rust side (the engine is read as it is; the Ember fields are read when present and treated as unset when a build lacks them). Screenshots of the result beside the audit's: docs/plans/miner-ui-3/n00-*.png to n26-*.png (the mock on port 4317 from this worktree, the rig, the Mac, tuning, tuned with the details open, the node details, earnings with the address ask, prove, settings, the quit ask, paused, syncing, the clock, the update card, the job strip, the logs, 900 px, 390 px, light).

File What
app/igneum-app/ui/index.html four pages behind the rail; the Mine hero (big button, the live total: MH/s, W, £ a day, blocks); the Tuning card (goal, schedule, Power control when it is the fix); the node line with Details; Activity with the strip and eight events; Earnings (money rows, the dev-fee switch, the address, Change address and Show my key as disclosures with their asks in place); Prove (switch, tier list, one counts line, Set up, Details); Settings (Tuning, This machine with the jobs row and History, Appearance, the update card, Logs, Advanced with the trust ask); the quit ask strip; the key sheet with the key first; the welcome with the mark, not the retired coin
app/igneum-app/ui/app.css dark and light token sets (prefers-color-scheme and [data-theme]), the row grid (.gl-main, .nums, .acts, .gl-tune, .gl-details), the totals, the segmented control, the disclosures, the asks, the bottom tab bar under 720 px, the folded rail under 1000 px
app/igneum-app/ui/app.js Notices with ember-tune's tuneNotice; UpdateCard.NAME is "Igneum Miner" (was "Igneum Ember"); View adds rowWord, cells, poundsPerDay, money, effOf, wattsTotal, noReading, tuneWords, nextCheck, schedule, goalWords, nodeLine, proveTier, proveLine, eventLine, addressAsk, trustAsk and ember-tune's tuneWord, tuneEta, tuningCard and toggle states; TuneLine is ember-tune's plus pounds; the DOM block renders the four pages, the row with its details (cap slider, identities, pin, telemetry, the tune table, the facts), the asks, the goal (POST api/tune/goal, a toast when the build lacks it), the price (the engine's power_price_pence when set, else the page's own storage), the appearance; `?tune=running
app/igneum-app/ui/view.test.mjs 7 new tests: the row word per state (paused on an on card, held, tuning, starting, failed), money and the cells, the tune line for every state, the next check, the schedule and the goal, the prove tier and line, the node line, the activity line, the asks
app/igneum-app/ui/tune-line.test.mjs ember-tune's version (e9738dd) as is, so the ember-tune merge carries no test change
app/igneum-app/ui/update-card.test.mjs one expectation: the card's name

node --test on the four UI files: 35 pass. The Rust side is untouched, so the app's unit tests are as master's; the 0.3.14 shipper runs them on PC 2 as usual (the rule: test suites run on the PCs).

The tick list (section 3 of the audit)

# Feature Where it is now
1 Setup screens and the key sheet as before; the address screen's button says Continue until "Use my own address" is picked
2 Start / stop the big button
3 Per-card switch the row
4 Rate, temperature, power per card; totals the row's cells (left out when not reported); the hero's total with W and £
5 Blocks found, this run, last 10 min, last hour, dev-fee count, chain height the hero (this run, lifetime), Activity's line, the dev fee on Earnings, the height on the node line
6 Next program countdown and epoch the node details
7 Blocks strip Activity, 110 px
8 Activity feed Activity, eight lines, JSON cut
9 Hot-plug states the row (the words and the strip as before)
10 Proving switch, setup, counts, segments, verifier, program ids Prove: the switch, the tier list, one line, Set up, Details
11 Address with Copy, source, blocks Earnings
12 Show / hide the key, the file path Earnings, "Show my key" with the ask
13 Change the address Earnings, "Change address" with the ask
14 Open the wallet Earnings
15 Node state, height, peers, version, chain numbers, digest, switches, finality, sync ETA the node line and its Details
16 Clock card with Sync clock Mine, above the hero (and the strip on the setup screens)
17 Version, update note, Check, Install now, auto-update Settings, one card
18 The update card and the strip unchanged
19 Remote jobs: allow, Check now, note, history, signing key Settings, This machine: the switch, the line, History
20 Power cap slider, applied / Retry, telemetry, efficiency the row's details; MH/W on the row
21 Identities the row's details
22 Ember Tune switch, Tune / Stop / Unpin, the tune line Settings (switch); the row (Tune, Stop, the line); Unpin in the details; Tune all on the card list
23 Power control Settings, and Mine's Tuning card when an NVIDIA card has it off
24 Start at login, vote, dev fee, name, trust, live page Settings (vote and trust under Advanced), the dev fee on Earnings
25 Copy the log, show the log, the folders Settings, Logs
26 The log drawer unchanged
27 Quit the rail, with the ask strip instead of a dialog
28 The pill, the rail foot the pill (with "tuning"); the foot has the name, the address, the uptime
29 Keyboard the rail's arrows (left and right too), Escape on the card and the quit ask, Enter on the price and the time box
30 The URL switches as before, plus ?tune=
new Goal, Tune all, the price, £ a day, MH/W on the row, the tune schedule, the prove tier, the node line, light mode, appearance, the bottom tab bar this build

Owed

What Who
watts_total and pounds_per_day on the state for the tray tip and the menu bar; address.balance_wei; price_gbp_per_ign the engine (section 11)
The wallet's copy of the update card still says "Igneum Ember" (app/igneum-wallet/ui/update-card.js) the wallet
A Windows and a PC screenshot of the row with a real NVIDIA card (the telemetry cells, the cap slider, Retry) the 0.3.14 cut, first thing to look at
The row's state word while tuning carries the meta after it ("tuning: step 7 of 9 · measuring 441 W · 32 GB · ...") and is cut on a narrow row a later pass: drop the meta while tuning
The merge with ember-tune: app.js takes this branch's file (it already carries ember-tune's UI words and test); the engine files merge by themselves the 0.3.14 shipper

14. Polish round (6 October 2026, after the 0.3.14 cut)

the project lead, on the live Mac app: "I do think this could look better", at the job strip reading "Job: 0.3.14 is published: re-read the manifest and install now (...) done after 0 min. Report uploaded." Branch rebased on master 630b537.

What Where
No raw job, manifest or relay text on a user surface. The strip reads "A job from the team ran: update check, 0 min." / "A job from the team is running: shard benchmark, 6 min. Proving shard 3 of 8." / "A job from the team failed: build, after 32 min." / "Updated to 0.3.14 at 18:52."; the technical line (the job's title, summary, RESULT line, exit code) sits behind a chevron; the × stays. Notices.jobWord maps a kind or an id prefix to a user's word (update check, restart, log collection, shard benchmark, build, tuning check, a script). app.js Notices
The Activity feed speaks in the app's voice: View.plainEvent maps every engine event string (src/engine.rs et al., 80 patterns) to a sentence ("Block found by Apple M5 Max", "Rule settings read from the team", "The node stopped (code 101); restarting", "A job from the team ran: update check, 0 min"); the engine's own line is the row's tooltip; the kind word becomes a coloured dot. Unknown lines keep their words with a JSON tail cut. app.js View, renderMine
The header: title, grey subtitle and the pill share one baseline; the pill is a sentence with a coloured dot: "Mining · 511 MH/s" (molten), "Tuning" (molten), "Paused", "Syncing the node", "Starting the worker", "Not mining" (grey), "Node restarting", "Node failed", "Engine not answering" (ember), "Stopping", "Detecting cards", "Setting up". View.pill. app.js, app.css
Three Mine layouts were offered behind `?variant=a b
390 px: the strip's text, chevron and × on one line. Light and dark checked. app.css

Screenshots: p04/p05 the plain job strip closed and open, p06 the updated strip, p07 the header paused, p08 the activity feed, p09/p12 light, p10/p11 390 px. Tests: 36 pass.

15. the project lead's ruling: the banner only (6 October 2026, evening)

the project lead: "lets not actually change the miner page just sort the banner". Variant C and the Earnings reshaping are reverted; the Mine and Earnings screens are exactly as shipped in 0.3.14. The three variant screenshots are gone with them. What stays from the polish round:

Kept Where
The strip's look: the row surface (one step lighter than the page), a 1 px ember hairline along the top, ash text, ember only on the state dot and the chevron; the update strip and the job strip share the one .notice; the asks and the clock card carry the same hairline. No filled brown or mustard field anywhere (the rail's active item, the pill, the ghost-on button, the option, the stop ring, the log hit and mark lost their tints; only ::selection keeps a colour). app.css
The strip's words: "A job from the team ran: update check, 0 min." / "Updated to 0.3.14 at 18:52.", the technical line behind the chevron, the × kept app.js Notices
The Activity feed in the app's voice (View.plainEvent, the engine line as the tooltip, a kind dot) app.js View, renderMine
The header: title, subtitle and pill on one baseline; the pill a sentence with a coloured dot (View.pill) app.js, app.css

Screenshots: r01-mine-strip-dark.png, r02-mine-strip-light.png (Mine as shipped, the job strip showing), r03-earnings-dark.png. Tests: 36 pass.