Nirvana

The DreamLand Design System

One vocabulary, two surfaces: the marketing site (dreamland.rocks) and the /play web client. Aged gold and arcane purple on obsidian; parchment for reading, dark wells for the game. This page is the source of truth — live surfaces migrate onto it.

Overview

The client was built on the site's vocabulary, so the foundation is already one system — same tokens, same fonts, same gem idea. Where they drifted, the calls below pick a single canon.

Three constraints that override everything

1. The terminal, the map, and any panel that renders ANSI game colour stay on a dark surface — the ANSI palette and screen-reader contrast are tuned for dark ground. 2. Parchment is for reading only (articles, news, hints, modals), never for game colour. 3. Colour is never the only signal of state — about 30% of players use a screen reader or low vision.

Color

The tokens below are shared. The ground, arcane, bright-gold and parchment sets are byte-identical across site and client. The matte-metal surface trio (--gold-metal-*) is the client's; the gems, the ink-purple cross-ref and the article face are the site's. The one thing to remember: gold splits in two — bright for text and for a selected/lit state, matte metal for resting control surfaces.

Ground — obsidian & stone

Arcane — the accent

Gold — text (bright) vs surface (matte metal)

The rule: panel titles, gilded words and links use --gold-bright/--gold. Resting button and control faces use --gold-metal-*. The bright gold also marks a selected/lit state (chosen tab, on-chip). Darken the resting surface, never the text or the lit state.

Gems — faceted-stone accents

Parchment & ink — reading surfaces

Text on dark

Typography

Three faces. The resolved call: one monospace, Fira Code — it carries UI labels, code spans and game text (terminal + article bodies). JetBrains Mono is retired.

--display · Playfair Display · headings, gilded titles
The Crown of Durin, lost beneath Old Thalos
--body · Alegreya Sans · UI & prose
Type what you do, and a huge living world writes back.
--mono / --article · Fira Code · UI labels, code AND game text
You see a rusty short sword here. It glows faintly. (5 damage, level 12)

The ligature rule

Fira Code ships with programming ligatures. In reading (article bodies) they stay ON. In the terminal / map / any aligned output they go OFF (font-variant-ligatures: none) — ligatures glue ->, !=, | together and wreck ASCII maps, tables, and prompts.

Article — ligatures ON
|=| -> != >= == |-- --|
Terminal — ligatures OFF
|=| -> != >= == |-- --|

Texture & shape

--noise · fractal grain (stone + parchment)
--radius · 5px

The one gem recipe

Every gold control points at these three tokens, so the matte finish can never drift back to glossy.

--gem-face: radial-gradient(140% 140% at 50% 0%, --gold-metal-hi, --gold-metal 55%, --gold-metal-lo); --gem-face-hover: radial-gradient(140% 140% at 50% 0%, #6c3aa8, --arcane-deep 60%, #24123f); --gem-shadow: inset 0 1px 1px rgba(255,255,255,.6), 0 1px 2px rgba(0,0,0,.5), 0 0 0 1px --gold-deep;

Buttons

Faceted gem, matte antique gold. Hover swaps to arcane and the label flips light. Three roles, three scales.

Naming — one role, two class sets

The site uses BEM; the client is locked to Bootstrap names (the JSX emits them). The DS names the role; both class sets are aliases for the same look.

RoleSite (BEM)Client (Bootstrap)
Primary — gold gem.btn--gold.btn
Accent — arcane.btn--arcane.btn-primary
Ghost — outline.btn--ghost.btn-secondary / .btn-outline-primary

Focus

One focus language across site and client: the arcane orbit — purple light that circles a focused field. Click in.

Reduced-motion falls back to a steady purple glow. In combat the input border owns red and the orbit stands down.

Form controls

Dark well framed in gold-deep, light text (a typed command echoes the same colour it will print). Switch, dropdown, segmented control and range come from the client settings.

Text input
Dropdown
Switch — off / on

off = muted dark gold, on = arcane. The knob wears a grip.

Segmented — ghost off, primary on, animated

Tabs

Branded jewel pills where players look; the compact/dev tab is just the segmented control.

Jewel pills — user-facing (same gem as the vital bars)

Hover an inactive pill = ghost; the active pill = primary gold gem, and it pops in on select (a quick over-scale) rather than sliding. Toggle-chips pop the same way.

Compact / dev tabs = the segmented control

Cards & panels

Three carved-panel weights, lightest to heaviest: the everyday app/reading card (windowlet), the opt-in modular railed frame, and the login-grade big inset panel. Reach down the list only when the thing deserves it — most content is a windowlet.

Windowlet — the default card · hover it
Windowlet

Masked gradient stroke, chevron ornament along the top, arcane wash. Dense, for who/group/affect panels, list rows, and general content blocks.

Railed — opt-in modular frame · hover it
Railed

Dark panel wearing the modular ornate frame (diamond caps, double strokes, keystones). For a headline card or feature block below the top tier.

Big inset — the login-grade feature panel
Enter DreamLand

Ornate octagon rail over an obsidian body, the modular ornate frame set a step inside, and a living arcane portal breathing behind it. The top tier — hero, login, the one crowned moment. Heavier than the railed card, so it stays rare.

Hover is opt-in: add .ds-card--hover only on cards that are actually clickable (list rows, feature tiles). Static content cards leave it off — no pointer, no lift. Retired: the corner-bracket card and the faceted gem-card. (Gem-cards are still live on the site home page — they deprecate in the live-CSS migration, not here.)

Map / segmented controls

Zoom and layer toggles wear the same matte gem as every other button; the active layer presses in and goes arcane.

Which selected-colour? Choosing one option among peers (segmented, tabs, chips) lights it in gold. A power/on state (switch on, active map layer, focus, the accent button) reads arcane.

Chips

Not one component with two skins — two different jobs.

Toggle-chip — interactive filter (same grammar as segmented: ghost off, primary on)
Data-chip — read-only, colour-coded per affect type
sanctuary haste 12r poison 3r fly calm STR 18

Data-chip colour = --chip-accent (buff green, debuff red, magic amethyst, mind sapphire, stat gold). The affects widget sets it per affect.

Parchment — reading surfaces

Aged sheet with a torn, worn edge, the modular frame sitting a step inside the rag (same corners/sides/keystones as the railed card, recoloured to --parch-edge). Help articles, news, hints, side-sheet modals. Game colour gets a light-tuned ANSI remap — never the dark palette on parchment.

On Ereshkigal, the Silent

The temple doors stand gilded and shut. A violet glow leaks from the seam. See also the Eight Paths.

Cross-refs on parchment use --arcane-ink (the bright accent washes out on light). One frame system, two surfaces: gold on dark, parch-edge on cream.

Dark — game surfaces

The terminal well, the map, the ANSI panels. Dark, gold-framed, Fira with ligatures off. This never becomes parchment.

Terminal well (80-col game text)
A rusty short sword lies here. The orc snarls: "You'll not pass!" > kill orc

ANSI palette (dark ground)

rgyb mcwd RGYB MCWD

Vital bars — hp / mana / move

HP 245/300
MANA 77/120
MV 18/40

The gem marks the resource (same faceted jewel the pill tabs wear). Colour is never the only signal — value text + the affects panel carry state for screen readers.

Ornaments

The decorative library. Skeuomorphic ornament rides the chrome; reading text stays clean. Everything here is modular — corners and sides that reuse and expand at one weight, no scaling.

Filigree divider

Modular frame — corners + sides

One corner mask (--frame-corner), flipped for the other three, plus consistent-weight side rules. Same weight at any size — no stretch. A side can also carry a chevron run.

Frame — double-stroke sides + keystones
Same frame, wider + chevron bottom side

Chevron ornament kit

The modular shape set (Figma 1124:7090): nested double-stroke units ridden as a currentColor mask. Middle is the repeating tooth; the -line pieces transition a tooth into a plain rule; the tl/bl/rt/rb caps close the ends. All nine modules, left to right:

Two compositions ship ready — a band and a divider. Both feed the chrome: the band is the windowlet top and the frame's chevron side; the divider brackets a section rule.

Normal row — the tooth tiled (band)
Row with line — caps + a plain rule (divider)
Recolours with currentColor (arcane)

The rules

The short version. Break these and the thing stops being one system.

Dark vs parchmentGame colour (ANSI, terminal, map, vitals) on dark. Parchment for reading only.
Gold surface vs gold textMatte --gold-metal-* for resting control faces; bright --gold-bright/--gold for text and the selected/lit state. Darken the resting surface, never the text.
Gold vs arcane selectionChoosing one option among peers (segmented, tabs, chips) = gold. A power/on state (switch on, active map layer, focus, accent button) = arcane.
One gem recipeAll resting gold controls point at --gem-face / --gem-shadow. The arcane accent is the one lit exception, with its own recipe.
One monospaceFira Code for UI labels, code and game text. Ligatures ON in article bodies, OFF in the terminal / map / any aligned output.
FocusArcane orbit on every focusable field, both surfaces. Reduced-motion → steady glow.
Ornament is modularCorners and sides reuse at one weight; recolour with currentColor. No stretching an ornament to fit.
AccessibilityColour is never the only signal. Native <select> on narrow screens. ~30% of players read by screen reader.

Source of truth. Live theme.css (site) and theme-parchment.css (client) migrate onto these decisions in a later, separately-reviewed pass.