feat(sirius-x): Sirius Studio web-builder + signed site uploads; shorter dashboard menu
Owners had no way to put a real page behind a name without running Sia
tooling themselves. Sirius Studio (studio.html, js/studio.js) embeds
GrapesJS (BSD-3, vendored under vendor/grapesjs so nothing loads from a
third party) with three starter templates; Publish exports one
self-contained index.html plus the editor project, uploads both to the
name's own folder bns/<name>/ on Sia, and sets the s3 record on chain if
the name does not point there yet. Drafts save to the same folder.
Gateway: /api/site/<name>[/<path>] — list, read-through, PUT and DELETE.
Every write carries a wallet signature over (name, path, body hash,
timestamp) that must recover to the current NFT owner, and writes are
confined to bns/<name>/ so no name can touch another name's bucket.
Dashboard menu is now Web-Builder, Domain names, My TLDs, Settings, Sign
out; Overview and Wallet folded into Domain names and Settings, Docs is a
link in Settings.
2026-09-17 01:35:21 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > Sirius Studio — build the site for your name< / title >
< meta name = "description" content = "Sirius Studio: a drag-and-drop site builder for BCNR names. Pages live on Sia, the name on the chain — your keys, your site." >
< link rel = "icon" href = "./assets/favicon.svg" type = "image/svg+xml" >
< link href = "https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel = "stylesheet" >
< link rel = "stylesheet" href = "./vendor/grapesjs/grapes.min.css?v=0.23.6" >
< style >
:root{
--bg:#050810; --panel:#141a24; --panel2:#0a0f1c; --line:rgba(255,255,255,.08);
--ink:#f1f4fa; --mut:#b8c2d4; --dim:#6a7488; --acid:#d6ff3d; --ok:#4fd1a5; --taken:#f6768a; --warn:#ffc75f;
--serif:'Fraunces',Georgia,serif; --sans:'DM Sans',system-ui,sans-serif; --mono:'JetBrains Mono',ui-monospace,monospace;
/* GrapesJS theme hooks */
--gjs-primary-color:#0e131b; --gjs-secondary-color:#b8c2d4; --gjs-tertiary-color:#d6ff3d; --gjs-quaternary-color:#d6ff3d;
--gjs-font-color:#f1f4fa; --gjs-main-dark-color:#0a0f1c; --gjs-main-light-color:#141a24;
}
*{box-sizing:border-box}
html,body{height:100%;margin:0}
body{background:var(--bg);color:var(--ink);font:14px/1.5 var(--sans);display:flex;flex-direction:column;overflow:hidden}
a{color:var(--acid)}
.bar{display:flex;align-items:center;gap:10px;padding:8px 14px;background:rgba(11,14,20,.95);border-bottom:1px solid var(--line);flex:none;flex-wrap:wrap}
.bar .brand{font-weight:600;color:var(--ink);text-decoration:none;font-size:15px;display:flex;align-items:center;gap:6px}
.bar .brand .g{color:var(--acid)}
.bar .name{font-family:var(--mono);font-size:14px;color:var(--ink);background:var(--panel);border:1px solid var(--line);padding:5px 10px;border-radius:8px}
.bar .name .tld{color:var(--acid)}
.bar .sp{flex:1}
.bar .st{font-size:12.5px;color:var(--dim);max-width:360px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bar .st.ok{color:var(--ok)} .bar .st.err{color:var(--taken)} .bar .st.busy{color:var(--warn)}
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:9px;background:#4b7bec;color:#fff;font:inherit;font-size:13px;border:none;cursor:pointer;text-decoration:none;line-height:1.2}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--ink)}
.btn.acid{background:var(--acid);color:#0b0e14;font-weight:600}
.btn.small{padding:5px 10px;font-size:12px}
.btn:disabled{opacity:.45;cursor:not-allowed}
select.sel{padding:6px 28px 6px 10px;border-radius:9px;background:var(--panel);color:var(--ink);border:1px solid var(--line);font:inherit;font-size:13px}
#editor{flex:1;min-height:0}
#gjs{height:100%}
.gjs-one-bg{background-color:var(--panel2)}
.gjs-two-color{color:var(--mut)}
.gjs-three-bg{background-color:var(--acid);color:#0b0e14}
.gjs-four-color,.gjs-four-color-h:hover{color:var(--acid)}
.gjs-pn-panel{border-color:var(--line)}
.gjs-cv-canvas{background:#fff}
/* gate / picker overlays */
.overlay{position:fixed;inset:0;background:rgba(5,8,16,.92);backdrop-filter:blur(4px);z-index:100;display:flex;align-items:center;justify-content:center;padding:20px;overflow:auto}
.overlay[hidden]{display:none}
.sheet{background:var(--panel);border:1px solid var(--line);border-radius:16px;max-width:860px;width:100%;padding:26px 28px}
.sheet h2{font-family:var(--serif);margin:0 0 .3rem;font-size:1.5rem}
.sheet p{color:var(--mut);margin:.2rem 0 1rem}
.tpls{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-top:10px}
.tpl{background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:0;overflow:hidden;cursor:pointer;text-align:left;color:inherit;font:inherit;transition:border-color .12s}
.tpl:hover{border-color:rgba(214,255,61,.4)}
.tpl .prev{height:110px;background:#fff;display:flex;align-items:center;justify-content:center;font-family:var(--serif);color:#111;font-size:22px}
.tpl .prev.dark{background:#0b0e14;color:#d6ff3d}
.tpl .prev.warm{background:#fff4e6;color:#7a3b00}
.tpl .prev.blue{background:#0f2a4a;color:#e6f0ff}
.tpl b{display:block;padding:10px 12px 2px;font-size:14px}
.tpl span{display:block;padding:0 12px 12px;color:var(--dim);font-size:12px}
.steps{margin-top:12px;font-family:var(--mono);font-size:12px;color:var(--mut);background:#0e131b;border:1px solid var(--line);border-radius:8px;padding:10px 12px;max-height:160px;overflow:auto}
.steps div::before{content:"› ";color:var(--acid)}
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:14px}
.row.end{justify-content:flex-end}
.muted{color:var(--mut);font-size:13px}
code{font-family:var(--mono);background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:12px}
< / style >
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
< script src = "./js/i18n.js?v=20260917h" > < / script >
feat(sirius-x): Sirius Studio web-builder + signed site uploads; shorter dashboard menu
Owners had no way to put a real page behind a name without running Sia
tooling themselves. Sirius Studio (studio.html, js/studio.js) embeds
GrapesJS (BSD-3, vendored under vendor/grapesjs so nothing loads from a
third party) with three starter templates; Publish exports one
self-contained index.html plus the editor project, uploads both to the
name's own folder bns/<name>/ on Sia, and sets the s3 record on chain if
the name does not point there yet. Drafts save to the same folder.
Gateway: /api/site/<name>[/<path>] — list, read-through, PUT and DELETE.
Every write carries a wallet signature over (name, path, body hash,
timestamp) that must recover to the current NFT owner, and writes are
confined to bns/<name>/ so no name can touch another name's bucket.
Dashboard menu is now Web-Builder, Domain names, My TLDs, Settings, Sign
out; Overview and Wallet folded into Domain names and Settings, Docs is a
link in Settings.
2026-09-17 01:35:21 +02:00
< / head >
< body >
< div class = "bar" >
< a class = "brand" href = "./portal.html#studio" > ⭐ < span class = "g" > Sirius< / span > Studio< / a >
< span class = "name" id = "site-name" > —< / span >
< select class = "sel" id = "tpl-select" title = "Start from a template" >
< option value = "" > Templates…< / option >
< option value = "landing" > Landing page< / option >
< option value = "profile" > Profile / link hub< / option >
< option value = "business" > Business one-pager< / option >
< option value = "blank" > Blank page< / option >
< / select >
< button class = "btn ghost small" id = "btn-preview" title = "Preview the exported page in a new tab" > Preview< / button >
< span class = "sp" > < / span >
< span class = "st" id = "status" > Loading…< / span >
< button class = "btn ghost small" id = "btn-draft" disabled > Save draft< / button >
< button class = "btn acid small" id = "btn-publish" disabled > Publish to Sia →< / button >
< a class = "btn ghost small" id = "btn-view" href = "#" target = "_blank" rel = "noopener" hidden > View site →< / a >
< / div >
< div id = "editor" > < div id = "gjs" > < / div > < / div >
<!-- sign - in gate -->
< div class = "overlay" id = "gate" hidden >
< div class = "sheet" style = "max-width:520px" >
< h2 > Sign in first< / h2 >
< p > Sirius Studio publishes with your wallet's key. Sign in on the dashboard, then come back to this name.< / p >
< div class = "row end" > < a class = "btn acid" id = "gate-link" href = "./portal.html" > Open the dashboard →< / a > < / div >
< / div >
< / div >
<!-- template picker for a fresh site -->
< div class = "overlay" id = "picker" hidden >
< div class = "sheet" >
< h2 > Build the site for < span id = "picker-name" style = "font-family:var(--mono);color:var(--acid)" > —< / span > < / h2 >
< p > Pick a starting point. Everything is editable — drag blocks in from the right, click any text to change it. Nothing leaves your browser until you press Publish; then the page is stored on Sia and the name points at it.< / p >
< div class = "tpls" >
< button class = "tpl" data-tpl = "landing" > < div class = "prev" > Hello, world< / div > < b > Landing page< / b > < span > Hero, three features, call to action.< / span > < / button >
< button class = "tpl" data-tpl = "profile" > < div class = "prev dark" > @you< / div > < b > Profile / link hub< / b > < span > Avatar, bio and a stack of links.< / span > < / button >
< button class = "tpl" data-tpl = "business" > < div class = "prev warm" > Open today< / div > < b > Business one-pager< / b > < span > About, services, hours, contact.< / span > < / button >
< button class = "tpl" data-tpl = "blank" > < div class = "prev blue" > —< / div > < b > Blank page< / b > < span > Start from nothing.< / span > < / button >
< / div >
< div class = "row end" > < a class = "btn ghost" href = "./portal.html#studio" > Back to dashboard< / a > < / div >
< / div >
< / div >
<!-- publish dialog -->
< div class = "overlay" id = "pub" hidden >
< div class = "sheet" style = "max-width:620px" >
< h2 > Publish < span id = "pub-name" style = "font-family:var(--mono);color:var(--acid)" > —< / span > < / h2 >
< p id = "pub-intro" > The page and its assets are uploaded to the name's folder on Sia, signed with your key. If the name does not point at that folder yet, one on-chain update sets it (a few cents of chain dust).< / p >
< div class = "steps" id = "pub-steps" > < / div >
< div class = "row end" >
< button class = "btn ghost" id = "pub-close" > Close< / button >
< a class = "btn acid" id = "pub-view" href = "#" target = "_blank" rel = "noopener" hidden > View site →< / a >
< / div >
< / div >
< / div >
< script type = "importmap" >
{ "imports": { "@bitauth/libauth": "https://silentmode.st/js/libauth.js" } }
< / script >
< script src = "./js/session.js?v=20260917dash" > < / script >
< script src = "./vendor/grapesjs/grapes.min.js?v=0.23.6" > < / script >
< script src = "./vendor/grapesjs/blocks-basic.js?v=1.0.2" > < / script >
< script src = "./vendor/grapesjs/preset-webpage.js?v=1.0.3" > < / script >
< script type = "module" src = "./js/studio.js?v=20260917studio" > < / script >
< / body >
< / html >