# How Hallmark Uses Catalog Themes for UI Design: A Complete Technical Breakdown

> Explore Hallmark's UI design technical breakdown Discover how catalog themes activate visual systems using CSS custom properties and data-theme attributes for effortless theming.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: deep-dive
- Published: 2026-08-06

---

**Hallmark powers its UI through a catalog of 20 pre-defined themes, each encoding a complete visual system via CSS custom properties that activate with a single `data-theme` attribute.**

The Hallmark repository implements a **theme-driven design engine** that lets you swap entire visual languages—palette, typography, spacing, motion, and component defaults—without touching component code. This article explains how the catalog works, how themes are selected and rotated, and how they shape every layer of the UI.

## Theme Definition and Structure

Hallmark's catalog lives in two locations: machine-readable CSS variables and human-readable design specifications.

### CSS Custom Properties in tokens.css

All 20 themes are defined in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) as `[data-theme="…"]` blocks. Each block declares the full set of CSS variables that downstream components consume:

```css
[data-theme="hum"] {
  /* Paper band */
  --color-paper: #f7f3ef;
  --color-paper-secondary: #efe9e2;
  
  /* Accent hue */
  --color-accent: #e85d4e;
  --color-accent-secondary: #f4a261;
  
  /* Display style */
  --font-display: 'Plus Jakarta Sans', sans-serif;
  --font-body: 'Plus Jakarta Sans', sans-serif;
  
  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-short: 150ms;
  
  /* Component defaults */
  --radius-pill: 9999px;
  --radius-card: 24px;
}

```

The file encodes **three diversification axes** for every theme: paper band, display style, and accent hue. These axes drive the rotation logic that prevents visual repetition across builds.

### Theme Documentation in Markdown

Individual theme specifications—design intent, reference palettes, motion rules, signature moves—are stored as Markdown files under `skills/hallmark/references/themes/`. The *Hum* theme (the only "playful" theme in the catalog) is documented in [`hum.md`](https://github.com/Nutlope/hallmark/blob/main/hum.md), covering typography (`Plus Jakarta Sans` for display), multi-accent section bands, and character moments that define its distinctive voice.

## Theme Selection Workflow

When Hallmark runs a design build, it follows the **Theme-diversification rule** defined in [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md):

1. **Default route** — Select one of the 20 catalog themes.
2. **Rotation** — Ensure successive builds differ on at least one of the three axes (paper, display, accent). The rotation is *theme-route-blind*, applying equally to catalog and custom runs.
3. **Signal-driven custom fork** — Switch to a custom theme only if the brief signals a multi-attribute aesthetic or structural need, as described in [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md). For ordinary briefs, the catalog operates silently without user intervention.

The selected theme's CSS variables are injected with a comment stamp:

```css
/* Hallmark · macrostructure: marquee-hero · theme: hum */

```

This stamp allows Hallmark to read the previous run and enforce diversification on the next build.

## How Themes Shape UI Components

Themes control five visual layers through CSS custom properties:

| Layer | Example Variables | Effect |
|-------|-------------------|--------|
| **Palette** | `--color-paper`, `--color-accent`, `--color-ink` | Background, foreground, interactive colors |
| **Typography** | `--font-display`, `--font-body` | Typeface swaps (e.g., Hum uses `Plus Jakarta Sans`) |
| **Component defaults** | `--radius-card`, `--shadow-elevated` | Shape and depth |
| **Motion** | `--ease-out`, `--dur-short` | Animation curves and timing |
| **Signature moves** | Documented in theme MD | High-level interaction patterns (Hum's button system, multi-accent bands) |

Because components reference these variables directly—`var(--color-accent)`, `var(--font-display)`—they remain **theme-agnostic**. No conditional logic, no theme-specific branches.

```css
/* A button that works in any theme */
.btn {
  background: var(--color-accent);
  color: var(--color-ink);
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  transition: transform var(--ease-out) var(--dur-short);
}

```

## Runtime Theme Activation

Applying a catalog theme requires only a single HTML attribute:

```html
<!doctype html>
<html data-theme="hum">
<head>
  <link rel="stylesheet" href="site/css/tokens.css">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
  <button class="btn btn--soft btn--pear">Get Started</button>
</body>
</html>

```

The browser matches `[data-theme="hum"]` in [`tokens.css`](https://github.com/Nutlope/hallmark/blob/main/tokens.css), and all components inherit the correct visual language. Switching to `data-theme="cobalt"` requires zero code changes.

## Theme-Aware Macrostructures

Each theme declares **macrostructure affinities** in its Markdown spec. *Hum*, for example, prefers Marquee Hero, Bento Grid, and Stat-Led layouts. When Hallmark selects a macrostructure from [`skills/hallmark/references/macrostructures.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/macrostructures.md), it cross-checks the active theme's affinity list. Mismatches fall back to neutral macrostructures, ensuring layout and visual language remain coherent.

## Implementing Theme Rotation

The diversification rule prevents visual fatigue. Here's the selection pseudo-code that enforces it:

```javascript
function pickTheme(previousTheme) {
  const catalog = [
    'specimen','midnight','brutal','garden','atelier','newsprint',
    'terminal','manifesto','almanac','sport','studio','riso',
    'bloom','coral','cobalt','aurora','editorial','carnival',
    'lumen','hum'
  ];

  const prevAxes = getAxes(previousTheme); // reads from tokens.css

  const candidates = catalog.filter(t => {
    const axes = getAxes(t);
    return !(axes.paper === prevAxes.paper &&
             axes.display === prevAxes.display &&
             axes.accent === prevAxes.accent);
  });

  return candidates[Math.floor(Math.random() * candidates.length)];
}

```

The `getAxes` helper extracts paper, display, and accent values to guarantee at least one axis differs from the previous build.

## Key Files in the Theme System

| File | Purpose |
|------|---------|
| [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) | CSS custom properties for all 20 themes; the runtime theme engine |
| `skills/hallmark/references/themes/<theme>.md` | Design specs, signature moves, macrostructure affinities |
| [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) | Theme-diversification rule, route logic, stamping format |
| [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md) | Custom theme branch and fallback behavior |
| [`skills/hallmark/references/macrostructures.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/macrostructures.md) | Layout index with theme affinity/rejection lists |

## Summary

- **Hallmark's catalog themes** encode complete visual systems through CSS custom properties in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css).
- **Activation** happens via `data-theme` attribute—no JavaScript, no component changes.
- **Diversification** is enforced across builds using three axes (paper, display, accent) recorded in theme stamps.
- **Components stay theme-agnostic** by referencing variables like `--color-accent` and `--font-display`.
- **Macrostructure selection** respects theme affinities to maintain visual coherence.

## Frequently Asked Questions

### How many themes are in Hallmark's catalog?

The catalog contains **20 pre-defined themes**: specimen, midnight, brutal, garden, atelier, newsprint, terminal, manifesto, almanac, sport, studio, riso, bloom, coral, cobalt, aurora, editorial, carnival, lumen, and hum. Each lives in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) with full CSS variable definitions.

### Can I create a custom theme instead of using the catalog?

Yes, but only when the **design brief signals a multi-attribute aesthetic or structural need**. Hallmark defaults to catalog themes for ordinary briefs and switches to custom themes via the workflow described in [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md). The catalog is designed to be "silent" and sufficient for most use cases.

### What happens if I use the same theme for multiple builds?

Hallmark's **rotation rule** prevents this. The system reads the previous build's theme stamp, extracts its three axes (paper, display, accent), and filters the catalog to exclude themes sharing all three. Only candidates that differ on at least one axis are eligible for selection.

### Do components need to know which theme is active?

No. Components reference CSS custom properties (`var(--color-accent)`, `var(--radius-card)`) without any theme-specific logic. This **decouples implementation from styling**—the same button component renders correctly for Hum's playful rounded style or Terminal's monospace aesthetic.