igneum/app/igneum-app/ui/index.html

337 lines
18 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Igneum Miner</title>
<meta name="color-scheme" content="dark">
<link rel="icon" href="mark.svg" type="image/svg+xml">
<link rel="stylesheet" href="app.css">
</head>
<body class="phase-welcome" data-phase="welcome">
<header class="top">
<div class="brand">
<img src="mark.svg" width="30" height="30" alt="">
<span class="word">IGNEUM</span><span class="miner">MINER</span>
</div>
<div class="top-right">
<div class="pill" id="pill"><span class="dot"></span><span id="pill-text">starting</span></div>
<button class="icon-btn" id="btn-settings" title="Settings" aria-label="Settings" hidden>
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3h.1a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8v.1a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"></path></svg>
</button>
</div>
</header>
<div class="banner clock" id="clock-banner" hidden>
<span id="clock-banner-text"></span>
<button class="btn small primary" id="clock-sync">Sync clock</button>
<span class="hint mono" id="clock-banner-hint"></span>
</div>
<div class="banner update" id="update-banner" hidden>
<span id="update-text">A new version of Igneum Miner is ready.</span>
<button class="btn small primary" id="update-install" hidden>Install now</button>
<button class="btn small primary" id="update-open" hidden>Open the download</button>
<button class="btn small ghost" id="update-later">Later</button>
<span class="prog" id="update-prog" hidden><i></i></span>
</div>
<div class="banner job" id="job-banner" hidden>
<span id="job-text"></span>
<button class="btn small ghost" id="job-hide">Hide</button>
<pre class="job-results mono" id="job-results" hidden></pre>
</div>
<main id="main">
<!-- 1. welcome -->
<section class="screen" id="screen-welcome">
<div class="hero">
<div class="coin-wrap"><img class="coin" src="coin.png" width="148" height="148" alt=""></div>
<div class="eyebrow ember">devnet v4 &middot; nothing is bought or sold</div>
<h1>Igneum Miner</h1>
<p class="lead">Mined by GPUs. Proven by fire. This app runs a node on this machine and mines Igneum with your graphics card.</p>
<div class="three">
<div class="tile">
<div class="k">01</div>
<div class="t">Runs a node</div>
<div class="s">Syncs the chain from the seed node, usually under a minute.</div>
</div>
<div class="tile">
<div class="k">02</div>
<div class="t">Mines on your GPU</div>
<div class="s">A new program every hour. The next one compiles while you mine.</div>
</div>
<div class="tile">
<div class="k">03</div>
<div class="t">Pays your address</div>
<div class="s">Block rewards go to an EVM address you choose or one made here.</div>
</div>
</div>
<div class="cta">
<button class="btn primary big" id="btn-begin">Get started</button>
</div>
<p class="seedline mono">Nobody from Igneum will ever ask for your seed.</p>
</div>
</section>
<!-- 2. cards -->
<section class="screen" id="screen-cards">
<div class="step">
<div class="eyebrow">step 1 of 2</div>
<h2>Your GPU</h2>
<p class="sub" id="cards-sub">Asking the graphics cards to report in.</p>
<div class="cards" id="cards-list">
<div class="card detecting" id="cards-detecting">
<div class="spinner"></div>
<div>
<div class="t">Detecting</div>
<div class="s mono" id="detect-text">loading the Metal worker</div>
</div>
</div>
</div>
<p class="note" id="cards-note" hidden></p>
<p class="note" id="cards-power" hidden>Igneum caps each NVIDIA card's power at 80% of its default limit to keep it stable (an RTX 5090 at full power hard-crashed in the field). This needs administrator rights once, when mining starts; the limit goes back to what it was on quit. The slider sets the cap per card.</p>
<p class="note" id="cards-help" hidden>Each card you switch on gets its own worker. Identities take turns on the card and each one votes and pays separately; 8 suits a big card, 2 a small one, 1 an integrated GPU.</p>
<div class="cta">
<button class="btn primary" id="btn-cards-next" disabled>Continue</button>
<button class="btn ghost" id="btn-cards-retry" hidden>Detect again</button>
</div>
</div>
</section>
<!-- 3. address -->
<section class="screen" id="screen-address">
<div class="step">
<div class="eyebrow">step 2 of 2</div>
<h2>Where should rewards go?</h2>
<p class="sub">Every block this machine finds pays one EVM address. Pick one way.</p>
<div class="options">
<label class="option on" id="opt-generate">
<input type="radio" name="mode" value="generate" checked>
<span class="radio"></span>
<span class="body">
<span class="t">Make me an address <span class="tag">recommended</span></span>
<span class="s">A secp256k1 key is made on this machine and stored in the app folder with the file locked to your user. You see the key once, to save it.</span>
</span>
</label>
<label class="option" id="opt-paste">
<input type="radio" name="mode" value="paste">
<span class="radio"></span>
<span class="body">
<span class="t">Use my own address</span>
<span class="s">Paste an EVM address you control. 0x followed by 40 hex characters.</span>
<input type="text" class="addr-input mono" id="addr-input" placeholder="0x" spellcheck="false" autocomplete="off">
<span class="err" id="addr-err" hidden>That is not an EVM address. 0x followed by 40 hex characters.</span>
</span>
</label>
</div>
<p class="err" id="start-blocked" hidden></p>
<div class="cta">
<button class="btn primary big" id="btn-start">Start mining</button>
<button class="btn ghost" id="btn-address-back">Back</button>
</div>
</div>
</section>
<!-- 4. dashboard -->
<section class="screen" id="screen-dashboard">
<div class="strip">
<div class="cell big ember">
<div class="k">hash rate</div>
<div class="v"><span id="d-hash">0.0</span><span class="unit">MH/s</span></div>
<div class="s" id="d-hash-sub">waiting for the worker</div>
</div>
<div class="cell big">
<div class="k">blocks found</div>
<div class="v" id="d-blocks">0</div>
<div class="s" id="d-blocks-sub">accepted by the node</div>
</div>
<div class="cell big" id="d-node-cell">
<div class="k">node</div>
<div class="v state" id="d-node">starting</div>
<div class="s" id="d-node-sub">opening the database</div>
</div>
<div class="cell big">
<div class="k">next program</div>
<div class="v" id="d-eta">--:--</div>
<div class="s" id="d-eta-sub">waiting for the node</div>
</div>
</div>
<div class="grid">
<div class="col-main">
<div class="card">
<div class="card-head">
<div class="eyebrow"><span class="dot small"></span>your blocks</div>
<div class="stats mono"><span>last 10 min <b id="d-found-10">0</b></span><span>last hour <b id="d-found-60">0</b></span><span>chain <b id="d-chain-blocks">0</b></span></div>
</div>
<canvas id="dag" aria-hidden="true"></canvas>
<div class="legend"><span><i class="sw ember"></i>block this machine found</span><span><i class="sw glow"></i>just accepted</span><span><i class="sw line"></i>one minute</span></div>
</div>
<div class="card">
<div class="card-head"><h3>Cards</h3><div class="eyebrow" id="d-cards-eyebrow">1 worker</div></div>
<div class="gpu-tiles" id="d-cards"><div class="empty">No card yet.</div></div>
<div class="gpu-off mono" id="d-cards-off" hidden></div>
</div>
</div>
<div class="col-side">
<div class="card">
<div class="card-head"><h3>Node</h3><div class="eyebrow" id="d-node-net">devnet v4</div></div>
<div class="kv">
<div><span class="k">height</span><span class="v mono" id="n-blocks">0</span></div>
<div><span class="k">headers</span><span class="v mono" id="n-headers">0</span></div>
<div><span class="k">peers</span><span class="v mono" id="n-peers">0</span></div>
<div><span class="k">daa score</span><span class="v mono" id="n-daa">0</span></div>
<div><span class="k">difficulty</span><span class="v mono" id="n-diff">0</span></div>
<div><span class="k">tips</span><span class="v mono" id="n-tips">0</span></div>
</div>
<div class="clock-card" id="n-clock" hidden>
<p class="clock-msg" id="n-clock-msg"></p>
<div class="row"><button class="btn small primary" id="n-clock-sync">Sync clock</button><span class="note mono small" id="n-clock-result"></span></div>
<p class="note" id="n-clock-hint"></p>
</div>
<p class="note" id="n-note"></p>
</div>
<div class="card">
<div class="card-head"><h3>Finality</h3><div class="eyebrow">miner-only</div></div>
<div class="kv">
<div><span class="k">last lock</span><span class="v mono" id="f-lock">none yet</span></div>
<div><span class="k">age</span><span class="v mono" id="f-age">n/a</span></div>
<div><span class="k">votes sent</span><span class="v mono" id="f-votes">0</span></div>
</div>
<p class="note" id="f-note">Locks appear once the miner votes on checkpoints.</p>
</div>
<div class="tile" id="tile-proving">
<div class="h">Proving</div>
<div class="kv">
<div><span class="k">state</span><span class="v mono" id="pv-state">off</span></div>
<div><span class="k">assigned</span><span class="v mono" id="pv-assigned">0</span></div>
<div><span class="k">submitted</span><span class="v mono" id="pv-submitted">0</span></div>
<div><span class="k">paid</span><span class="v mono" id="pv-paid">0</span></div>
</div>
<p class="note" id="pv-note">Off. Settings switches it on: this machine proves the shards the chain assigns to its keys.</p>
<div class="row" id="pv-setup-row" hidden><button class="btn small" id="pv-setup">Set up</button></div>
</div>
<div class="card">
<div class="card-head"><h3>Events</h3><div class="eyebrow">newest first</div></div>
<div class="feed" id="d-events"><div class="empty">No events yet.</div></div>
</div>
</div>
</div>
</section>
</main>
<!-- the key sheet, shown once -->
<div class="sheet-wrap" id="sheet-key" hidden>
<div class="sheet">
<div class="eyebrow ember">shown once</div>
<h2>Save your key</h2>
<p class="sub">This key controls the rewards address. Keep a copy somewhere safe. Anyone with the key can spend what the address holds.</p>
<div class="field">
<div class="k">rewards address</div>
<div class="box mono"><span id="key-address"></span><button class="btn tiny" data-copy="key-address">Copy</button></div>
</div>
<div class="field">
<div class="k">private key</div>
<div class="box mono key"><span id="key-private"></span><button class="btn tiny" data-copy="key-private">Copy</button></div>
</div>
<p class="note">Stored at <span class="mono" id="key-file"></span>, readable by your user only. Settings can show it again.</p>
<p class="note">On devnet the vote keys are test keys derived from the miner's label. Mainnet vote keys will be random and stored like this wallet.</p>
<label class="check"><input type="checkbox" id="key-ack"><span>I have saved my key</span></label>
<div class="cta">
<button class="btn primary big" id="btn-key-done" disabled>Start mining</button>
</div>
</div>
</div>
<!-- settings -->
<div class="panel-wrap" id="settings" hidden>
<aside class="panel">
<div class="panel-head"><h3>Settings</h3><button class="icon-btn" id="btn-settings-close" aria-label="Close">&times;</button></div>
<div class="panel-body">
<div class="field">
<div class="k">rewards address</div>
<div class="box mono"><span id="s-address"></span><button class="btn tiny" data-copy="s-address">Copy</button></div>
<div class="row">
<input type="text" class="addr-input mono" id="s-address-input" placeholder="paste a new address" spellcheck="false" autocomplete="off">
<button class="btn small" id="s-address-save">Change</button>
</div>
<div class="err" id="s-address-err" hidden></div>
<button class="btn small ghost" id="s-reveal" hidden>Show my key</button>
<div class="box mono key" id="s-key-box" hidden><span id="s-key"></span><button class="btn tiny" data-copy="s-key">Copy</button></div>
</div>
<div class="field">
<div class="k">this machine</div>
<div class="row">
<input type="text" class="addr-input" id="s-name" placeholder="a name for this machine" maxlength="40" spellcheck="false">
<button class="btn small" id="s-name-save">Rename</button>
</div>
<p class="note">A label for you only. Keys and labels come from the machine id <span class="mono" id="s-mid"></span>, never from the computer name.</p>
</div>
<div class="field">
<div class="k">cards</div>
<div class="cards compact" id="s-cards"></div>
<div class="row between"><p class="note">Switch a card on or off, set its identities. Only that card's worker restarts; the node keeps running.</p><button class="btn small" id="s-cards-save">Apply</button></div>
</div>
<div class="field">
<label class="switch"><input type="checkbox" id="s-vote"><span class="track"></span><span>Vote on finality checkpoints</span></label>
<label class="switch"><input type="checkbox" id="s-prove"><span class="track"></span><span>Prove assigned shards (proving v0; on a Mac the CPU prover is slow)</span></label>
<label class="switch"><input type="checkbox" id="s-login"><span class="track"></span><span>Start at login</span></label>
</div>
<div class="field">
<div class="k">version</div>
<div class="row between"><span class="mono" id="s-version"></span><span class="row"><button class="btn small primary" id="s-install" hidden>Install now</button><button class="btn small" id="s-update">Check now</button></span></div>
<label class="switch"><input type="checkbox" id="s-auto-update"><span class="track"></span><span>Install updates by itself at a safe moment</span></label>
<p class="note" id="s-update-note"></p>
</div>
<div class="field">
<div class="k">remote jobs</div>
<div class="row between"><label class="switch"><input type="checkbox" id="s-jobs-allow"><span class="track"></span><span>Allow remote jobs from Igneum (signed)</span></label><button class="btn small" id="s-jobs-check">Check now</button></div>
<p class="note">Igneum publishes signed jobs (a benchmark, a script, a file to fetch, logs to collect, a restart) next to the update manifest. This machine runs each one once and reports to the Igneum log intake. Only jobs signed by the key below run; nothing else can send one.</p>
<p class="note mono small" id="s-jobs-key"></p>
<p class="note" id="s-jobs-note"></p>
<div class="job-history" id="s-jobs-history"></div>
</div>
<div class="field">
<div class="k">folders</div>
<p class="note mono small" id="s-node-dir"></p>
<p class="note mono small" id="s-log-dir"></p>
</div>
<div class="field">
<button class="btn small ghost" id="s-live" hidden>Open the live devnet page</button>
</div>
</div>
</aside>
</div>
<!-- the log drawer -->
<div class="drawer" id="drawer">
<div class="drawer-head">
<div class="chips" id="log-chips">
<button class="chip on" data-src="">all</button>
<button class="chip" data-src="app">app</button>
<button class="chip" data-src="node">node</button>
<button class="chip" data-src="miner">miner</button>
<button class="chip" data-src="watch">watch</button>
</div>
<label class="check small"><input type="checkbox" id="log-follow" checked><span>follow</span></label>
</div>
<pre class="log" id="log"></pre>
</div>
<footer class="bottom" id="bottom" hidden>
<div class="left">
<button class="btn small" id="btn-pause">Pause</button>
<button class="btn small ghost" id="btn-logs">Logs</button>
</div>
<div class="mid mono" id="foot-status"></div>
<div class="right">
<span class="mono dim" id="foot-version"></span>
<button class="btn small ghost danger" id="btn-quit">Quit</button>
</div>
</footer>
<div class="toast" id="toast" hidden></div>
<script src="app.js"></script>
</body>
</html>