# How Hallmark Handles the Diversification Rule in UI Generation: A Deep Dive into Theme Rotation

> Discover how Hallmark manages UI generation with its three-axis rotation system. Ensure design diversification and understand theme rotation for unique user experiences.

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

---

**Hallmark enforces the diversification rule through a three-axis rotation system that ensures each generated page differs from the previous output on at least one of paper-band, display-style, or accent-hue, while flipping to "must-share" mode when a [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) file locks the project to a consistent visual system.**

The **diversification rule** is the core mechanism that prevents Hallmark from generating repetitive UIs. As implemented in `Nutlope/hallmark`, this rule operates as a smart theme-rotation engine that reads project memory, compares design axes, and either enforces variety or consistency depending on project context. Understanding this rule is essential for anyone customizing Hallmark's output or debugging unexpected theme selections.

## How the Diversification Rule Works in Hallmark

Hallmark's diversification system follows a **seven-step pipeline** that executes after any existing design memory is loaded. The entire process is documented in [[`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md).

### Step 1: Check for Project Memory ([`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md))

Hallmark first looks for a [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) file at the project root. If present, the diversification rule **inverts completely**: consecutive pages must **share** the same theme system rather than differ. This "app mode" treats the repository as a single cohesive application requiring visual consistency.

### Step 2: Parse the Last Stamp and Log

When no [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) exists, Hallmark reads the most recent generation record from two sources:

- The **CSS/HTML stamp comment** embedded in generated files (e.g., `/* Hallmark · macrostructure: … */`)
- The **[`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json)** file containing structured history

From these, Hallmark extracts the **three diversification axes** of the previous run:

| Axis | Description |
|------|-------------|
| **paper-band** | The background/surface color system (warm, cool, neutral, etc.) |
| **display-style** | The structural layout approach (grid, editorial, immersive, etc.) |
| **accent-hue** | The primary accent color family and saturation strategy |

### Step 3: Select a Different Theme

Hallmark picks from approximately **20 catalog themes** or generates a **custom theme** when the brief signals creative intent. The chosen theme must differ from the previous one on **at least one** of the three axes. This "one-axis minimum" rule prevents identical consecutive outputs while allowing deliberate similarities.

### Step 4: Apply Cross-Route Diversification

The diversification check is **theme-route-blind**. A custom theme following a catalog theme (or another custom theme) must still satisfy the axis-difference requirement. Custom themes explicitly declare their three axes in their metadata so the same validation applies universally. See [[`custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/custom-theme.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md#254) for the declaration schema.

### Step 5-7: Handle Edge Cases and Persist State

- **App mode override**: When [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) is present, skip catalog rotation and enforce shared axes across all pages ([[`redesign.md`](https://github.com/Nutlope/hallmark/blob/main/redesign.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/verbs/redesign.md#222))
- **Studied-DNA suspension**: If a prior "study" diagnosis supplies concrete DNA (paper, accent, type, macrostructure), diversification is suspended and that exact system is reused ([[`SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/SKILL.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md#337))
- **Logging**: After generation, Hallmark writes a stamp comment and appends to [`/.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main//.hallmark/log.json) for future comparison ([[`SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/SKILL.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md#461))

## The Three Diversification Axes Explained

Each theme in the catalog defines its position on three axes, documented in `skills/hallmark/references/themes/*.md`.

### Axis Definitions

- **paper-band**: Controls the chromatic temperature of backgrounds—options typically include `warm`, `cool`, `neutral`, `oxide`, or `midnight`
- **display-style**: Determines the macro-layout philosophy—values like `editorial`, `immersive`, `systematic`, or `brutalist`
- **accent-hue**: Specifies the primary action color and its rotation behavior—some themes fix this, others rotate among a drop set

### Rotation Window and Drop-Hue Logic

Certain themes implement **extended rotation** beyond the basic rule. For example, the *Carnival* theme defines a "drop" hue that rotates among five possible values, with consecutive builds prohibited from reusing any drop seen in the last **3 entries**. This creates a longer memory window than the default single-step comparison. See [`themes/carnival.md`](https://github.com/Nutlope/hallmark/blob/main/themes/carnival.md) and [`themes/lumen.md`](https://github.com/Nutlope/hallmark/blob/main/themes/lumen.md) for concrete axis declarations.

## Core Diversification Logic in Code

The following pseudo-code illustrates the validation pattern Hallmark uses internally. The real implementation resides in the skill's JavaScript/TypeScript modules and mirrors this structure exactly:

```javascript
// Diversification rule validation as implemented in Hallmark
import { readFileSync } from 'fs';
import path from 'path';

// 1️⃣ Load the previous generation's axes from log.json
function getPrevAxes(projectRoot) {
  const logPath = path.join(projectRoot, '.hallmark', 'log.json');
  if (!fs.existsSync(logPath)) return null;
  const log = JSON.parse(readFileSync(logPath, 'utf8'));
  const last = log[log.length - 1];
  return {
    paperBand: last.axes.paperBand,
    displayStyle: last.axes.displayStyle,
    accentHue: last.axes.accentHue,
  };
}

// 2️⃣ Extract axes from a catalog theme's markdown file
function getThemeAxes(themeName) {
  const themeFile = path.join(
    __dirname, 'skills', 'hallmark', 'references', 'themes', `${themeName}.md`
  );
  const content = readFileSync(themeFile, 'utf8');
  // Theme files contain YAML frontmatter with the three axes
  const yaml = content.match(/```yaml([\s\S]*?)```/)[1];
  return yamlParser(yaml);
}

// 3️⃣ Core diversification test: must differ on at least one axis
function passesDiversification(prev, candidate) {
  if (!prev) return true; // First run: any theme is valid
  return (
    prev.paperBand !== candidate.paperBand ||
    prev.displayStyle !== candidate.displayStyle ||
    prev.accentHue !== candidate.accentHue
  );
}

// 4️⃣ Theme selection with diversification enforcement
function pickTheme(projectRoot, catalogThemes) {
  const prev = getPrevAxes(projectRoot);
  for (const theme of catalogThemes) {
    const axes = getThemeAxes(theme);
    if (passesDiversification(prev, axes)) return theme;
  }
  throw new Error('No theme satisfies diversification – enlarge rotation window');
}

```

The production code adds two critical extensions: **inversion logic** for [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) presence (requiring `passesConsistency` instead of `passesDiversification`) and **custom-theme axis parsing** from embedded YAML declarations.

## When the Diversification Rule Inverts to "Must-Share"

The most important edge case in Hallmark's diversification rule is the **app-mode inversion**. Documented in [[`redesign.md`](https://github.com/Nutlope/hallmark/blob/main/redesign.md)](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/verbs/redesign.md#222), this behavior triggers when:

1. A [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) file exists at project root
2. Hallmark is invoked for a multi-page application (not a one-off landing page)
3. The project explicitly requests **consistency** across routes

In this mode, the rule flips from "must differ on ≥1 axis" to "must match on all 3 axes." Catalog rotation is skipped entirely, and Hallmark instead:

- Reads the locked theme from [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md)
- Validates that all generated pages conform to that theme's axes
- Ignores [`log.json`](https://github.com/Nutlope/hallmark/blob/main/log.json) diversity constraints

This inversion ensures that application UIs feel cohesive rather than disjointed, while still allowing the diversification rule to operate normally for one-off or exploration projects.

## Key Source Files for the Diversification Rule

| File | Purpose |
|------|---------|
| [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) | Central specification of the diversification rule, rotation window, and interaction with project memory |
| [`skills/hallmark/references/verbs/redesign.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/verbs/redesign.md) | Inversion logic for multi-page app consistency |
| [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md) | Axis declaration schema for non-catalog themes |
| `skills/hallmark/references/themes/*.md` | Per-theme axis definitions and drop-hue rotation rules |
| [`skills/hallmark/references/design-md.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/design-md.md) | Documentation of the "design-first" override mode |
| [`site/_tests/README.md`](https://github.com/Nutlope/hallmark/blob/main/site/_tests/README.md) | Test expectations and planned improvements for diversification |
| `site/_tests/verbs/redesign/` | Concrete test cases verifying rule behavior |

## Summary

- Hallmark's **diversification rule** operates on **three axes**: paper-band, display-style, and accent-hue
- Consecutive generations must differ on **at least one axis** unless [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) is present, which **inverts the rule** to require consistency
- The rule is **theme-route-blind**: both catalog and custom themes participate in the same validation
- **Log persistence** in [`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json) and CSS stamp comments enable cross-run memory
- **Studied-DNA runs** suspend diversification entirely when a precise visual system is diagnosed

## Frequently Asked Questions

### What happens if no theme satisfies the diversification rule?

Hallmark throws an explicit error: `'No theme satisfies diversification – enlarge rotation window'`. In practice, this rarely occurs because the catalog contains ~20 themes with varied axis combinations. If encountered, the solution is to either expand the acceptable theme set or reduce the rotation window (checking fewer historical entries).

### How does the diversification rule affect custom themes?

Custom themes must **explicitly declare** their three axes (paper, display, accent) in their YAML metadata. Once declared, they enter the same diversification pool as catalog themes. A custom theme following any other theme—catalog or custom—must still differ on at least one axis.

### Can I disable the diversification rule for a specific project?

Yes. Create a [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) file at your project root. This triggers **app-mode inversion**, which forces consistency across all generated pages. Alternatively, supply a **studied-DNA diagnosis** with concrete paper, accent, type, and macrostructure values; Hallmark will suspend diversification and reuse that exact system.

### Why does Hallmark look at 3-5 log entries instead of just the last one?

The **rotation window** prevents rapid cycling between two similar themes. By examining 3-5 historical entries, Hallmark ensures broader palette exploration over time while still allowing deliberate returns to previously used aesthetics after sufficient variety has been generated.