design tokens - Drowbe/coffee-pub-blacksmith GitHub Wiki

Design Tokens

Audience: module authors styling against Blacksmith.

The complete set of CSS custom properties Blacksmith defines, what each one means, and how to consume or override them from another module.

The authoritative definition is styles/vars.css. This page is checked against it by tools/check-design-tokens.mjs, which fails if any value here drifts or any token goes undocumented.

How tokens reach your module

styles/vars.css declares every token on :root, and Foundry loads it as part of Blacksmith's stylesheet set. Once Blacksmith is active the tokens are global: a child module references them with no import, no build step, and no load-order handling.

/* in your module's CSS -- works as long as Blacksmith is active */
.my-module-panel {
    padding: var(--blacksmith-space-lg);
    background: var(--blacksmith-surface-dark-1);
    color: var(--blacksmith-text-light);
    border-radius: var(--blacksmith-radius-md);
}

Always supply a fallback for anything that must survive Blacksmith being disabled:

padding: var(--blacksmith-space-lg, 12px);

To retheme Blacksmith's own components inside your module's scope, redefine a token on your root element. The override cascades to any Blacksmith component rendered within it:

#coffee-pub-mymodule { --blacksmith-color-brand-accent: #4a7a2a; }

Two constraints carried from styles/vars.css:16-17: component-specific rules do not belong in that file, and new CSS references tokens rather than repeating literal values.

Spacing

The scale is deliberately short. Pick the nearest step rather than introducing an intermediate value.

Token Value Use
--blacksmith-space-xs 2px Micro gaps -- icon padding, hairline margins
--blacksmith-space-sm 4px Tight spacing -- icon margins, dense rows
--blacksmith-space-md 8px Standard padding -- buttons, compact elements
--blacksmith-space-lg 12px Section padding -- card internals, form groups
--blacksmith-space-xl 20px Separation between major content blocks
--blacksmith-dialog-max-width 560px Cap for a content-sized dialog, so auto width cannot run to the viewport

When converting existing literals: 2px to xs, 4px to sm, 6px and 8px to md, 10px and 12px to lg, 16px and 20px to xl.

Color: brand

The core palette. Everything else is a surface, a text tone, or a status.

Token Value Use
--blacksmith-color-brand #594a3c Primary text and body
--blacksmith-color-brand-dark #481515 Headers
--blacksmith-color-brand-accent #c15701 Interactive and hover orange
--blacksmith-color-brand-muted #8d8061 Borders, dividers, muted text

Color: light surfaces

The parchment / chat-card context, lightest to strongest.

Token Value Use
--blacksmith-surface-0 #ffffff Pure white
--blacksmith-surface-1 #f6f1ed Off-white content areas
--blacksmith-surface-2 #e4ddd9 Raised areas, headers
--blacksmith-surface-3 #c4bcaa Stronger contrast areas

Color: dark surfaces

The window / toolbar context, deepest to lightest.

Token Value Use
--blacksmith-surface-dark-0 #0e0c0c Near black, deepest
--blacksmith-surface-dark-1 #222222 Main window background
--blacksmith-surface-dark-2 #313030 Button background
--blacksmith-surface-dark-3 #4b4b4b Borders, dividers

Color: text

Pick by the surface the text sits on, not by the component.

Token Value Use
--blacksmith-text-primary #594a3c On light surfaces
--blacksmith-text-secondary #746950 Subdued on light
--blacksmith-text-light #bdbdae On dark surfaces
--blacksmith-text-muted #ada39d Subdued on dark
--blacksmith-text-inverse #ffffff High contrast on dark

Color: interactive states

Token Value Use
--blacksmith-interactive-default rgba(21, 9, 1, 0.9) Resting interactive surface
--blacksmith-interactive-hover rgba(97, 41, 4, 0.4) Hover wash
--blacksmith-interactive-active rgba(124, 62, 10, 0.8) Pressed or active

Color: status

Semantic outcome colors, for text and solid fills.

Token Value Use
--blacksmith-status-success #629602 Success, pass
--blacksmith-status-warning #aa6000 Warning, caution
--blacksmith-status-danger #8b0000 Failure, destructive
--blacksmith-status-damage #d63737 Combat damage, distinct from danger
--blacksmith-status-info #3c6685 Informational

Color: token disposition

One pair per CONST.TOKEN_DISPOSITIONS value, identifying a token or combatant as friendly, neutral, hostile, or secret.

These are Foundry's own values, verbatim, from CONFIG.Canvas.dispositionColors in core's client/config.mjs. Matching core means matching every other module that reads disposition. Disposition is a Foundry concept rather than a system one, and the dnd5e system does not override these.

Note that core's FRIENDLY is cyan, not green - the green usually associated with "friendly" is core's separate PARTY disposition (0x33BC4E), which has no token here.

Use the solid token for a mark read against a surface - a dot, an icon, a rule - and the -bg token when the surface itself is the reading, such as a button fill. All four fills share one alpha, so none is quietened relative to its neighbours.

Token Value Use
--blacksmith-disposition-friendly #43dfdf Friendly disposition mark
--blacksmith-disposition-friendly-bg rgba(67, 223, 223, 0.45) Friendly disposition fill
--blacksmith-disposition-neutral #f1d836 Neutral disposition mark
--blacksmith-disposition-neutral-bg rgba(241, 216, 54, 0.45) Neutral disposition fill
--blacksmith-disposition-hostile #e72124 Hostile disposition mark
--blacksmith-disposition-hostile-bg rgba(231, 33, 36, 0.45) Hostile disposition fill
--blacksmith-disposition-secret #a612d4 Secret disposition mark
--blacksmith-disposition-secret-bg rgba(166, 18, 212, 0.45) Secret disposition fill

Color: variant palette

Paired border and background tints for panels and tagged content. Each variant is a translucent border at 45 percent and a background wash at 12 percent of the same hue, so variants layer over any surface without a solid fill. Consume them as a pair.

Token Value Use
--blacksmith-variant-danger-border rgba(104, 41, 41, 0.45) Danger panel border
--blacksmith-variant-danger-bg rgba(104, 41, 41, 0.12) Danger panel background
--blacksmith-variant-success-border rgba(51, 92, 51, 0.45) Success panel border
--blacksmith-variant-success-bg rgba(51, 92, 51, 0.12) Success panel background
--blacksmith-variant-warning-border rgba(115, 86, 35, 0.45) Warning panel border
--blacksmith-variant-warning-bg rgba(115, 86, 35, 0.12) Warning panel background
--blacksmith-variant-info-border rgba(47, 68, 106, 0.45) Info panel border
--blacksmith-variant-info-bg rgba(47, 68, 106, 0.12) Info panel background
--blacksmith-variant-music-border rgba(160, 63, 1, 0.45) Music panel border
--blacksmith-variant-music-bg rgba(160, 63, 1, 0.12) Music panel background
--blacksmith-variant-environment-border rgba(42, 70, 62, 0.45) Environment panel border
--blacksmith-variant-environment-bg rgba(42, 70, 62, 0.12) Environment panel background
--blacksmith-variant-oneshot-border rgba(124, 133, 0, 0.45) One-shot panel border
--blacksmith-variant-oneshot-bg rgba(124, 133, 0, 0.12) One-shot panel background
--blacksmith-variant-timeline-border rgba(47, 68, 106, 0.45) Timeline panel border
--blacksmith-variant-timeline-bg rgba(47, 68, 106, 0.12) Timeline panel background

The timeline and info pairs currently hold identical values, so the two variants render indistinguishably.

Typography

Sizes are relative (em), so a component inherits the scale of whatever context it renders into.

Token Value Use
--blacksmith-font-size-xs 0.8em Fine print, badge labels
--blacksmith-font-size-sm 0.85em Secondary and meta text
--blacksmith-font-size-base 1em Body
--blacksmith-font-size-md 1.1em Emphasized body
--blacksmith-font-size-lg 1.3em Subheadings
--blacksmith-font-size-xl 1.5em Headings
--blacksmith-font-weight-light 100 Thin display text
--blacksmith-font-weight-normal 400 Body
--blacksmith-font-weight-bold 700 Emphasis
--blacksmith-font-weight-black 900 Stat values, strong display

Neutral overlays

Translucent neutrals, for edges and fills that sit on top of something rather than replacing it. The surface tokens are opaque by design, because a surface has to hide what is behind it -- which makes them the wrong choice for a border. An opaque grey outline reads as a drawn box rather than an edge.

Pick by intent rather than by number. hint should be almost subliminal; subtle should be seen.

Token Value Use
--blacksmith-border-hint rgba(255, 255, 255, 0.08) Barely-there edge on a dark surface
--blacksmith-border-subtle rgba(255, 255, 255, 0.16) Visible divider or panel edge
--blacksmith-fill-hint rgba(255, 255, 255, 0.04) Faint backing, e.g. behind transparent artwork
--blacksmith-fill-subtle rgba(255, 255, 255, 0.10) Hover lift, selected row

Border radius

Token Value Use
--blacksmith-radius-sm 3px Tight corners -- inputs, small chips
--blacksmith-radius-md 4px Default for buttons, panels, cards
--blacksmith-radius-lg 5px Larger containers
--blacksmith-radius-pill 16px Fully rounded badges and pills

Elevation

Token Value Use
--blacksmith-shadow-sm 0 1px 2px rgba(0, 0, 0, 0.3) Subtle lift -- resting elements
--blacksmith-shadow-md 0 2px 4px rgba(0, 0, 0, 0.4) Raised panels, hover states
--blacksmith-shadow-lg 0 4px 10px rgba(0, 0, 0, 0.6) Floating surfaces -- popouts, dialogs

Tokens defined outside vars.css

Component stylesheets define their own scoped custom properties for values only that component uses -- --blacksmith-card-* in the card stylesheets, --blacksmith-menubar-* in styles/menubar.css, --blacksmith-pin-* in styles/pins.css. Those are documented with their components rather than here, and they are not part of the global token contract: treat them as internal unless a component page says otherwise.

A few are written by JavaScript at runtime rather than declared in CSS, so they hold no value in a static stylesheet read. --marker-position is set per marker as the gauge part renders and read by styles/cards-parts.css to place it along the track. On canvas pins, --pin-stroke-color, --pin-stroke-px and --gm-indicator-size-px are set per-pin at scripts/pins-renderer.js:514-519.

--pin-size-px is set at scripts/pins-renderer.js:512 but is read by no stylesheet in the module: pin dimensions currently come from inline width/height written alongside it at scripts/pins-renderer.js:510-511. Setting or overriding --pin-size-px from another module therefore has no effect.