diff --git a/plans/names-codes/2026-10-09-name-codes.md b/plans/names-codes/2026-10-09-name-codes.md index 5e5e29e820..d14295702a 100644 --- a/plans/names-codes/2026-10-09-name-codes.md +++ b/plans/names-codes/2026-10-09-name-codes.md @@ -180,6 +180,8 @@ Years default to 2 and the status to `free`. The group's command menu and usage **Store:** an order record gains optional `kind: "name"`, `minLength`, `years` and `label`. The label is kept only in this browser, for N4 and the history. A record without `kind` is a badge. +**The button's place:** each badge step keeps the Wefunder block under its main button. That block's fixed minimum height is what keeps the button at one height on every screen. The name steps (N1, N2, N3) and the name failure screen keep an empty block of that height (`.invest`, `aria-hidden`) without the badge offer. On N3 the slot holds "You get a code for any name of 7+ letters", where the badge checkout says "Or invest $10,000+". The history list (N10) keeps the real block. + **New rules in `styles.css`:** `.name-box` (with `.tld`), `.name-status`, `.tiers`/`.tier`, `.stepper`/`.step`/`.term`, `.term-total`, `.primary.next` and `.name-mark`. All of them use the existing tokens, so the dark theme needs nothing of its own (D0–D4). They are prototyped in `mockups/mockups.css`. ### Buying, start to finish diff --git a/plans/names-codes/mockups/board.mjs b/plans/names-codes/mockups/board.mjs index 27513b543c..02f36e253e 100644 --- a/plans/names-codes/mockups/board.mjs +++ b/plans/names-codes/mockups/board.mjs @@ -92,7 +92,8 @@ async function renderAll(frames) { if (error) throw new Error(`board: ${f.tag} failed to render: ${error}`); await page.evaluate(() => document.fonts.ready); const file = join(SCREENS_DIR, `${f.tag}.jpg`); - const shot = { path: file, type: "jpeg", quality: JPEG_QUALITY }; + // animations frozen, or the waiting dot's pulse changes the bytes on every run + const shot = { path: file, type: "jpeg", quality: JPEG_QUALITY, animations: "disabled", caret: "hide" }; if (kind.element) await page.locator("#shot").screenshot(shot); else await page.screenshot({ ...shot, fullPage: true }); f.jpeg = readFileSync(file); diff --git a/plans/names-codes/mockups/screens.js b/plans/names-codes/mockups/screens.js index f5d3658dd1..34cc99bf7a 100644 --- a/plans/names-codes/mockups/screens.js +++ b/plans/names-codes/mockups/screens.js @@ -101,6 +101,11 @@ function qr(payload, caption) { return wrap; } +// The invest block's fixed height without its badge offer, so the button above stands where it does on the badge steps. +function reserve() { + return el("div", { class: "invest", "aria-hidden": "true" }); +} + function nameMark() { return el("span", { class: "name-mark", "aria-hidden": "true" }, "#"); } @@ -150,7 +155,7 @@ function nameEntry(state, label = "") { } const action = state === "available" ? button("Continue", noop) : button("Check availability", noop); if (["empty", "short", "chars", "taken", "reserved", "limited"].includes(state)) action.setAttribute("disabled", ""); - p.append(action); + p.append(action, reserve()); return p; } @@ -175,7 +180,8 @@ function nameYears(label, years) { plus), el("div", { class: "term-total" }, dollars(per * years)), el("div", { class: "notes" }, el("p", { class: "muted" }, "The years start when you register the name in the app.")), - button("Continue", noop)); + button("Continue", noop), + reserve()); } // ---------------------------------------------------------------- checkout @@ -216,7 +222,8 @@ function nameSummary(label, years, selected, opts = {}) { p.append(el("span", { class: "label standalone" }, "Pay with"), methods(selected, opts.unavailable), el("div", { class: "notes slot" }, ...(selected === "card" ? [el("p", { class: "muted" }, "Card payments are processed by Stripe.")] : [])), button(`Pay ${total} with ${METHOD_NAMES[selected]}`, noop), - el("p", { class: "muted" }, `You get a code for any name of ${tierOf(label)}+ letters. Register ${label}.simplex with it in the app.`)); + el("div", { class: "invest", "aria-hidden": "true" }, + el("p", { class: "muted" }, `You get a code for any name of ${tierOf(label)}+ letters. Register ${label}.simplex with it in the app.`))); return p; } @@ -230,7 +237,8 @@ function invoiceFailure() { return panel(back(), el("h1", {}, "That did not go through"), el("p", { class: "lede" }, el("span", { class: "half" }, "The order was not created,"), " ", el("span", { class: "half" }, "and nothing was charged.")), el("p", { class: "lede" }, "If this happens again, get in touch."), - button("Try again", noop)); + button("Try again", noop), + reserve()); } // ---------------------------------------------------------------- payment, shared with badges @@ -316,10 +324,13 @@ function history() { method: "card", price: "$420.00", when: "2 October 2026, 09:40", code: "SB-JKN2E-E888G-5KK16-KZAK5" }), entry({ art: nameMark(), title: "orbital.simplex", sub: "Name code · 7+ letters · 2 years", status: "this invoice expired", tone: "lost", method: "btc", price: "$200.00", when: "28 September 2026, 18:03", open: true })); - return panel(el("h1", {}, "Your codes"), + const p = panel(el("h1", {}, "Your codes"), el("p", { class: "lede" }, "Every code you bought is in this browser, and nowhere else."), list, el("p", { class: "forget-line" }, button(s.FORGET_EVERYTHING, noop, "link danger"))); + const invest = s.investPanel(undefined); + if (invest) p.append(invest); + return p; } // ---------------------------------------------------------------- landing diff --git a/plans/names-codes/names-flow.svg b/plans/names-codes/names-flow.svg index fec14f0a69..45b16e4f65 100644 --- a/plans/names-codes/names-flow.svg +++ b/plans/names-codes/names-flow.svg @@ -1,6 +1,6 @@ - + - + SimpleX names - every screen, on the web and where it meets the app one tree per surface, left to right - blue is the normal path, orange a variant or a failure, grey a platform difference, and dashed is everything that crosses between the site and the app @@ -21,12 +21,12 @@ Your codes, and the dark theme the history list holds badges and names side by side; four screens shown again in the dark palette - -On the web, on a phone -the same screens at 390 px - what stays side by side and what stacks - -For the operator -codes issued by hand, as for badges + +On the web, on a phone +the same screens at 390 px - what stays side by side and what stacks + +For the operator +codes issued by hand, as for badges Buying a name, start to finish What the name check can answer instead The term at its edges @@ -36,8 +36,8 @@ Paying by card A code this browser cannot show, and a link to nothing History, then the same screens dark -Buying a name at phone width -The terminal and the managed group +Buying a name at phone width +The terminal and the managed group @@ -70,12 +70,12 @@ - - - - - - + + + + + + @@ -96,7 +96,7 @@ store.simplex.chat/#/name - + N1. The name One question: which name. The field fixes .simplex and folds case as it is typed. The three tiers are shown from the start, @@ -108,7 +108,7 @@ store.simplex.chat/#/name - + N1a. Typed The tier the length falls in is marked as it is typed. Nothing is sent: the name leaves the page only when Check availability @@ -120,7 +120,7 @@ store.simplex.chat/#/name - + N1b. Available The service hashed the label (keccak256), asked the resolver for [hash].simplex, and heard available. Continue opens only @@ -133,7 +133,7 @@ store.simplex.chat/#/name/years - + N2. How long Two years is the floor, because the contract registers for no less than 730 days. The stepper moves a year at a time up to @@ -146,7 +146,7 @@ store.simplex.chat/#/name/checkout - + N3. Check your order, and pay The badge checkout's shape with the name's rows. 'Your code covers names of 7+ letters' is what is bought, and the line @@ -159,7 +159,7 @@ store.simplex.chat/?order=q7ZpL2dN9xWc4KfR8tYb1A - + N5. Paying in crypto Shared with badges, unchanged: the address, the amount, the QR and the held rate come from BTCPay, and the page waits on @@ -171,7 +171,7 @@ store.simplex.chat/?order=q7ZpL2dN9xWc4KfR8tYb1A - + N6. Payment received Shared: the full amount is in and the network is confirming it. Settlement marks the code row paid, as for a badge. @@ -196,7 +196,7 @@ store.simplex.chat/#/name - + N1c. Too short Judged on the page before any request: a name of 5 letters or fewer can be neither checked nor bought. @@ -207,7 +207,7 @@ store.simplex.chat/#/name - + N1d. Not a name Judged on the page: a-z, 0-9 and single hyphens inside the name, the rule the contract and the resolver share. Upper case @@ -219,7 +219,7 @@ store.simplex.chat/#/name - + N1e. Taken The resolver answered registered. Continue stays shut and the field stays editable for another try. No expiry date is shown: @@ -231,7 +231,7 @@ store.simplex.chat/#/name - + N1f. Reserved The resolver answered reserved (internal, trademark or community). Reserved names are not sold here. @@ -242,7 +242,7 @@ store.simplex.chat/#/name - + N1g. Not checked The resolver or its [names] section did not answer. The buyer can try again; nothing moves forward on a guess. @@ -253,7 +253,7 @@ store.simplex.chat/#/name - + N1h. Too many checks The read rate limit answered 429. Check stays off for Retry-After, as checkout's rate-limited screen does. @@ -264,7 +264,7 @@ store.simplex.chat/#/name/years - + N2a. Ten years The ceiling: plus is off at ten. Minus is off at two, as on N2. @@ -274,7 +274,7 @@ store.simplex.chat/#/name/years - + N2b. A 6-letter name Six letters cost four times the base: $200 a year, $600 for three years. Seven cost twice, $100 a year. @@ -303,7 +303,7 @@ store.simplex.chat/#/name/checkout - + N3a. A method is unavailable Shared B4b: a provider section is missing or the provider is down. The method is shown disabled and Pay relabels to the one @@ -338,7 +338,7 @@ store.simplex.chat/#/name/checkout - + N3d. That did not go through The shared failure screen without the badge's invest block. Try again sends the same selection again. @@ -361,7 +361,7 @@ store.simplex.chat/?order=q7ZpL2dN9xWc4KfR8tYb1A - + N5a. Part of the amount Shared: BTCPay saw less than the amount, and the page asks for the rest at the same address. @@ -427,7 +427,7 @@ store.simplex.chat/?order=q7ZpL2dN9xWc4KfR8tYb1A - + N8b. Card submitted Shared: a confirm that succeeded is not settlement, so the page waits for the service to say paid, then goes to N4. @@ -476,18 +476,18 @@ N9. The link does not work Shared: an unknown order, a mistyped link, or one retention removed. - + store.simplex.chat/#/codes - -N10. Your codes -The shared list with name rows: the chosen name as the title -(kept only in this browser), what the code covers, and the code -with Copy once paid. Badge rows are unchanged. + +N10. Your codes +The shared list with name rows: the chosen name as the title +(kept only in this browser), what the code covers, and the code +with Copy once paid. Badge rows are unchanged. @@ -506,7 +506,7 @@ store.simplex.chat/#/name - + D1b. N1b, dark The field, its answer and the tiers on the dark ground. @@ -516,7 +516,7 @@ store.simplex.chat/#/name/checkout - + D3. N3, dark The checkout, unchanged but for its rows. @@ -530,58 +530,58 @@ D4. N4, dark The QR keeps its white ground in the dark theme, so it still scans. - -store.simplex.chat - -M0. N0 at 390 px -The two ways in stack under the -hero. - -store.simplex.chat/#/name - -M1b. N1b at 390 px -Name and .simplex on one line; the -tiers stay side by side. - -store.simplex.chat/#/name/years - -M2. N2 at 390 px -The stepper keeps its size; only -the type steps down. - -store.simplex.chat/#/name/checkout - -M3. N3 at 390 px -The three methods stay side by -side, as for a badge. - -store.simplex.chat/?order=q7ZpL2dN9x… - -M5. N5 at 390 px -QR first, then the amount and the -address. - -store.simplex.chat/?order=q7ZpL2dN9x… - -M4. N4 at 390 px -Code, the two buttons, the QR, -then the warnings. - -store.simplex.chat/#/name - -M1e. N1e at 390 px -A taken name at phone width. - - -OP1. Issuing by hand -//issue name <length> [years] beside the badge forms, printing the -code once. //revoke takes either kind. - - -OP2. Issuing in the group -/issue name and /bulk name for moderators -and above, single use. Every member reads -what is posted there, as for badge codes. + +store.simplex.chat + +M0. N0 at 390 px +The two ways in stack under the +hero. + +store.simplex.chat/#/name + +M1b. N1b at 390 px +Name and .simplex on one line; the +tiers stay side by side. + +store.simplex.chat/#/name/years + +M2. N2 at 390 px +The stepper keeps its size; only +the type steps down. + +store.simplex.chat/#/name/checkout + +M3. N3 at 390 px +The three methods stay side by +side, as for a badge. + +store.simplex.chat/?order=q7ZpL2dN9x… + +M5. N5 at 390 px +QR first, then the amount and the +address. + +store.simplex.chat/?order=q7ZpL2dN9x… + +M4. N4 at 390 px +Code, the two buttons, the QR, +then the warnings. + +store.simplex.chat/#/name + +M1e. N1e at 390 px +A taken name at phone width. + + +OP1. Issuing by hand +//issue name <length> [years] beside the badge forms, printing the +code once. //revoke takes either kind. + + +OP2. Issuing in the group +/issue name and /bulk name for moderators +and above, single use. Every member reads +what is posted there, as for badge codes. opened from simplex.chat, a link, or the app Get a SimpleX name types a name @@ -622,20 +622,20 @@ dark theme dark theme dark theme -a phone -a name: available -Continue -Continue -Pay -it confirms -another name: registered -the operator's terminal, --run-cli -the managed group - -Design notes -Design document, not screenshots of a build: every web screen is rendered from mockups/screens.js on the webapp's own compiled modules and styles.css, so the shared screens are the real ones and the name screens are prototypes for nameScreens.ts. -A name code is an entitlement - names of N or more letters for Y years. It is not bound to the name that was checked, because registering needs the owner's wallet key, which only the app has. -The name leaves the page only on Check availability. The service hashes it for the resolver and neither logs nor stores it; checkout carries the tier, the years and the code's hash, never the name. -Prices: $50 a year for 8 or more letters, twice that for 7, four times for 6; 2 to 10 years, paid once, nothing renews. -Regenerate after npm run build in apps/simplex-badge-service/web with: node plans/names-codes/mockups/board.mjs +a phone +a name: available +Continue +Continue +Pay +it confirms +another name: registered +the operator's terminal, --run-cli +the managed group + +Design notes +Design document, not screenshots of a build: every web screen is rendered from mockups/screens.js on the webapp's own compiled modules and styles.css, so the shared screens are the real ones and the name screens are prototypes for nameScreens.ts. +A name code is an entitlement - names of N or more letters for Y years. It is not bound to the name that was checked, because registering needs the owner's wallet key, which only the app has. +The name leaves the page only on Check availability. The service hashes it for the resolver and neither logs nor stores it; checkout carries the tier, the years and the code's hash, never the name. +Prices: $50 a year for 8 or more letters, twice that for 7, four times for 6; 2 to 10 years, paid once, nothing renews. +Regenerate after npm run build in apps/simplex-badge-service/web with: node plans/names-codes/mockups/board.mjs \ No newline at end of file diff --git a/plans/names-codes/screens/D1b.jpg b/plans/names-codes/screens/D1b.jpg index 96b82e2770..c50f5cb36b 100644 Binary files a/plans/names-codes/screens/D1b.jpg and b/plans/names-codes/screens/D1b.jpg differ diff --git a/plans/names-codes/screens/D3.jpg b/plans/names-codes/screens/D3.jpg index 53e6fee55c..46e8f54d9f 100644 Binary files a/plans/names-codes/screens/D3.jpg and b/plans/names-codes/screens/D3.jpg differ diff --git a/plans/names-codes/screens/M1b.jpg b/plans/names-codes/screens/M1b.jpg index e68481eaa2..b0953c4728 100644 Binary files a/plans/names-codes/screens/M1b.jpg and b/plans/names-codes/screens/M1b.jpg differ diff --git a/plans/names-codes/screens/M1e.jpg b/plans/names-codes/screens/M1e.jpg index 3536effd30..b119311ca9 100644 Binary files a/plans/names-codes/screens/M1e.jpg and b/plans/names-codes/screens/M1e.jpg differ diff --git a/plans/names-codes/screens/M2.jpg b/plans/names-codes/screens/M2.jpg index 65a566e54d..2cfaf4886c 100644 Binary files a/plans/names-codes/screens/M2.jpg and b/plans/names-codes/screens/M2.jpg differ diff --git a/plans/names-codes/screens/M3.jpg b/plans/names-codes/screens/M3.jpg index 4e868a294f..bbd42d3616 100644 Binary files a/plans/names-codes/screens/M3.jpg and b/plans/names-codes/screens/M3.jpg differ diff --git a/plans/names-codes/screens/M5.jpg b/plans/names-codes/screens/M5.jpg index 1be0ac6b0e..f372106829 100644 Binary files a/plans/names-codes/screens/M5.jpg and b/plans/names-codes/screens/M5.jpg differ diff --git a/plans/names-codes/screens/N1.jpg b/plans/names-codes/screens/N1.jpg index 513247811f..b0545febda 100644 Binary files a/plans/names-codes/screens/N1.jpg and b/plans/names-codes/screens/N1.jpg differ diff --git a/plans/names-codes/screens/N10.jpg b/plans/names-codes/screens/N10.jpg index 143fd83810..c8fbbde96f 100644 Binary files a/plans/names-codes/screens/N10.jpg and b/plans/names-codes/screens/N10.jpg differ diff --git a/plans/names-codes/screens/N1a.jpg b/plans/names-codes/screens/N1a.jpg index 0f00db5cf5..fc5e645357 100644 Binary files a/plans/names-codes/screens/N1a.jpg and b/plans/names-codes/screens/N1a.jpg differ diff --git a/plans/names-codes/screens/N1b.jpg b/plans/names-codes/screens/N1b.jpg index 441add3fc5..e311ee72af 100644 Binary files a/plans/names-codes/screens/N1b.jpg and b/plans/names-codes/screens/N1b.jpg differ diff --git a/plans/names-codes/screens/N1c.jpg b/plans/names-codes/screens/N1c.jpg index 5794fb74bf..0fb3573128 100644 Binary files a/plans/names-codes/screens/N1c.jpg and b/plans/names-codes/screens/N1c.jpg differ diff --git a/plans/names-codes/screens/N1d.jpg b/plans/names-codes/screens/N1d.jpg index 83c6f957ec..5479ebabcf 100644 Binary files a/plans/names-codes/screens/N1d.jpg and b/plans/names-codes/screens/N1d.jpg differ diff --git a/plans/names-codes/screens/N1e.jpg b/plans/names-codes/screens/N1e.jpg index db98da69cf..6de953fec9 100644 Binary files a/plans/names-codes/screens/N1e.jpg and b/plans/names-codes/screens/N1e.jpg differ diff --git a/plans/names-codes/screens/N1f.jpg b/plans/names-codes/screens/N1f.jpg index 18d9778abc..6693ba9f3d 100644 Binary files a/plans/names-codes/screens/N1f.jpg and b/plans/names-codes/screens/N1f.jpg differ diff --git a/plans/names-codes/screens/N1g.jpg b/plans/names-codes/screens/N1g.jpg index 3c08b6aae4..af51684ad6 100644 Binary files a/plans/names-codes/screens/N1g.jpg and b/plans/names-codes/screens/N1g.jpg differ diff --git a/plans/names-codes/screens/N1h.jpg b/plans/names-codes/screens/N1h.jpg index dc3c6e77cf..f30cb860d1 100644 Binary files a/plans/names-codes/screens/N1h.jpg and b/plans/names-codes/screens/N1h.jpg differ diff --git a/plans/names-codes/screens/N2.jpg b/plans/names-codes/screens/N2.jpg index 89367a2a16..09cf697665 100644 Binary files a/plans/names-codes/screens/N2.jpg and b/plans/names-codes/screens/N2.jpg differ diff --git a/plans/names-codes/screens/N2a.jpg b/plans/names-codes/screens/N2a.jpg index 8ec9a8f8b2..c5e5fbbf66 100644 Binary files a/plans/names-codes/screens/N2a.jpg and b/plans/names-codes/screens/N2a.jpg differ diff --git a/plans/names-codes/screens/N2b.jpg b/plans/names-codes/screens/N2b.jpg index 08f8e9deee..da719a38d2 100644 Binary files a/plans/names-codes/screens/N2b.jpg and b/plans/names-codes/screens/N2b.jpg differ diff --git a/plans/names-codes/screens/N3.jpg b/plans/names-codes/screens/N3.jpg index cd3f3c8933..74ac272bbc 100644 Binary files a/plans/names-codes/screens/N3.jpg and b/plans/names-codes/screens/N3.jpg differ diff --git a/plans/names-codes/screens/N3a.jpg b/plans/names-codes/screens/N3a.jpg index 89d1666a0c..fc38151265 100644 Binary files a/plans/names-codes/screens/N3a.jpg and b/plans/names-codes/screens/N3a.jpg differ diff --git a/plans/names-codes/screens/N3d.jpg b/plans/names-codes/screens/N3d.jpg index 066f41c864..9d354e02d9 100644 Binary files a/plans/names-codes/screens/N3d.jpg and b/plans/names-codes/screens/N3d.jpg differ diff --git a/plans/names-codes/screens/N5.jpg b/plans/names-codes/screens/N5.jpg index e63d5c6236..c7c280ac85 100644 Binary files a/plans/names-codes/screens/N5.jpg and b/plans/names-codes/screens/N5.jpg differ diff --git a/plans/names-codes/screens/N5a.jpg b/plans/names-codes/screens/N5a.jpg index 5949230c57..0e379f9193 100644 Binary files a/plans/names-codes/screens/N5a.jpg and b/plans/names-codes/screens/N5a.jpg differ diff --git a/plans/names-codes/screens/N6.jpg b/plans/names-codes/screens/N6.jpg index cd43810f9c..39734a3f49 100644 Binary files a/plans/names-codes/screens/N6.jpg and b/plans/names-codes/screens/N6.jpg differ diff --git a/plans/names-codes/screens/N8b.jpg b/plans/names-codes/screens/N8b.jpg index 61d2891cc5..beebda5580 100644 Binary files a/plans/names-codes/screens/N8b.jpg and b/plans/names-codes/screens/N8b.jpg differ