Files
FabledGrimoire/docs/design-system.md
T
bvandeusenandClaude Opus 5.5 e99f1169f7
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m1s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 36s
rename(547): what people read says Grimoire
Step 1 of the Scribe -> Grimoire rename: every capitalised "Scribe" in prose
becomes "Grimoire" ("Fabled Scribe" -> "Fabled Grimoire") across the UI,
the PWA manifest and page title, the MCP instructions and tool docstrings,
hook and skill text, docs and README, with the tests that assert on that
prose moving with it. Old migrations keep their wording.

Identifiers are untouched here: the package, plugin name, MCP server key,
hook file names, env vars, the .scribe marker and FabledScribe repo/image
names move in steps 2 and 3, along with prose that quotes them.

The sweep matched "Scribe" only as a whole word, so describe/subscribe and
friends are untouched. The longer name took the MCP instructions one
character over their 1,600 budget; two phrases are shortened to fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 10:46:37 -04:00

17 KiB

FabledSword Design System

A house-style design system for the FabledSword family of self-hosted applications. FabledSword is the umbrella identity; individual apps share a common visual language but each carries its own signature accent color.

Brand model

FabledSword is a house style, not a single brand. Apps share:

  • Typography
  • Surfaces and dark-mode foundation
  • Component shapes (pills, cards, buttons)
  • Spacing system
  • Semantic colors (success, warning, error, info)
  • Action button colors (moss primary, bronze secondary)
  • Voice and tone

Each public app has its own signature accent used for: the wordmark, the app icon, active nav state, "you are here" indicators, cursor/selection color, and key brand moments. Accents do not appear on action buttons — those stay system-wide.

Aesthetic direction

Modern mythic with heraldic restraint. Tech-forward execution, but the visual language borrows from manuscripts, heraldry, and forged objects rather than from gaming or fantasy iconography. Dark-mode-first because that's where these apps live.

The reference points: a well-printed book, a well-kept armory, a steward's ledger. Not: a fantasy novel cover, a tabletop RPG character sheet, a Renaissance Faire poster.


Color system

Universal surfaces (dark mode foundation)

Token Hex Usage
Obsidian #14171A Page background, deepest surface
Iron #1E2228 Card surfaces, raised elements
Slate #2C313A Hovered surfaces, secondary elevation
Pewter #3F4651 Borders, dividers, ghost button outlines

Universal text and parchment

Token Hex Usage
Parchment #E8E4D8 Primary text on dark surfaces
Vellum #C2BFB4 Secondary text, captions
Ash #9C9A92 Tertiary text, hints, metadata

Parchment is intentionally not pure white — it's slightly warm to feel like aged paper. Pure white (#FFFFFF) is never used as text color.

Universal action colors

Token Hex Usage
Moss #4A5D3F Primary action buttons (Save, Submit, Confirm)
Bronze #8B7355 Secondary action buttons (Cancel-but-not-destructive, alternate paths)
Pewter #3F4651 Tertiary/ghost buttons

Critical rule: Action button colors are universal across all apps. A Save button in Grimoire and a Save button in Minstrel look identical. Per-app accents do not appear on buttons.

Semantic colors

Token Hex Usage
Success #4A5D3F Success states (same as Moss — they're aligned by design)
Warning #8B6F1E Warnings, caution states
Error #C04A1F Error messages, validation failures
Info #3D5A6E Informational callouts
Destructive #6B2118 Destructive action buttons (Delete, Remove, irreversible)

Why error and destructive are different: Error is the orange-red used in alerts and validation messages. Destructive (oxblood) is reserved for buttons that perform irreversible actions — it carries more weight precisely because it's used sparingly. Pair destructive buttons with an icon (trash, X) so color is reinforcement, not the only signal.

Per-app signature accents

App Hex Mood
Fabled Grimoire #5B4A8A Dusty violet — ink, manuscripts
Minstrel #4A6B5C Forest teal — music, performance
Fabled Forge #8B5A2B Forge bronze — creation, craft
Roundtable #4A5D7E Slate blue — stewardship, infrastructure
FabledSword (umbrella) #6B2118 Oxblood — house identity, ceremonial use only

Accent usage rules:

  • The accent appears on the app's wordmark and icon.
  • The accent indicates active/current state in nav (the selected page, the active tab).
  • The accent is the cursor color and text-selection color in long-form surfaces (Grimoire notes, Forge story drafts).
  • The accent does NOT appear on primary or secondary action buttons.
  • The accent does NOT appear in body text or chrome.
  • One accent per app. Don't mix accents within a single app.

Color contrast

All text-on-surface combinations meet WCAG AA at minimum. Parchment on Obsidian is the maximum-contrast pairing; Vellum on Iron is the lowest-contrast pairing still considered acceptable for body text. Ash is for hints only — never load-bearing information.


Typography

Type families

Family Role Source
Fraunces Display, headings, wordmarks Google Fonts
Inter Body, UI, labels Google Fonts
JetBrains Mono Code, terminal output, monospaced data Google Fonts

Why this pairing

Fraunces is a contemporary serif with personality — it has the warmth and authority of a book serif without feeling like costume. It signals "this is considered" without signaling "this is a fantasy product." Inter is the workhorse — neutral, ubiquitous, designed for screens, doesn't compete with the serif. JetBrains Mono is the natural choice for any developer-adjacent product and supports ligatures.

Type scale

Token Size Weight Family Usage
Display 40px 500 Fraunces App wordmark, hero text
H1 32px 500 Fraunces Page titles
H2 24px 500 Fraunces Section headings
H3 18px 500 Inter Subsection headings, card titles
Body 15px 400 Inter Paragraphs, default text
Body small 13px 400 Inter Captions, metadata
Label 12px 500 Inter Buttons, form labels, badges
Code 13px 400 JetBrains Mono Inline code, code blocks
Tiny 11px 500 Inter Micro-labels (UPPERCASE LETTERSPACED)

Typography rules

  • Sentence case everywhere. Never Title Case for headings, never ALL CAPS except for the Tiny micro-label style.
  • Two weights only: 400 regular and 500 medium. Never 600 or 700 — they read heavy in dark mode.
  • Fraunces only at 18px and above. Below that it loses too much detail and feels fragile. For h3 and below, use Inter.
  • Line height 1.5 for body, 1.3 for headings, 1.7 for long-form reading surfaces (Grimoire notes, Forge drafts).
  • Letter-spacing at default for everything except the Tiny micro-label, which gets 0.08em letter-spacing and uppercase styling.

Spacing and layout

Spacing scale (px)

4, 8, 12, 16, 20, 24, 32, 48, 64, 96

Use rem units for vertical rhythm in long-form content (paragraph spacing). Use px for component-internal spacing (padding, gaps).

Border radius

Token Size Usage
Small 4px Pills, tags, code spans
Medium 8px Buttons, inputs, small cards
Large 12px Cards, panels, modals
Extra large 16px Hero containers, major surfaces

Borders

  • Default border: 0.5px solid Pewter (#3F4651)
  • Hovered/emphasized border: 0.5px solid Vellum at 30% opacity
  • Featured/active border: 2px solid [accent] (only for emphasizing a selected card or active tab)

The 0.5px default is deliberate — it reads as a hairline at most pixel densities and avoids the heavy "boxed-in" feeling that 1px+ borders create on dark backgrounds.


Components

Buttons

Variant Background Text Border
Primary Moss #4A5D3F Parchment None
Secondary Bronze #8B7355 Parchment None
Ghost Transparent Parchment 0.5px Pewter
Destructive Oxblood #6B2118 Parchment None — pair with icon

Padding: 8px 16px for default, 6px 12px for compact, 10px 20px for prominent. Border-radius: 8px. Font: Inter 12px/500 with default letter-spacing.

Pills and tags

Used for tags, hashtags, code spans, status badges. Background is the accent color at ~15% opacity, text is the accent at full strength. Border-radius 4px, padding 2px 8px, Inter 11px/500.

In Grimoire specifically, hashtags and tags use the dusty violet accent. In Minstrel, they'd use forest teal. The pattern is shared; the color follows the app.

Cards

  • Background: Iron (#1E2228)
  • Border: 0.5px Pewter
  • Border-radius: 12px
  • Padding: 20px

For featured/selected cards, swap to a 2px solid accent border. Don't change the background.

Inputs

  • Background: Obsidian (#14171A) — darker than the page surface to feel "inset"
  • Border: 0.5px Pewter
  • Border-radius: 8px
  • Padding: 8px 12px
  • Focus state: 2px solid accent ring (using box-shadow: 0 0 0 2px [accent] to avoid layout shift)

Code blocks

  • Background: Obsidian (#14171A)
  • Border: 0.5px Pewter
  • Border-radius: 8px
  • Padding: 12px 16px
  • Font: JetBrains Mono 13px/400
  • Inline code: same family, with 4px-radius pill background using the app accent at 15% opacity

The FabledSword lockup

A small, persistent FS mark appears in the navigation chrome of every app — the way an Apple logo persists across macOS apps. This is the only place oxblood appears in normal app usage.

Specification:

  • 16-20px height in nav contexts
  • Oxblood (#6B2118) on dark surfaces
  • Positioned in the bottom-left of nav rails or top-left when there's no rail
  • Hover/click reveals a small menu: link to other apps in the family, link to FabledSword.com, version info

The lockup itself is a small heraldic mark — a stylized FS monogram — not a literal sword icon. We're avoiding sword imagery in app chrome because it would clash with the restrained, modern-mythic aesthetic. The wordmark "FabledSword" appears only on the umbrella site and in About/Settings dialogs.


Voice and tone

The FabledSword voice is understated mythic — it borrows the register of stewardship, craft, and considered making, but never tips into roleplay or affectation.

Do

  • Use plain language for everything functional. ("Save", "Cancel", "Add note")
  • Reserve flavored language for moments where the user is waiting or failing — loading states, empty states, error pages, 404s.
  • Borrow vocabulary from craft and stewardship: "draft", "ledger", "kept", "set aside", "to come", "in progress", "abandoned".
  • Be brief. The mythic register is undermined by verbosity.

Don't

  • Don't use thee/thou/thy or pseudo-archaic spelling.
  • Don't address the user as "traveler", "wanderer", "adventurer", or any RPG-adjacent epithet.
  • Don't use sword/blade/forge metaphors in error messages. ("Your save was forged successfully" — no.)
  • Don't make the user feel like they're playing a game when they're just trying to use software.

Examples

Context Plain FabledSword voice
Empty list "No items yet" "Nothing kept here yet."
404 "Page not found" "This page is not in the ledger."
Loading "Loading..." "Fetching..." (just keep it plain — the mythic note is reserved for moments with more space)
Save success "Saved!" "Saved." (plain — success doesn't need flavor)
Save error "Error saving" "Couldn't save. The change has been kept locally — try again in a moment."
Delete confirm "Delete this?" "Remove this from the ledger? This can't be undone."

The pattern: action-adjacent language stays plain; absence/failure/waiting gets the flavor.


Iconography

Style

  • Stroke-based, 1.5px stroke weight at 24px, 1px at 16px
  • Rounded line caps and joins
  • 24px or 16px grid
  • Outline style by default; filled style only for active/selected states

Use Lucide (https://lucide.dev) as the base icon set — it matches this style exactly and is open-source. Only commission custom icons for app-specific concepts that Lucide doesn't cover.

Don't

  • No filled icons in default UI (reserve for active states)
  • No icon styles that mix stroke and fill chaotically
  • No literal medieval imagery (swords, scrolls with curls, banners) in functional UI
  • No emoji as icons

Per-app application

Fabled Grimoire (#5B4A8A — dusty violet)

A second-brain notes and task management tool. The accent appears in: the wordmark, hashtags and tag pills, the active nav item, text selection color, and the cursor in the editor. Notes are presented on Iron-surfaced cards with generous reading line-height. The hashtag system uses Grimoire's accent for visual continuity.

Minstrel (#4A6B5C — forest teal)

Self-hosted music. The accent appears on: now-playing indicators, active track highlights, the wordmark, equalizer/visualization elements. Album art dominates visually, so the accent should appear in chrome and metadata, never overlapping cover imagery.

Fabled Forge (#8B5A2B — forge bronze)

Story-building and worldbuilding tool. The accent appears on: the wordmark, character/location/object markers in story trees, the editor cursor, "kept/canon" indicators distinguishing finalized story elements from drafts. This app benefits from Fraunces being used more aggressively — for entity titles, chapter headings, etc.

Roundtable (#4A5D7E — slate blue)

Home server management. The accent appears on: the wordmark, healthy/online status indicators, the active dashboard panel border. Status colors here are critical — green for healthy, amber for warning, red (the orange-red error tone, not oxblood) for failed. The accent itself indicates "this is the panel I'm currently looking at."

Naming note: "Roundtable" leans the wrong direction — its connotation is equal participants in discussion rather than one steward managing a domain. Consider "Steward" or "Castellan" if you revisit naming. Castellan in particular is good — it specifically means "the officer in charge of a castle."


Implementation notes

CSS custom properties

:root {
  /* Surfaces */
  --fs-obsidian: #14171A;
  --fs-iron: #1E2228;
  --fs-slate: #2C313A;
  --fs-pewter: #3F4651;

  /* Text */
  --fs-parchment: #E8E4D8;
  --fs-vellum: #C2BFB4;
  --fs-ash: #9C9A92;

  /* Action */
  --fs-moss: #4A5D3F;
  --fs-bronze: #8B7355;

  /* Semantic */
  --fs-warning: #8B6F1E;
  --fs-error: #C04A1F;
  --fs-info: #3D5A6E;
  --fs-oxblood: #6B2118;

  /* Typography */
  --fs-font-display: 'Fraunces', Georgia, serif;
  --fs-font-body: 'Inter', system-ui, sans-serif;
  --fs-font-mono: 'JetBrains Mono', ui-monospace, monospace;

  /* Layout */
  --fs-radius-sm: 4px;
  --fs-radius-md: 8px;
  --fs-radius-lg: 12px;
  --fs-radius-xl: 16px;
}

/* Per-app accent — set ONE of these on the root for each app */
[data-app="scribe"]    { --fs-accent: #5B4A8A; }
[data-app="minstrel"]  { --fs-accent: #4A6B5C; }
[data-app="forge"]     { --fs-accent: #8B5A2B; }
[data-app="roundtable"]{ --fs-accent: #4A5D7E; }

Tailwind integration

If using Tailwind, extend the theme with these tokens rather than relying on default colors. The default Tailwind palette will fight this system — you'll get drift back toward bright defaults if you don't lock down the palette explicitly.


What this kit deliberately does NOT include

  • Logo files. The lockup design is described conceptually but the actual mark needs to be drawn. Hire a designer or use Claude Design to iterate on a heraldic FS monogram.
  • Marketing site design. This kit is for application UI. The umbrella marketing site (FabledSword.com) can use this system but will need additional patterns (hero layouts, feature grids, etc.).
  • Email templates. Different constraints, different problem.
  • Print collateral. Not in scope.
  • Mobile native app patterns. This is web-first. iOS/Android conventions would override several choices here (button shapes, navigation patterns).

Grimoire

The design system Grimoire renders with is stored in Grimoire itself: Grimoire, which inherits FabledSword, edited at /design-systems. frontend/src/assets/theme.css is generated from it, and CI rejects a var() the sheet doesn't define. Where this page and the stored system differ, the stored system is right. Grimoire applies the baseline above with these choices:

  • Accent footprint. Dusty violet marks Grimoire's own moments: the wordmark, active navigation, the editor's cursor and selection, tags and wikilinks, in-progress status, focus rings, and the call to action that starts something new (a first note, say). Operating the software uses the action colours: Moss to save or confirm, Bronze for alternatives, Oxblood with an icon to delete, Pewter ghost for tertiary actions.
  • Light and dark. Both are supported. Light mode is warm parchment (#F5F1E8 page, #FBF8F0 cards, #14171A text) rather than white, with a cool wash on code blocks so syntax colours stay readable. The accent, action and semantic colours are the same in both.
  • Status and priority. Status: todo Pewter, in progress the accent, done Moss, cancelled Ash, paused Warning. Priority runs cool to warm: low Info, medium Warning, high Error. Overdue uses Error. Each has a low-alpha -bg companion.
  • Type. Inter for UI and body, Fraunces at 18px and up (display, H1, H2), JetBrains Mono for code. Two weights only, 400 and 500. Line height 1.5 for body, 1.3 for headings, 1.7 on reading surfaces such as a note.
  • Icons. Lucide, at 16px inline and 24px for navigation and primary actions; no emoji in the interface.
  • Borders are structural. Cards, dialogs, code blocks, focus rings and major dividers get borders; list rows, chips and empty states are separated by surface tint and spacing instead.