orgchain: Super Testnet restyled for lineage (lineage.yolopreneur.lol/orgchain/)

Skin and copy only: src/lineage.css over style.css with lineage's tokens, a rehearsal guide and lineage branding,
relative paths (base './'), the theme follows the system under its own key, and Inscriboor downloads link to
supertestnet.lol (the extension only connects there). Unit tests 32/32; checked in Chrome at 1280 and 390 wide,
light and dark, through a full root → birth → recursive inscription run with no CSP or script errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4upF5LVwmPDDqrhdUfnXh
This commit is contained in:
teahubxyzandClaude Opus 5.5 committed 2026-10-14 16:06:04 -07:00
1 parent 96876db762
commit 6d48c5c8ff
14 files changed
+200 -20

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
# Orgchain (branch `orgchain`)
Super Testnet restyled for lineage, served at https://lineage.yolopreneur.lol/orgchain/.
- Same lab and code as `main`. The differences are a skin and copy: `src/lineage.css` (loads after `style.css` and
points its tokens at lineage's), a rehearsal guide and lineage branding in `index.html`, the lineage favicon,
relative paths (`vite.config.js` `base: './'`, the recursive preview, license links), the theme following the system
setting under its own storage key, and Inscriboor downloads linking to supertestnet.lol (the extension only connects
there, so the local test wallet is the path here).
- Build: `npm ci && npm run build`, then copy `dist/` to `ventures/lineage/orgchain/` on `teahubxyz/time` `gh-pages`.
Headers (CSP and the rest, matching supertestnet.lol's) come from `ventures/lineage/_headers`, scoped to
`/orgchain/*`.
- Keep in step with `main`: rebase this branch onto `main`, rebuild, recopy.
+23 -13
View File
@@ -2,28 +2,38 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#f7931a"> <meta name="theme-color" content="#141414">
<meta name="description" content="A private Bitcoin playground. Mine fake coins, inscribe a thought, and follow it into a block."> <meta name="description" content="Super Testnet in lineage's clothes: rehearse an org's lineage (root, births, badges) as inscriptions on a private toy Bitcoin chain in your browser, with pretend money.">
<title>Super Testnet — your own little Bitcoin universe</title> <title>Orgchain — rehearse an org on a small chain · Lineage</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg"> <link rel="icon" type="image/svg+xml" href="favicon.svg">
</head> </head>
<body> <body>
<header> <header class="band">
<a class="brand" href="#"><span class="mark" aria-hidden="true"></span> SUPER TESTNET <span class="version">v0</span></a> <div class="band-in">
<div class="header-actions"><span class="network"><i></i> PRIVATE LOCAL CHAIN</span><button id="theme-toggle" class="theme-toggle quiet" type="button" aria-label="Toggle color theme">☀ Light</button></div> <div>
<h1 class="wordmark">Orgchain</h1>
<p class="lede"><b>Rehearse an org on a small chain.</b> Mint a root, give birth to children, award a badge, all as inscriptions on a private toy Bitcoin chain in this tab, with pretend money.</p>
</div>
<div class="flags">
<span class="flag hz">Test coins</span>
<span class="flag">Private chain</span>
<a class="flag" href="../">Lineage ↗</a>
<button id="theme-toggle" class="flag" type="button" aria-label="Toggle color theme">☾ Dark</button>
</div>
</div>
</header> </header>
<main> <main>
<section class="hero"><div><p class="eyebrow">BITCOIN, WITH ROOM TO EXPERIMENT</p><h1>Your own little<br>Bitcoin universe.</h1><p class="intro">Mine a block. Inscribe a thought. See it land in your wallet.<br>All in your browser, all with pretend money.</p></div><div class="orbit" aria-hidden="true"><div class="cube"><svg viewBox="0 0 100 100" width="82" height="82" fill="none" stroke="currentColor" stroke-width="5" aria-hidden="true"><path d="M35 17v12m12-12v12M35 76v12m12-12v12M24 29h25c22 0 22 23 0 23H24m0 0h28c22 0 22 24 0 24H24m7-47v47"/></svg></div><span>YOUR CHAIN. YOUR PACE.</span></div></section> <section class="rehearse blk" aria-labelledby="t-rehearse"><h2 class="tab" id="t-rehearse">Rehearsal <span class="sub">a lineage in four moves</span></h2><div class="panel"><ol class="moves"><li><b>Root.</b> Fund a wallet, then inscribe the org with metaprotocol <code>lineage/v0</code> and metadata like <code>{"lineage":"root","name":"yolopreneur"}</code>.</li><li><b>Birth.</b> Inscribe a child with the root as its parent. Only the parent's holder can: the parent is spent to make the child, and the child carries the parent's ID on-chain (ord tag 3).</li><li><b>Generations.</b> Children can be parents too: <code>time</code> under the root, <code>docscope</code> under <code>time</code>, as deep as the tree goes.</li><li><b>Badge.</b> Inscribe a badge once, like <code>{"lineage":"badge","skill":"launch","belt":"green"}</code>, then mint each award as a child of it with the badge as delegate, so every award shows the same mark.</li></ol><p class="later"><b>Not in this lab yet:</b> handing an award to a seat, graduation (moving a venture's inscription to its own new root) and closing (burning a parent so no more children can be born). Those need transfers and burns, which this lab doesn't do.</p></div></section>
<aside class="notice"><strong>Test coins only.</strong> This is a private simulation, not Bitcoin testnet or mainnet. Local-wallet keys stay in this browser, unencrypted. Inscriboor keys stay in the extension. Never load real keys or send real funds here.</aside> <aside class="notice"><strong>Test coins only.</strong> This is a private simulation, not Bitcoin testnet or mainnet. Local-wallet keys stay in this browser, unencrypted. Inscriboor keys stay in the extension. Never load real keys or send real funds here. Nothing on Orgchain is a real org, key or badge.</aside>
<div id="status" role="status" aria-live="polite">Choose Inscriboor or a local test wallet to start your first loop.</div> <div id="status" role="status" aria-live="polite">Choose Inscriboor or a local test wallet to start your first loop.</div>
<section class="workspace"> <section class="workspace">
<article class="panel wallet"><div class="panel-title"><span class="step">01</span><h2>Your test wallet</h2><span id="wallet-state" class="tag">NOT CREATED</span></div> <article class="panel wallet"><div class="panel-title"><span class="step">01</span><h2>Your test wallet</h2><span id="wallet-state" class="tag">NOT CREATED</span></div>
<div id="empty-wallet"><p>One wallet. A whole chain to play with.</p><button id="connect-inscriboor" class="primary">Get Inscriboor ↓</button> <button id="create-wallet" class="quiet">Use local test wallet</button><p id="inscriboor-status" class="muted">Looking for the extension…</p><details class="install-help"><summary>Install Inscriboor</summary><ol><li>Download and unzip Inscriboor.</li><li>Open <code>chrome://extensions</code> (or Brave extensions).</li><li>Turn on Developer mode.</li><li>Choose <strong>Load unpacked</strong> and select the unzipped <code>extension</code> folder.</li><li>Refresh this page. The button above will change from <strong>Get Inscriboor</strong> to <strong>Connect Inscriboor</strong>.</li></ol></details></div> <div id="empty-wallet"><p>One wallet. A whole chain to play with.</p><button id="create-wallet" class="primary">Use local test wallet</button> <button id="connect-inscriboor" class="quiet">Get Inscriboor ↓</button><p id="inscriboor-status" class="muted">Looking for the extension…</p><details class="install-help"><summary>Install Inscriboor</summary><p class="muted">Inscriboor 0.2.4 connects on supertestnet.lol only. On Orgchain, use the local test wallet.</p><ol><li>Download and unzip Inscriboor.</li><li>Open <code>chrome://extensions</code> (or Brave extensions).</li><li>Turn on Developer mode.</li><li>Choose <strong>Load unpacked</strong> and select the unzipped <code>extension</code> folder.</li><li>Refresh this page. The button above will change from <strong>Get Inscriboor</strong> to <strong>Connect Inscriboor</strong>.</li></ol></details></div>
<div id="active-wallet" hidden><p class="label">FAKE BTC BALANCE</p><div class="balance"><span id="balance">0</span><small>BTC</small></div><p id="reserved" class="muted"></p><label for="address">Local regtest-format address</label><input id="address" readonly><button id="export-wallet" class="quiet">↓ Save test wallet</button></div> <div id="active-wallet" hidden><p class="label">FAKE BTC BALANCE</p><div class="balance"><span id="balance">0</span><small>BTC</small></div><p id="reserved" class="muted"></p><label for="address">Local regtest-format address</label><input id="address" readonly><button id="export-wallet" class="quiet">↓ Save test wallet</button></div>
<div class="wallet-footer"><label class="file-button" for="load-wallet">↑ Load test wallet or lab backup</label><input id="load-wallet" type="file" accept=".json,application/json"><p class="muted">Saved on this device. Local-wallet backups contain their test key; Inscriboor backups contain only a public descriptor. A lab backup also preserves the chain.</p></div> <div class="wallet-footer"><label class="file-button" for="load-wallet">↑ Load test wallet or lab backup</label><input id="load-wallet" type="file" accept=".json,application/json"><p class="muted">Saved on this device. Local-wallet backups contain their test key; Inscriboor backups contain only a public descriptor. A lab backup also preserves the chain.</p></div>
</article> </article>
<article class="panel"><div class="panel-title"><span class="step">02</span><h2>Make some blocks</h2></div><p>Skip the faucet queue. Every block gives you <strong>50 fake BTC</strong>, ready to use immediately.</p><div class="chain-stats"><div><span class="label">BLOCK HEIGHT</span><strong id="height">0</strong></div><div><span class="label">PENDING TXS</span><strong id="pending">0</strong></div></div><button id="mine" class="primary" disabled>Mine now <span>+</span></button><label for="miner-interval">Auto miner</label><select id="miner-interval"><option value="0">OFF</option><option value="10">10s</option><option value="30">30s</option><option value="60">60s</option></select><p id="miner-status" aria-live="polite">Auto mining OFF</p><p class="muted">Keep a lab tab open; browser throttling may delay blocks. Mining also confirms your pending inscriptions.</p></article> <article class="panel"><div class="panel-title"><span class="step">02</span><h2>Make some blocks</h2></div><p>Skip the faucet queue. Every block gives you <strong>50 fake BTC</strong>, ready to use immediately.</p><div class="chain-stats"><div><span class="label">BLOCK HEIGHT</span><strong id="height">0</strong></div><div><span class="label">PENDING TXS</span><strong id="pending">0</strong></div></div><button id="mine" class="primary" disabled>Mine now <span>+</span></button><label for="miner-interval">Auto miner</label><select id="miner-interval"><option value="0">OFF</option><option value="10">10s</option><option value="30">30s</option><option value="60">60s</option></select><p id="miner-status" aria-live="polite">Auto mining OFF</p><p class="muted">Keep a lab tab open; browser throttling may delay blocks. Mining also confirms your pending inscriptions.</p></article>
<article class="panel inscribe"><div class="panel-title"><span class="step">03</span><h2>Leave a little something</h2><span class="tag">INSCRIPTION LAB</span></div><label for="mime-type">Content type</label><select id="mime-type"></select><label for="body-file">Or upload a local file (16 KiB maximum)</label><input id="body-file" type="file"><label for="parent">Parent inscription (optional, immutable)</label><select id="parent"><option value="">No parent</option></select><label for="delegate">Delegate inscription ID (optional, future IDs allowed)</label><input id="delegate" placeholder="64 hex characters + i0"><label for="reinscribe">Reinscribe an owned sat (optional)</label><select id="reinscribe"><option value="">New sat</option></select><label for="pointer">Advanced pointer (zero-based output sat position)</label><input id="pointer" inputmode="numeric" placeholder="Default first sat"><button id="recursive-demo" class="quiet">Use recursive demo</button><p class="muted">Recursive HTML/SVG scripts use local fetch and ord.render(text) in an isolated worker; ord.id is the requested inscription. No DOM or network access.</p><label for="payload">What will you put on your chain?</label><textarea id="payload" placeholder="Hello, little Bitcoin universe…" rows="3" disabled></textarea><label for="metadata">JSON metadata (optional, independent of body)</label><textarea id="metadata" rows="3" placeholder='{"protocol":"my-experiment","note":"hello"}'></textarea><p id="metadata-count" class="muted">0 / 2048 CBOR bytes · ord tag 5 · JSON is authoring format only</p><label for="metaprotocol">Metaprotocol (optional, independent field)</label><input id="metaprotocol" placeholder="e.g. tea-v1 · ord tag 7"><p class="muted">Native ord metaprotocol identifier. Metadata and inscription data remain independent.</p><div class="compose-footer"><span id="byte-count" class="muted">0 / 16384 bytes</span><button id="review" disabled>Review inscription ↗</button></div> <article class="panel inscribe"><div class="panel-title"><span class="step">03</span><h2>Inscribe a root, a birth, a badge</h2><span class="tag">INSCRIPTION LAB</span></div><label for="mime-type">Content type</label><select id="mime-type"></select><label for="body-file">Or upload a local file (16 KiB maximum)</label><input id="body-file" type="file"><label for="parent">Parent inscription (optional, immutable)</label><select id="parent"><option value="">No parent</option></select><label for="delegate">Delegate inscription ID (optional, future IDs allowed)</label><input id="delegate" placeholder="64 hex characters + i0"><label for="reinscribe">Reinscribe an owned sat (optional)</label><select id="reinscribe"><option value="">New sat</option></select><label for="pointer">Advanced pointer (zero-based output sat position)</label><input id="pointer" inputmode="numeric" placeholder="Default first sat"><button id="recursive-demo" class="quiet">Use recursive demo</button><p class="muted">Recursive HTML/SVG scripts use local fetch and ord.render(text) in an isolated worker; ord.id is the requested inscription. No DOM or network access.</p><label for="payload">What will you put on your chain?</label><textarea id="payload" placeholder="yolopreneur — the root of the tree…" rows="3" disabled></textarea><label for="metadata">JSON metadata (optional, independent of body)</label><textarea id="metadata" rows="3" placeholder='{"lineage":"birth","name":"time"}'></textarea><p id="metadata-count" class="muted">0 / 2048 CBOR bytes · ord tag 5 · JSON is authoring format only</p><label for="metaprotocol">Metaprotocol (optional, independent field)</label><input id="metaprotocol" placeholder="e.g. lineage/v0 · ord tag 7"><p class="muted">Native ord metaprotocol identifier. Metadata and inscription data remain independent.</p><div class="compose-footer"><span id="byte-count" class="muted">0 / 16384 bytes</span><button id="review" disabled>Review inscription ↗</button></div>
<div id="review-panel" hidden><h3>Review before signing</h3><div id="review-preview"></div><pre id="review-text"></pre><p id="review-parent"></p><pre id="review-metadata"></pre><p>Two transactions: commit + reveal. <strong>1,000 fake sats</strong> in fees; <strong>1,000 fake sats</strong> in a new wallet output. Any selected parent or reinscription output is also returned in full; reinscription appends to its existing sat stack.</p><p id="signing-note" class="muted">The next button asks your active signer to approve commit + reveal, then submits them to your private chain.</p><button id="sign" class="primary">Sign & inscribe</button> <button id="cancel-review" class="quiet">Cancel</button></div> <div id="review-panel" hidden><h3>Review before signing</h3><div id="review-preview"></div><pre id="review-text"></pre><p id="review-parent"></p><pre id="review-metadata"></pre><p>Two transactions: commit + reveal. <strong>1,000 fake sats</strong> in fees; <strong>1,000 fake sats</strong> in a new wallet output. Any selected parent or reinscription output is also returned in full; reinscription appends to its existing sat stack.</p><p id="signing-note" class="muted">The next button asks your active signer to approve commit + reveal, then submits them to your private chain.</p><button id="sign" class="primary">Sign & inscribe</button> <button id="cancel-review" class="quiet">Cancel</button></div>
</article> </article>
</section> </section>
@@ -53,7 +63,7 @@
<button id="api-try">Try</button> <button id="api-copy" class="quiet">Copy response</button> <button id="api-try">Try</button> <button id="api-copy" class="quiet">Copy response</button>
<pre id="api-response" aria-live="polite">Choose a path and press Try.</pre> <pre id="api-response" aria-live="polite">Choose a path and press Try.</pre>
</section> </section>
<details class="about"><summary>Under the hood & attribution</summary><p>Real serialized Bitcoin transactions, Schnorr signatures and Taproot commit/reveal scripts, on a deliberately simplified local UTXO chain. No proof of work, Bitcoin consensus, peer network, public broadcast, or production custody. Synthetic local sats follow FIFO input-to-output ranges. Child creation and reinscription preserve the owned sat. Fees retire the input tail; this is not Bitcoin consensus.</p><p>Built from and inspired by <a href="https://github.com/supertestnet/testnet_generator">Supertestnet’s testnet_generator</a>, <a href="https://github.com/supertestnet/inscriptions-online">inscriptions-online</a>, and <a href="https://github.com/supertestnet/vanilla-js-browser-wallet">vanilla-js-browser-wallet</a>. <a href="https://github.com/supertestnet/node_faker">node_faker</a> was evaluated for future RPC compatibility.</p><p>Transaction library: <a href="https://github.com/cmdruid/tapscript">tapscript by Christopher Scott</a> (<a href="/licenses/tapscript.txt">CC-BY-1.0</a>). <a href="/licenses/supertestnet-CC0.txt">Supertestnet CC0 license</a> · <a href="/licenses/noble-curves.txt">noble-curves license</a> · <a href="/licenses/noble-hashes.txt">noble-hashes license</a>.</p></details> <details class="about"><summary>Under the hood &amp; attribution</summary><p>Orgchain is <a href="https://supertestnet.lol/">Super Testnet</a> in lineage's clothes: the same lab and code, restyled, with a rehearsal guide on top. Its lab state lives in this browser, separate from supertestnet.lol's.</p><p>Real serialized Bitcoin transactions, Schnorr signatures and Taproot commit/reveal scripts, on a deliberately simplified local UTXO chain. No proof of work, Bitcoin consensus, peer network, public broadcast, or production custody. Synthetic local sats follow FIFO input-to-output ranges. Child creation and reinscription preserve the owned sat. Fees retire the input tail; this is not Bitcoin consensus.</p><p>Built from and inspired by <a href="https://github.com/supertestnet/testnet_generator">Supertestnet’s testnet_generator</a>, <a href="https://github.com/supertestnet/inscriptions-online">inscriptions-online</a>, and <a href="https://github.com/supertestnet/vanilla-js-browser-wallet">vanilla-js-browser-wallet</a>. <a href="https://github.com/supertestnet/node_faker">node_faker</a> was evaluated for future RPC compatibility.</p><p>Transaction library: <a href="https://github.com/cmdruid/tapscript">tapscript by Christopher Scott</a> (<a href="licenses/tapscript.txt">CC-BY-1.0</a>). <a href="licenses/supertestnet-CC0.txt">Supertestnet CC0 license</a> · <a href="licenses/noble-curves.txt">noble-curves license</a> · <a href="licenses/noble-hashes.txt">noble-hashes license</a>.</p></details>
<footer><span>SMALL CHAIN. BIG POSSIBILITIES.</span><button id="reset" class="quiet danger">Reset local lab</button></footer> <footer><span>SMALL CHAIN. WHOLE FAMILY TREE.</span><span class="made">Part of <a href="../">Lineage</a> · <a href="https://yolopreneur.lol/">yolopreneur.lol</a> · based on <a href="https://supertestnet.lol/">Super Testnet</a></span><button id="reset" class="quiet danger">Reset local lab</button></footer>
</main><script type="module" src="/src/main.js"></script> </main><script type="module" src="/src/main.js"></script>
</body></html> </body></html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
{"version":"0.2.4","url":"https://supertestnet.lol/downloads/inscriboor-extension-v0.2.4.zip"}n
+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34 34"><rect width="34" height="34" rx="8" fill="#f7931a"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" fill="#ffc21a"/><path d="M5 3v10h7" stroke="#141414" stroke-width="2.6" fill="none"/></svg>

Before

Width:  |  Height:  |  Size: 119 B

After

Width:  |  Height:  |  Size: 181 B

+1 -1
View File
@@ -1 +1 @@
<!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-local-ord-preview'; worker-src blob:; style-src 'unsafe-inline'; connect-src 'none'; img-src data:; form-action 'none'; base-uri 'none'"><div id="markup"></div><pre id="recursive-output"></pre><script nonce="local-ord-preview" src="/recursive-preview.js"></script> <!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-local-ord-preview'; worker-src blob:; style-src 'unsafe-inline'; connect-src 'none'; img-src data:; form-action 'none'; base-uri 'none'"><div id="markup"></div><pre id="recursive-output"></pre><script nonce="local-ord-preview" src="recursive-preview.js"></script>
+153
View File
@@ -0,0 +1,153 @@
/* Orgchain: Super Testnet in lineage's clothes.
Same lab, dressed as lineage's key-ceremony sheet: raw concrete, black rule, hazard yellow for the action and for
anything live, everything in the system monospace. Restyle only: loads after style.css and repoints its tokens. */
:root {
--concrete: #e4e3dd; --slab: #f6f5f1; --ink: #141414; --ink-2: #4a4944; --ink-3: #66655f;
--signal: #ffc21a; --on-signal: #141414; --ok: #1d7a3a; --focus: #2346ff;
--band: #141414; --band-fg: #f6f5f1; --band-muted: #b0afa8; --shadow: #141414;
--mono: ui-monospace, "SF Mono", "Cascadia Mono", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
--display: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--t-xs: 0.75rem; --t-s: 0.8125rem; --t-m: 0.9375rem; --t-l: 1.25rem;
}
:root[data-theme="dark"] {
--concrete: #151514; --slab: #1e1e1c; --ink: #ecebe4; --ink-2: #b9b8b0; --ink-3: #94938b;
--ok: #62c784; --focus: #93a8ff; --band: #0b0b0a; --band-fg: #ecebe4; --band-muted: #9d9c95; --shadow: #4d4c47;
}
/* Super Testnet's own tokens, pointed at lineage's in both themes (style.css sets light values on [data-theme]) */
:root, :root[data-theme="light"], :root[data-theme="dark"] {
--orange: var(--signal); --orange-2: var(--signal);
--bg: var(--concrete); --panel: var(--slab); --panel-2: var(--concrete); --soft: var(--concrete);
--text: var(--ink); --muted: var(--ink-2); --line: var(--ink);
font-family: var(--mono);
}
:root, :root[data-theme="light"] { --danger: #b3261e; }
:root[data-theme="dark"] { --danger: #ff8a7f; }
* { border-radius: 0 !important; }
html, body { background: var(--concrete); }
body { font: 400 var(--t-m)/1.5 var(--mono); color: var(--ink); transition: none; }
::selection { background: var(--signal); color: var(--on-signal); }
a { color: var(--ink); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { background: var(--signal); color: var(--on-signal); }
code { font-family: inherit; font-weight: 700; }
button:focus-visible, a:focus-visible, summary:focus-visible, .file-button:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* header slab, as on lineage's key tree */
header.band { max-width: none; margin: 0; padding: 0; display: block; border-bottom: 3px solid var(--ink); background: var(--band); color: var(--band-fg); }
.band-in {
max-width: 1240px; margin: 0 auto; padding-block: 22px 20px;
padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px));
display: flex; flex-wrap: wrap; gap: 16px 32px; align-items: flex-end; justify-content: space-between;
}
.wordmark { margin: 0; color: var(--band-fg); font: 900 clamp(3.25rem, 11vw, 7rem)/0.82 var(--display); letter-spacing: -0.05em; text-transform: uppercase; }
.lede { margin: 12px 0 0; color: var(--band-muted); font-size: var(--t-s); max-width: 58ch; }
.lede b { color: var(--band-fg); }
.flags { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.flag, button.flag {
font: 700 var(--t-xs)/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; padding: 7px 9px 6px;
border: 2px solid var(--band-fg); background: transparent; color: var(--band-fg); box-shadow: none; text-decoration: none;
}
.flag.hz { background: var(--signal); border-color: var(--signal); color: var(--on-signal); }
a.flag:hover, button.flag:hover:not(:disabled) { background: var(--band-fg); color: var(--band); border-color: var(--band-fg); transform: none; }
button.flag:active:not(:disabled) { transform: none; }
/* blocks with ink tabs */
.blk { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
.blk > .panel { align-self: stretch; }
.tab {
margin: 0; background: var(--ink); color: var(--slab); font: 700 var(--t-xs)/1 var(--mono);
letter-spacing: 0.14em; text-transform: uppercase; padding: 8px 11px 7px; display: flex; gap: 12px; max-width: 100%;
}
.tab .sub { font-weight: 400; letter-spacing: 0.06em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rehearse { margin: 40px 0 0; }
.moves { margin: 0; padding: 0 0 0 1.6em; display: grid; gap: 10px; font-size: var(--t-s); line-height: 1.6; max-width: 96ch; }
.moves li::marker { font-weight: 700; }
.moves b, .panel .later b { color: var(--ink); }
.panel .later { margin: 16px 0 0; padding: 10px 12px; border: 2px dashed var(--ink); font-size: var(--t-s); color: var(--ink-2); max-width: 96ch; }
.notice { margin-top: 28px; background: transparent; border: 2px dashed var(--ink); padding: 10px 12px; font-size: var(--t-s); color: var(--ink-2); }
.notice strong { color: var(--ink); }
#status { color: var(--ink); font: 700 var(--t-s)/1.5 var(--mono); padding: 16px 0; }
#status::before { content: "\25B8 "; }
#status.error { color: var(--danger); }
/* panels: slabs with a hard ink shadow */
.panel { background: var(--slab); border: 3px solid var(--ink); box-shadow: 8px 8px 0 var(--shadow); padding: 22px; }
.workspace { gap: 28px; }
.panel-title { gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.panel-title h2, #indexes > h2, #api-explorer > h2 { font: 700 var(--t-m)/1.3 var(--mono); letter-spacing: 0.04em; text-transform: uppercase; margin: 0; }
.step { background: var(--ink); color: var(--slab); border: 0; padding: 7px 9px 6px; font: 700 var(--t-xs)/1 var(--mono); letter-spacing: 0.1em; }
.tag { border: 2px solid var(--ink); color: var(--ink); font: 700 0.6875rem/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; padding: 5px 7px 4px; }
.panel p { font-size: var(--t-s); color: var(--ink-2); }
.label, .chain-kicker { font: 700 var(--t-xs)/1.2 var(--mono) !important; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
h3 { font: 700 var(--t-m)/1.3 var(--mono); text-transform: uppercase; letter-spacing: 0.04em; }
/* form */
label { font: 700 var(--t-xs)/1.3 var(--mono); letter-spacing: 0.06em; color: var(--ink-2); margin: 16px 0 6px; }
input, textarea, select { background: var(--concrete); border: 2px solid var(--ink); color: var(--ink); font: 400 var(--t-s)/1.4 var(--mono); padding: 9px 10px; }
input:focus, textarea:focus, select:focus { border-color: var(--ink); outline: 3px solid var(--focus); outline-offset: 2px; }
input[type=file] { border-style: dashed; background: transparent; }
.file-button { color: var(--ink); font-weight: 700; text-decoration-thickness: 2px; }
.wallet-footer { border-top: 2px dashed var(--ink-3); }
.install-help summary { cursor: pointer; font-weight: 700; }
/* buttons, as on the key tree */
button {
font: 700 var(--t-s)/1 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; padding: 10px 12px 9px;
background: var(--slab); color: var(--ink); border: 2px solid var(--ink); box-shadow: 3px 3px 0 var(--shadow); transition: none;
}
button:hover:not(:disabled) { background: var(--concrete); border-color: var(--ink); transform: none; }
button:active:not(:disabled) { transform: translate(3px, 3px); box-shadow: none; }
button:disabled { opacity: 0.45; box-shadow: none; }
button.primary { background: var(--signal); color: var(--on-signal); border-color: var(--ink); }
button.primary:hover:not(:disabled) { background: var(--signal); filter: brightness(1.05); }
.quiet { background: transparent; font-size: var(--t-xs); box-shadow: 2px 2px 0 var(--shadow); }
button.danger, .danger { color: var(--danger); }
/* numbers */
.balance { font: 700 2.4rem/1 var(--mono); letter-spacing: -0.02em; }
.balance small { color: var(--ink-2); font: 700 var(--t-xs)/1 var(--mono); letter-spacing: 0.1em; }
.chain-stats strong { font: 700 2.5rem/1 var(--mono); }
pre { background: var(--concrete); border: 2px solid var(--ink); font: 400 var(--t-xs)/1.6 var(--mono); }
/* sections */
.section-title { margin: 52px 0 18px; }
.eyebrow { display: inline-block; background: var(--ink); color: var(--slab); padding: 8px 11px 7px; font: 700 var(--t-xs)/1 var(--mono); letter-spacing: 0.14em; margin: 0 0 10px; }
.section-title h2 { font: 900 clamp(1.6rem, 3.4vw, 2.4rem)/1 var(--display); letter-spacing: -0.03em; text-transform: uppercase; }
#collection-count { background: var(--signal); color: var(--on-signal); font: 700 var(--t-s)/1 var(--mono); padding: 5px 8px 4px; vertical-align: middle; }
.empty { border: 2px dashed var(--ink); color: var(--ink-2); font-size: var(--t-s); }
.collectible { background: var(--slab); border: 3px solid var(--ink); box-shadow: 6px 6px 0 var(--shadow); }
.collectible pre { font: 400 1rem/1.5 var(--mono); border: 0; background: transparent; }
.inscription-preview { border: 2px solid var(--ink); }
/* chain board: pending is live, so it wears the signal */
.chain-board { background: var(--slab); border: 3px solid var(--ink); box-shadow: 8px 8px 0 var(--shadow); }
.chain-kicker { color: var(--ink); }
.mempool-empty { border: 2px dashed var(--ink); color: var(--ink-2); }
.mempool-card { background: var(--signal); color: var(--on-signal); border: 2px solid var(--ink); text-transform: none; letter-spacing: 0; }
.mempool-card strong { color: var(--on-signal); }
.mempool-card span { color: var(--on-signal); }
.chain-divider { border-left: 3px solid var(--ink); }
.chain-divider span { color: var(--ink-2); font: 700 var(--t-xs)/1 var(--mono); letter-spacing: 0.1em; }
.block-card { background: var(--concrete); border: 2px solid var(--ink); text-transform: none; letter-spacing: 0; font-weight: 400; }
.block-card:before { border-top: 3px solid var(--ink); opacity: 1; }
.block-card .block-accent { color: var(--on-signal); background: var(--signal); display: inline-block; padding: 2px 5px; }
.inspector h2 { font: 700 var(--t-l)/1.25 var(--mono); }
#protocol-events article { border-bottom: 1px dashed var(--ink-3); }
#indexes, #api-explorer { margin-top: 2.5rem; }
/* about + footer */
.about { border-top: 3px solid var(--ink); color: var(--ink-2); font-size: var(--t-s); }
.about summary { color: var(--ink); font: 700 var(--t-xs)/1.4 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; }
footer { border-top: 3px solid var(--ink); font: 700 var(--t-xs)/1.4 var(--mono); letter-spacing: 0.12em; color: var(--ink); flex-wrap: wrap; gap: 12px; }
footer .made { color: var(--ink-2); font-weight: 400; letter-spacing: 0.04em; }
@media (max-width: 700px) {
.band-in { padding-block: 18px 16px; }
.panel, .chain-board { box-shadow: 5px 5px 0 var(--shadow); padding: 18px; }
}
@media (prefers-reduced-motion: reduce) { button:active:not(:disabled) { transform: none; } }
/* long ids and JSON wrap instead of widening the page */
.moves, .moves code, .collectible, .inspector, #review-panel, #status { overflow-wrap: anywhere; }
+4 -3
View File
@@ -1,5 +1,6 @@
import { RECURSIVE_DEMO } from './recursion.js'; import { RECURSIVE_DEMO } from './recursion.js';
import './style.css'; import './style.css';
import './lineage.css';
import { encodeMetadata, parseMetadataJSON } from './adapters/metadata.js'; import { encodeMetadata, parseMetadataJSON } from './adapters/metadata.js';
import { MetadataIndex, deriveProtocol } from './adapters/metadata-index.js'; import { MetadataIndex, deriveProtocol } from './adapters/metadata-index.js';
import { LocalOrdAPI } from './adapters/local-ord-api.js'; import { LocalOrdAPI } from './adapters/local-ord-api.js';
@@ -14,11 +15,11 @@ import { STORAGE_KEY, readLab, mutateLab, decodeLab, encodeLab } from './storage
const $ = id => document.getElementById(id); const $ = id => document.getElementById(id);
const btc = sats => (sats / 1e8).toFixed(8); const btc = sats => (sats / 1e8).toFixed(8);
const short = id => `${id.slice(0, 12)}…${id.slice(-8)}`; const short = id => `${id.slice(0, 12)}…${id.slice(-8)}`;
const THEME_KEY = 'super-testnet-theme'; const THEME_KEY = 'orgchain-theme';
let fileBytes = null, fileLoading = false, fileRevision = 0; let fileBytes = null, fileLoading = false, fileRevision = 0;
let lab, busy = false, reviewed = null, failed = false; let lab, busy = false, reviewed = null, failed = false;
let inscriboorProvider = null; let inscriboorProvider = null;
const INSCRIBOOR_RELEASE = { version: '0.2.4', url: '/downloads/inscriboor-extension-v0.2.4.zip' }; const INSCRIBOOR_RELEASE = { version: '0.2.4', url: 'https://supertestnet.lol/downloads/inscriboor-extension-v0.2.4.zip' };
const message = (text, error = false) => { $('status').textContent = text; $('status').classList.toggle('error', error); }; const message = (text, error = false) => { $('status').textContent = text; $('status').classList.toggle('error', error); };
const el = (tag, text, className) => { const node = document.createElement(tag); if (text !== undefined) node.textContent = text; if (className) node.className = className; return node; }; const el = (tag, text, className) => { const node = document.createElement(tag); if (text !== undefined) node.textContent = text; if (className) node.className = className; return node; };
@@ -46,7 +47,7 @@ function setTheme(theme, persist = false) {
} }
function initTheme() { function initTheme() {
const saved = localStorage.getItem(THEME_KEY); const saved = localStorage.getItem(THEME_KEY);
setTheme(saved === 'light' || saved === 'dark' ? saved : 'dark'); setTheme(saved === 'light' || saved === 'dark' ? saved : (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));
} }
function download(name, contents) { function download(name, contents) {
const url = URL.createObjectURL(new Blob([contents], { type: 'application/json' })); const url = URL.createObjectURL(new Blob([contents], { type: 'application/json' }));
+1 -1
View File
@@ -33,7 +33,7 @@ export function preview(item, api = null) {
node.title = `${type} recursive preview`; node.referrerPolicy = 'no-referrer'; node.title = `${type} recursive preview`; node.referrerPolicy = 'no-referrer';
const payload = recursivePayload(template.innerHTML, scripts, item.id); const payload = recursivePayload(template.innerHTML, scripts, item.id);
node.onload = () => { node.cleanup?.(); node.cleanup = connectRecursion(node, api, payload); }; node.onload = () => { node.cleanup?.(); node.cleanup = connectRecursion(node, api, payload); };
node.src = '/recursive-preview.html'; node.dataset.previewUrl = ''; node.className = 'inscription-preview'; node.src = 'recursive-preview.html'; node.dataset.previewUrl = ''; node.className = 'inscription-preview';
return node; return node;
} }
const csp = "default-src 'none'; style-src 'unsafe-inline'; script-src 'none'; form-action 'none'; base-uri 'none'"; const csp = "default-src 'none'; style-src 'unsafe-inline'; script-src 'none'; form-action 'none'; base-uri 'none'";
+4
View File
@@ -0,0 +1,4 @@
import { defineConfig } from 'vite';
// Orgchain is served from lineage.yolopreneur.lol/orgchain/: relative asset URLs work at any sub-path.
export default defineConfig({ base: './' });