commit 287ab9de7531aa3eb9268c9fe863ba9237aabb04
parent d0a327c9fcd0ec3e30bc2ba94b858ae93b30157f
Author: Joris Hartog <jorishartog@hotmail.com>
Date: Sun, 26 Jul 2026 12:16:20 +0200
Move public site to GitHub Pages
Diffstat:
4 files changed, 361 insertions(+), 140 deletions(-)
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
@@ -0,0 +1,37 @@
+name: Deploy GitHub Pages
+
+on:
+ push:
+ branches: ["main"]
+ paths:
+ - "www/**"
+ - ".github/workflows/pages.yml"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: www
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/docs/genesis.md b/docs/genesis.md
@@ -0,0 +1,39 @@
+# Starting The Genesis Node
+
+This is operator documentation for bootstrapping a Luun devnet. Most users should join an existing seed node instead.
+
+## Start Setup
+
+Start with a public P2P bind and a local-only management UI:
+
+```sh
+cargo run -- --p2p 0.0.0.0:9444 --http 127.0.0.1:18661
+```
+
+Open `http://127.0.0.1:18661`, set the wallet password, write down the recovery phrase, and finish setup.
+
+## Create Genesis
+
+Restart from a fresh chain database with `--genesis`:
+
+```sh
+cargo run -- --genesis --p2p 0.0.0.0:9444 --http 127.0.0.1:18661
+```
+
+Genesis bootstraps the chain with a 1 LUUN burn, creates launch tickets for the first blocks, measures an initial VDF delay, and leaves the starter wallet with spendable LUUN for early testing.
+
+## Invite Nodes
+
+Give other node operators your public P2P address:
+
+```text
+your-host.example:9444
+```
+
+They can join with:
+
+```sh
+cargo run -- --data-dir .luun --p2p 0.0.0.0:9445 --http 127.0.0.1:18661 --join your-host.example:9444
+```
+
+Keep the management UI bound to `127.0.0.1`.
diff --git a/docs/index.html b/docs/index.html
@@ -1,140 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>Luun</title>
- <style>
- :root {
- color-scheme: dark;
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
- background: #0f1012;
- color: #edf2f5;
- }
- * { box-sizing: border-box; }
- body { margin: 0; background: #0f1012; color: #edf2f5; }
- a { color: #d5f55f; }
- code { color: #c7f5ea; overflow-wrap: anywhere; }
- pre { margin: 0; overflow-x: auto; border: 1px solid #2a3035; border-radius: 8px; padding: 14px; background: #111316; }
- .hero { min-height: 78vh; display: grid; align-items: end; padding: 56px 22px 28px; background: linear-gradient(180deg, #15171a 0%, #0f1012 100%); }
- .wrap { width: min(980px, 100%); margin: 0 auto; }
- .mark { width: 54px; height: 54px; display: grid; place-items: center; border-radius: 8px; background: #d5f55f; color: #11140c; font-size: 28px; font-weight: 950; }
- h1 { margin: 24px 0 12px; font-size: clamp(44px, 9vw, 96px); line-height: .95; letter-spacing: 0; }
- h2 { margin: 0 0 12px; font-size: 25px; }
- h3 { margin: 0 0 10px; font-size: 17px; }
- p { max-width: 700px; color: #b8c2c8; font-size: 18px; line-height: 1.55; }
- .lead { color: #edf2f5; font-size: 22px; }
- .next { margin-top: 52px; color: #8d989f; font-size: 13px; font-weight: 800; text-transform: uppercase; }
- section { padding: 34px 22px; border-top: 1px solid #22282d; }
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; margin-top: 18px; }
- .card { border: 1px solid #2a3035; border-radius: 8px; padding: 16px; background: #181b1f; }
- .card p { margin: 0; font-size: 15px; }
- .steps { display: grid; gap: 14px; margin-top: 18px; }
- .step { display: grid; grid-template-columns: 38px minmax(0, 1fr); gap: 12px; align-items: start; }
- .num { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 999px; background: #d5f55f; color: #11140c; font-weight: 900; }
- .note { border-left: 3px solid #d5f55f; padding-left: 14px; color: #cbd3d7; }
- .footer { padding-bottom: 56px; color: #8d989f; }
- @media (max-width: 640px) {
- .hero { min-height: 70vh; }
- p { font-size: 16px; }
- .lead { font-size: 19px; }
- .step { grid-template-columns: 1fr; }
- }
- </style>
-</head>
-<body>
- <header class="hero">
- <div class="wrap">
- <div class="mark">L</div>
- <h1>Luun</h1>
- <p class="lead">A small experimental currency where blocks are finalized by burning LUUN, while new coins are introduced by proof-of-work mine actions.</p>
- <p>Luun is not a mainnet and not money yet. It is a devnet prototype for learning how a wallet, node, finalizer, miner, mempool, and peer network behave when real people run it on real machines.</p>
- <div class="next">Start a node below</div>
- </div>
- </header>
-
- <section>
- <div class="wrap">
- <h2>What Makes It Different</h2>
- <div class="grid">
- <div class="card">
- <h3>Burn To Finalize</h3>
- <p>Nodes burn LUUN to enter the block lottery. The top-ranked burner finalizes first; lower ranks can take over with extra VDF delay if the first one disappears.</p>
- </div>
- <div class="card">
- <h3>Mine To Issue</h3>
- <p>Proof-of-work mine actions introduce new LUUN. A miner chooses a fee rate for the finalizer; the rest of the 1 LUUN reward goes to the miner.</p>
- </div>
- <div class="card">
- <h3>Friendly Devnet</h3>
- <p>The current network is for testing with people you trust. Expect resets, bugs, and protocol changes.</p>
- </div>
- </div>
- </div>
- </section>
-
- <section>
- <div class="wrap">
- <h2>Run The First Node</h2>
- <p>Clone the repo, build it with Cargo, and start a fresh chain from an empty data directory.</p>
- <div class="steps">
- <div class="step">
- <div class="num">1</div>
- <div>
- <h3>Start Genesis</h3>
- <pre><code>cargo run -- --genesis --data-dir .luun-devnet --p2p 0.0.0.0:9444 --http 127.0.0.1:18661</code></pre>
- </div>
- </div>
- <div class="step">
- <div class="num">2</div>
- <div>
- <h3>Open The Local UI</h3>
- <p>Go to <code>http://127.0.0.1:18661</code>, set a password, write down the recovery phrase, and finish setup. The wallet file is encrypted with that password.</p>
- </div>
- </div>
- <div class="step">
- <div class="num">3</div>
- <div>
- <h3>Share Your P2P Address</h3>
- <p>Give friends your public host and P2P port, for example <code>your-host.example:9444</code>. Keep the management UI bound to <code>127.0.0.1</code>.</p>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section>
- <div class="wrap">
- <h2>Join A Friend</h2>
- <p>Use a separate data directory and join the seed node your friend gives you.</p>
- <pre><code>cargo run -- --data-dir .luun-friend --p2p 0.0.0.0:9445 --http 127.0.0.1:18661 --join your-friend-host:9444</code></pre>
- <p>After joining, open the local UI, set your password, back up your recovery phrase, and wait for your friend to send you LUUN. Then you can send transactions, burn for block leadership, or enable PoW mine actions.</p>
- </div>
- </section>
-
- <section>
- <div class="wrap">
- <h2>Important Safety Notes</h2>
- <div class="grid">
- <div class="card">
- <h3>Do Not Expose The UI</h3>
- <p>The management UI is password protected, but it should stay local. Use SSH tunneling or a private network if you need remote access.</p>
- </div>
- <div class="card">
- <h3>Back Up The Phrase</h3>
- <p>The encrypted wallet protects the file at rest. The recovery phrase is still the thing that restores the wallet.</p>
- </div>
- <div class="card">
- <h3>Expect Resets</h3>
- <p>This is a devnet. Chain state can be reset, protocol rules can change, and LUUN has no real-world value.</p>
- </div>
- </div>
- <p class="note">For more technical details, see the README in the repository.</p>
- </div>
- </section>
-
- <section class="footer">
- <div class="wrap">Luun devnet prototype.</div>
- </section>
-</body>
-</html>
diff --git a/www/index.html b/www/index.html
@@ -0,0 +1,285 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="color-scheme" content="dark">
+ <meta name="description" content="Luun is a small devnet currency prototype with burn-based block finalization and proof-of-work issuance.">
+ <title>Luun Devnet</title>
+ <style>
+ :root {
+ color-scheme: dark;
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ background: #0d0f10;
+ color: #edf2f5;
+ --bg: #0d0f10;
+ --panel: #15191b;
+ --panel-2: #101315;
+ --line: #273036;
+ --muted: #98a6ad;
+ --text: #edf2f5;
+ --green: #d5f55f;
+ --cyan: #8de9cd;
+ --blue: #8bdcff;
+ --amber: #ffd070;
+ }
+ * { box-sizing: border-box; }
+ body {
+ margin: 0;
+ background: var(--bg);
+ color: var(--text);
+ }
+ a { color: var(--green); text-decoration-thickness: 1px; text-underline-offset: 3px; }
+ code {
+ color: #c7f5ea;
+ overflow-wrap: anywhere;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
+ }
+ pre {
+ margin: 0;
+ overflow-x: auto;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 14px;
+ background: #0b0d0e;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .03);
+ }
+ .wrap { width: min(1060px, calc(100% - 44px)); margin: 0 auto; }
+ .topbar {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ border-bottom: 1px solid rgba(39, 48, 54, .9);
+ background: rgba(13, 15, 16, .82);
+ backdrop-filter: blur(12px);
+ }
+ .topbar .wrap {
+ display: flex;
+ justify-content: space-between;
+ gap: 18px;
+ align-items: center;
+ min-height: 58px;
+ }
+ .brand { display: flex; gap: 10px; align-items: center; font-weight: 900; }
+ .mark {
+ width: 32px;
+ height: 32px;
+ display: grid;
+ place-items: center;
+ border-radius: 8px;
+ background: var(--green);
+ color: #12170b;
+ font-weight: 950;
+ }
+ nav { display: flex; gap: 16px; flex-wrap: wrap; color: var(--muted); font-size: 13px; font-weight: 750; }
+ nav a { color: var(--muted); text-decoration: none; }
+ nav a:hover { color: var(--green); }
+ .hero { padding: 92px 0 48px; }
+ .hero-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.05fr) minmax(320px, .72fr);
+ gap: 32px;
+ align-items: end;
+ }
+ .eyebrow {
+ display: inline-flex;
+ gap: 8px;
+ align-items: center;
+ margin-bottom: 18px;
+ color: var(--green);
+ font-size: 12px;
+ font-weight: 900;
+ text-transform: uppercase;
+ }
+ .dot { width: 8px; height: 8px; border-radius: 999px; background: var(--green); box-shadow: 0 0 18px rgba(213, 245, 95, .75); }
+ h1 {
+ max-width: 760px;
+ margin: 0 0 18px;
+ font-size: clamp(48px, 9vw, 104px);
+ line-height: .92;
+ letter-spacing: 0;
+ }
+ h2 { margin: 0 0 12px; font-size: 28px; line-height: 1.1; letter-spacing: 0; }
+ h3 { margin: 0 0 8px; font-size: 16px; letter-spacing: 0; }
+ p { max-width: 720px; color: #b7c3c9; font-size: 17px; line-height: 1.6; }
+ .lead { color: #eef4f6; font-size: 21px; }
+ .actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
+ .button {
+ display: inline-flex;
+ align-items: center;
+ min-height: 42px;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 0 14px;
+ background: var(--panel);
+ color: var(--text);
+ font-size: 14px;
+ font-weight: 850;
+ text-decoration: none;
+ }
+ .button.primary { border-color: var(--green); background: var(--green); color: #11140c; }
+ .button:hover { border-color: var(--green); }
+ .status-panel {
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ overflow: hidden;
+ background: rgba(21, 25, 27, .82);
+ box-shadow: 0 24px 80px rgba(0, 0, 0, .24);
+ }
+ .status-head {
+ display: flex;
+ justify-content: space-between;
+ gap: 10px;
+ align-items: center;
+ padding: 12px 14px;
+ border-bottom: 1px solid var(--line);
+ color: var(--muted);
+ font-size: 12px;
+ font-weight: 850;
+ text-transform: uppercase;
+ }
+ .status-body { display: grid; gap: 1px; background: var(--line); }
+ .stat {
+ display: grid;
+ grid-template-columns: 126px minmax(0, 1fr);
+ gap: 12px;
+ padding: 12px 14px;
+ background: var(--panel-2);
+ }
+ .label { color: #87949b; font-size: 11px; font-weight: 850; text-transform: uppercase; }
+ .value { color: var(--text); font-weight: 850; }
+ .value.green { color: var(--green); }
+ section { padding: 38px 0; border-top: 1px solid rgba(39, 48, 54, .9); }
+ .section-head { display: flex; justify-content: space-between; gap: 18px; align-items: end; margin-bottom: 18px; }
+ .section-head p { margin: 0; max-width: 560px; font-size: 15px; }
+ .grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
+ .card {
+ min-width: 0;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 16px;
+ background: rgba(21, 25, 27, .88);
+ }
+ .card p { margin: 0; font-size: 15px; }
+ .tag {
+ display: inline-flex;
+ margin-bottom: 12px;
+ border: 1px solid #3b464d;
+ border-radius: 999px;
+ padding: 3px 8px;
+ color: var(--muted);
+ font-size: 11px;
+ font-weight: 850;
+ text-transform: uppercase;
+ }
+ .tag.green { border-color: rgba(213, 245, 95, .42); color: var(--green); }
+ .tag.cyan { border-color: rgba(141, 233, 205, .4); color: var(--cyan); }
+ .tag.blue { border-color: rgba(139, 220, 255, .4); color: var(--blue); }
+ .split {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(260px, .54fr);
+ gap: 18px;
+ align-items: start;
+ }
+ .note {
+ border-left: 3px solid var(--green);
+ padding-left: 14px;
+ color: #cbd3d7;
+ font-size: 15px;
+ }
+ .footer { padding-bottom: 60px; color: #87949b; font-size: 14px; }
+ @media (max-width: 820px) {
+ .hero { padding-top: 58px; }
+ .hero-grid, .split, .grid { grid-template-columns: 1fr; }
+ .section-head { display: grid; }
+ nav { display: none; }
+ .wrap { width: min(100% - 32px, 1060px); }
+ .stat { grid-template-columns: 1fr; gap: 4px; }
+ }
+ </style>
+</head>
+<body>
+ <div class="topbar">
+ <div class="wrap">
+ <div class="brand"><span class="mark">L</span><span>Luun</span></div>
+ <nav aria-label="Page sections">
+ <a href="#what">What is Luun</a>
+ <a href="#join">Join</a>
+ </nav>
+ </div>
+ </div>
+
+ <header class="hero">
+ <div class="wrap hero-grid">
+ <div>
+ <div class="eyebrow"><span class="dot"></span> Devnet prototype</div>
+ <h1>Luun</h1>
+ <p class="lead">An experimental currency where blocks are finalized by burning LUUN, while new coins are introduced by proof-of-work mine actions.</p>
+ <p>Luun is not a mainnet and not money yet. It is a small L1 lab for learning how a wallet, node, finalizer, miner, mempool, and peer network behave when real people run it on real machines.</p>
+ <div class="actions">
+ <a class="button primary" href="#what">What is Luun</a>
+ <a class="button" href="#join">How to join</a>
+ </div>
+ </div>
+ <aside class="status-panel" aria-label="Protocol snapshot">
+ <div class="status-head"><span>Protocol Snapshot</span><span>devnet</span></div>
+ <div class="status-body">
+ <div class="stat"><span class="label">Finalize</span><span class="value green">Burn lottery + VDF</span></div>
+ <div class="stat"><span class="label">Issue</span><span class="value">PoW mine actions</span></div>
+ <div class="stat"><span class="label">Wallet</span><span class="value">Encrypted local seed</span></div>
+ <div class="stat"><span class="label">Network</span><span class="value">One P2P TCP port</span></div>
+ </div>
+ </aside>
+ </div>
+ </header>
+
+ <main>
+ <section id="what">
+ <div class="wrap">
+ <div class="section-head">
+ <h2>What Is Luun?</h2>
+ <p>Luun combines proof-of-burn finalization, a VDF clock, and proof-of-work issuance.</p>
+ </div>
+ <div class="grid">
+ <div class="card">
+ <span class="tag green">PoB</span>
+ <h3>Proof Of Burn</h3>
+ <p>Nodes burn LUUN to enter the block lottery. The top-ranked burner finalizes first; lower ranks can take over with extra VDF delay if the first one disappears.</p>
+ </div>
+ <div class="card">
+ <span class="tag cyan">VDF</span>
+ <h3>Verifiable Delay</h3>
+ <p>The selected finalizer must run sequential VDF work before publishing a block. That delay is the chain's clock and gives fallback finalizers a clean way to take over.</p>
+ </div>
+ <div class="card">
+ <span class="tag blue">PoW</span>
+ <h3>Proof Of Work Issuance</h3>
+ <p>PoW mine actions introduce new LUUN. Miners create 1 LUUN at a time and choose the fee paid to the block finalizer that includes the action.</p>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <section id="join">
+ <div class="wrap split">
+ <div>
+ <h2>How To Join</h2>
+ <p>Ask for a public seed node address, then start Luun with a local data directory and that peer as your join target.</p>
+ <pre><code>cargo run -- --data-dir .luun --p2p 0.0.0.0:9445 --http 127.0.0.1:18661 --join seed.example:9444</code></pre>
+ <p>Open <code>http://127.0.0.1:18661</code>, set a password, back up your recovery phrase, and let the node sync. After you receive LUUN, you can send transactions, burn for block finalization, or enable PoW mine actions.</p>
+ <p class="note">Keep the management UI local. The P2P port is for node traffic; the wallet UI should stay on <code>127.0.0.1</code>.</p>
+ </div>
+ <aside class="card">
+ <span class="tag cyan">No Public Port?</span>
+ <h3>Outbound Nodes Work</h3>
+ <p>You can still join by connecting outbound to a public peer. Your actions can gossip through that upstream connection, and the node catches up again after reconnects.</p>
+ </aside>
+ </div>
+ </section>
+ </main>
+
+ <section class="footer">
+ <div class="wrap">Luun devnet prototype.</div>
+ </section>
+</body>
+</html>