External NIP-46 signer mode is a stronger posture, not a caveat: the key never arrives on this machine, so a compromised desktop cannot extract it. The old claim only holds for embedded/bunker modes and undersold the external-signer option. UI already ranked modes correctly; no code change.
16 KiB
| name | description | colors | typography | rounded | spacing | components | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Nostr Keynctr | Local-first Nostr identity atelier — keys stay in Rust, the UI stays calm and warm. |
|
|
|
|
|
Design System: Nostr Keynctr
Overview
Creative North Star: "Vault & Atelier"
Nostr Keynctr is an atelier, not a dashboard — a warm, quiet workshop where identity work is done with care. The space feels like heavy paper and soft stone, with ink that is near-black, not pure black. Instruments are laid out plainly; nothing shouts for attention. Trust is built through precision: consistent edges, settled type, and state that is always legible. The product truth — in local modes keys never leave Rust, and in external-signer mode they never arrive on this machine at all — is mirrored visually: the UI is restrained, the material is honest, and every destructive or security-relevant moment is given deliberate weight.
The aesthetic is warm and human, not technical or bold. Density is Operate: scannable lists, clear hierarchies, and generous but not loose spacing (8/12/16/20/32). The four themes (light, dark, glass/Aurora, neon) share the same semantic roles; only the material values shift. Neon and glass are gated expressions, never the default.
Key Characteristics:
- Warm and human, precise and calm — humanity first, then exactness.
- Paper and stone material language — tonal layering over heavy shadows.
- Semantic tokens only — every color has a job (public data vs. private operation vs. relay health vs. security).
- Operate density — tasks complete faster because hierarchy is consistent.
- Vault logic made visible — locked/muted states are distinct at a glance.
Colors
Four themes share the same semantic roles; values below are the light (paper) baseline extracted from frontend/src/styles.css (:root / :root[data-theme='light']). Dark, neon, and glass override the same tokens (see Elevation notes for glass treatment).
Primary
- Antique Brass — restrained identity accent (
{colors.antique-brass}#6d5ae6): Used for primary actions, active nav (is-active), focus rings, and the themed undo bar link ("Undo and restore profile"). Restrained — ≤10% of any screen. Hover is{colors.antique-brass-hover}#5c49d4; wash is{colors.antique-brass-soft}#efecfd. - Focus Violet (
{colors.focus}#6d5ae6): Same value as primary; outlines viaoutline: 2px solid var(--focus).
Neutral
- Warm Ivory — canvas (
{colors.warm-ivory}#f6f4f0):var(--bg)— page background. - Paper — surface (
{colors.paper}#ffffff):var(--surface)— cards, sidebar, modals. - Soft Stone — raised/tinted surface (
{colors.soft-stone}#f1ede7):var(--surface-2)— inline code, secondary surfaces, segmented control track,create-explainer. - Stone Hover — hover wash (
{colors.stone-hover}#faf8f5):var(--surface-hover). - Ink — primary text (
{colors.ink}#201b15):var(--text)— near-black, never pure black. - Ink Muted — secondary text (
{colors.ink-muted}#6d655a):var(--text-muted)— subtitles, hints,.muted, dates. - Line — hairline border (
{colors.line}#e6e0d6):var(--border). - Line Strong — emphasized border (
{colors.line-strong}#d8d0c3):var(--border-strong)— input strokes, secondary buttons.
Semantic Feedback
- Muted Sage — secure/success (
{colors.muted-sage}#22713c / wash #e7f5ec): active profile border, success badges/alerts. Not decorative — only for successful security-state confirmation. - Signal Coral — destructive/warning/error (
{colors.signal-coral}#c0392b / wash #fdecec): danger buttons, error alerts, relay bad dots. Destructive actions live here alone. - Antique Gold — caution (
{colors.antique-gold}#9a6b13 / wash #fcf3e0): warning badges/alerts. - Clear Ink — information/relay (
{colors.clear-ink}#2868a4 / wash #e9f2fb): info badges/alerts, relay neutral states. - On Brass — text on accent (
{colors.on-brass}#ffffff): label inside primary buttons.
Theme overrides (same roles, different material): Dark inverts to ink surfaces (#211d29, #2a2534) with primary #8b7cff; Neon uses pure black panels (#000000) and Cyber Pink primary #ff1493 + Aurora Purple/Yellow highlights; Glass (Aurora) uses translucent rgba(23,29,41,0.58) surfaces with backdrop-filter: blur(18px) saturate(160%) and cyan primary #7fdbff. Tokens stay semantically identical, so components do not branch per theme.
Named Rules
The One Accent Rule. Antique Brass is the only saturated accent in the restrained palette. Its rarity is the point — use it for primary actions and active state only.
The Vault Separation Rule. Secret-dependent UI never shares color with public data: private operations are flagged via muted-sage/signal-coral and explicit Approve/Reject, never via primary alone.
Typography
Display Font: System UI stack (system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif) — no custom display face; trust is in weight and rhythm, not ornament.
Body Font: Same System UI stack — continuity over contrast.
Label/Mono Font: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace — code and npub only.
Character: Humanist, quiet, and precise. Weight 650 for headings is the only emphasis; body is regular 15/1.5 for long-form readability without dense compaction.
Hierarchy
- Display (650, 24px, 1.25):
h1page titles only — one per screen. - Headline (650, 16px, 1.25):
h2card heads, modal titles. - Title (650, 16px, 1.25): Profile/cluster names (
.profile-name,.profile-card-meta h3). - Body (400, 15px, 1.5): All reading text,
p,li,.page-subtitle(14px muted variant). Max width ~65–75ch in cards. - Label (600, 13px): Field labels,
.hint,.char-count,.field > label. - Mono (400, 13.8px / 0.92em):
code,.mono, npub displays — always onSoft Stonepill.
Named Rules
The Weight Restraint Rule. Only headings are 650. Do not add semibold to body or emphasize muted text with weight — color shift (ink → ink-muted) is the emphasis.
Layout
Canvas: Centered column (max-width: 920px, margin: 0 auto) with screen padding 32px 40px 56px (collapses proportionally on narrow viewports). Inner stack via .screen-inner (gap: 20px, flex-direction: column).
Shell: Fixed sidebar 248px + flexible .main (overflow-y: auto). Sidebar is paper on light, translucent blurred pane on glass. App is height: 100vh locked; only main scrolls.
Grids: Home is single-column (gap: 20px). Profiles use responsive repeat(auto-fill, minmax(280px, 1fr)) (gap: 16px). Relays are vertical list (gap: 12px). Compose card keeps tabs above editor; preview stacks below.
Spacing rhythm: 8/12/16/20/32. Section gaps 20px; card internal padding 18–20px; button padding 10px 18px (md) / 7px 12px (sm); input padding 10px 12px. No arbitrary values — step on the scale.
Responsive: Flex-wrap at page heads and action rows; segmented controls wrap; profile grid collapses to single column; modal max-width 520px, max-height 88vh.
Elevation & Depth
System is flat-by-default, tonal before lifted. Depth is conveyed first by material contrast (Warm Ivory → Paper → Soft Stone) and 1px Line borders. Shadows are whisper-low and never the primary separation.
Shadow Vocabulary
- Paper Lift (
box-shadow: 0 1px 2px rgba(30,25,18,0.05), 0 8px 24px rgba(30,25,18,0.06)): Cards, profile cards — the default lift for paper surfaces on ivory. - Modal Lift (
box-shadow: 0 12px 40px rgba(20,15,10,0.22)): Modals — only overlay that earns a large, soft shadow. On dark:0 12px 40px rgba(0,0,0,0.6). - Neon Glow (gated) (
0 0 32px rgba(255,20,147,0.12)paired with dark shadows): Only indata-theme='neon'modals — never on light/paper.
Glass/Aurora exception: Panels become translucent (rgba(23,29,41,0.58), rgba(255,255,255,0.05)) with backdrop-filter: blur(18px) saturate(160%); body carries three radial gradients (cyan/purple/aqua washes) to create depth through blur, not shadow.
Named Rules
The Flat-By-Default Rule. Surfaces are flat at rest. Shadows appear only as a response to layer (card on canvas, modal over app). Never add shadow to inline controls or navigation.
Shapes
Form language is softly squared with a pill exception. Corners are gentle, never sharp, never fully rounded except for tags and avatars.
- Soft square (
border-radius: var(--radius)14px): Cards, modals (16px), empty states — the workhorse. - Compact square (
border-radius: var(--radius-sm)9px): Buttons, inputs, alerts, segmented control, nav items. - Pill (
border-radius: 999px): Badges,npub-chip, toggles, compose tabs, segmented buttons. - Circle (
50%): Avatars (42px / 52px lg), toggles thumb. - Empty-state dash (
border: 1.5px dashed var(--border-strong)): Deliberately unfinished — signals "bring your own." - Glass blur is shape-adjacent: panels keep the same radii but gain
backdrop-filterto soften edges without changing geometry.
Components
Buttons
- Shape: Compact square (9px),
font-weight: 600,gap: 8px. - Primary (Antique Brass on Paper):
background: var(--primary)/color: var(--on-primary)/padding: 10px 18px(md) or7px 12px(sm). Hover →var(--primary-hover). Loading shows spinner inrgba(255,255,255,0.4)track. - Secondary:
background: var(--surface)/border: 1px solid var(--border-strong)/color: var(--text)/ Hover →var(--surface-hover). - Danger:
background: var(--danger-soft)/color: var(--danger)/ Hover →var(--danger)on white. - Ghost:
background: transparent/color: var(--text-muted)/ Hover →var(--surface-2)+var(--text). - Focus everywhere:
outline: 2px solid var(--focus)offset: 2px.
Chips / Badges
- Style: Pill (999px),
padding: 3px 10px,font-size: 12px/weight: 650, neutral usesvar(--surface-2)+var(--border), semantic variants use<role>-softwashes.
Cards / Containers
- Corner Style: Soft square (14px).
- Background:
var(--surface)(or translucent on glass). - Shadow Strategy: Paper Lift by default; see Elevation.
- Border:
1px solid var(--border)(active profile card upgrades tovar(--success)). - Internal Padding:
18px(profile card) /20px(card-body).
Inputs / Fields
- Style:
background: var(--surface)/border: 1px solid var(--border-strong)/radius: 9px/padding: 10px 12px/font: inherit. - Focus:
border-color: var(--focus)+box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus) 22%, transparent). - Error:
.field-errorinvar(--danger)13px / 500. - Hint:
.hintinvar(--text-muted)13px.
Navigation (Sidebar)
- Style: Sidebar
248px,background: var(--surface),border-right: 1px solid var(--border). Brand block with38pxwhite tile (invertedfilter: invert(1)on dark/neon/glass). - Nav item:
padding: 11px 12px/radius: 9px/font-weight: 550/color: var(--text-muted)→ hovervar(--surface-2)+var(--text)→ activevar(--primary-soft)+var(--primary). - Footer: Profile row + top border
1px solid var(--border).
Undo Bar (Signature Component)
- Shape: Compact square (
8px),padding: 10px 14px,border: 1px solid var(--border),background: var(--primary-soft). - Character: Warm, not alarming — confirms deletion without shouting. Label in
var(--text)500, dash invar(--text-muted), action as themed link. - Action: Inline
<button>styled as link (background: none/color: var(--primary)/font-weight: 600/underline2pxoffset). Auto-dismisses after 5s; restores viaundoDelete. Same token treatment on all themes.
Do's and Don'ts
Do:
- Do keep Warm Ivory (
#f6f4f0) as the only page canvas on light; let Paper and Soft Stone carry the hierarchy. - Do use Muted Sage wash only for successful security confirmation (active badge, save success).
- Do keep one primary per screen — Antique Brass is rare by design; secondary actions stay ghost or secondary.
- Do use
var(--focus)(same as primary) for every focus ring; keep the 2px + 2px offset invariant. - Do preserve the side-by-side rate: cards on Paper with 1px Line borders before adding any shadow.
- Do let glass blur inherit radii; never change corner size just for translucency.
Don't:
- Don't use Signal Coral outside error/destructive states — never for decorative accents or neutral badges.
- Don't introduce a new accent hue outside the four semantic washes (primary/success/warning/danger/info); add a new feature with existing tokens.
- Don't bump heading weight beyond 650 or add bold to muted text — shift color to Ink Muted instead.
- Don't apply neon glow (pink
0 0 32px rgba(255,20,147,0.12)) outsidedata-theme='neon'modals. - Don't invent a new radius — step on
9px/14px/16px/999pxonly. - Don't replace the 5s auto-dismiss undo bar with a permanent modal; the atelier stays calm after a task.