# How Hallmark Detects Existing Design Systems in Its Pre‑Flight Scan

> Discover how Hallmark's pre-flight scan detects existing design systems by analyzing package.json, Tailwind configs, CSS, and design.md files for fonts, palettes, and more.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: how-to-guide
- Published: 2026-08-05

---

**Hallmark runs a six‑step pre‑flight scan that analyzes [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json), Tailwind configs, CSS custom properties, and optional [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) files to detect existing fonts, palettes, spacing scales, motion libraries, and frameworks before generating any code.**

The scan is the first operation in every Hallmark session. It runs automatically when it finds [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json), `tailwind.config.*`, [`index.html`](https://github.com/Nutlope/hallmark/blob/main/index.html), or any CSS files—no user prompt required. Results are cached in [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) for reuse across runs unless source files change [`skills/hallmark/SKILL.md#L45-L50`][`#77-L81`].

## How the Pre‑Flight Scan Works

### Automatic Trigger and Caching

Hallmark starts the scan without interaction if recognizable project files exist. The findings land in [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json). Subsequent runs skip re‑analysis unless:

- The user explicitly requests a refresh, or  
- Detected source files have newer modification times than the cache

This caching strategy keeps CLI startup fast while respecting codebase evolution [`skills/hallmark/SKILL.md#L77-L81`][`#81-L82`].

### Six Signal Sources in Priority Order

The scan evaluates signals sequentially. A higher‑priority finding can override lower‑priority ones.

1. **[`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) (or [`DESIGN.md`](https://github.com/Nutlope/hallmark/blob/main/DESIGN.md))** – treated as a **locked design system** that short‑circuits all other detection [`skills/hallmark/SKILL.md#L53-L55`][`#85-L87`]

2. **Font stack** – detected via:

   - `next/font`, `@fontsource/*`, `expo-google-fonts`, or `geist` in [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json)
   - `<link rel="stylesheet">` tags in HTML
   - `tailwind.config.{js,ts}` `theme.extend.fontFamily`
   - `@import` statements in stylesheets [`skills/hallmark/SKILL.md#L54-L56`]

3. **Color palette** – extracted from:

   - OKLCH, HSL, or hex values in `:root` CSS blocks
   - `tailwind.config` `theme.extend.colors`
   - DTCG‑style token files: [`tokens.json`](https://github.com/Nutlope/hallmark/blob/main/tokens.json), `design-tokens.{json,yaml}` [`skills/hallmark/SKILL.md#L55-L56`]

4. **Micro‑interaction stance** – `framer-motion`, `gsap`, `motion`, `lenis`, `lottie-react`, `@react-spring/*`, or `auto-animate` in [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) signals "motion‑on"; absence means "motion‑cut" [`skills/hallmark/SKILL.md#L56-L57`]

5. **Spacing scale** – sourced from Tailwind's `theme.extend.spacing`, CSS custom properties named `--space-*`, or explicit 4‑pt/8‑pt scale definitions [`skills/hallmark/SKILL.md#L57-L58`]

6. **Framework** – identified by dependency names:

   - **Next.js** (`next`)
   - **Astro** (`astro`)
   - **Vue** (`vue`)
   - **Svelte / SvelteKit** (`svelte`, `@sveltejs/kit`)
   - **Remix** (`@remix-run/*`)
   - **Vanilla HTML** (fallback when none match) [`skills/hallmark/SKILL.md#L58-L59`]

## What the Scan Reports

On first run, Hallmark logs findings in a structured summary:

```text
Pre‑flight findings:
· Font stack: Geist + Geist Mono (next/font, package.json L23)
· Palette: OKLCH custom properties (app/globals.css :root)
· Motion: framer‑motion 11 installed (package.json L41)
· Spacing: Tailwind extend.spacing (4‑pt scale, tailwind.config.ts L18)
· Framework: Next.js 15 (app router)

Hallmark will preserve: font stack, palette, spacing scale.
Hallmark will introduce: macrostructure, microinteraction discipline,
slop‑test gates, hero enrichment recipe.

```

This transparency lets developers audit exactly what Hallmark detected and what it will preserve versus introduce.

## Edge Cases and Conflict Handling

### Locked Design System via [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md)

When [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) or [`DESIGN.md`](https://github.com/Nutlope/hallmark/blob/main/DESIGN.md) exists in the project root, Hallmark treats it as authoritative. All font, color, spacing, and motion decisions defer to this file's definitions. No further signal detection runs for those categories [`skills/hallmark/SKILL.md#L85-L87`].

### No Detectable Signals

For empty repositories without recognizable files, Hallmark proceeds with a full default stack and notes the absence of pre‑flight data in its output [`skills/hallmark/SKILL.md#L87-L89`].

### Conflicting Signals

If the scan finds contradictory evidence—such as a font library installed via [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) but a hard‑coded font stack in CSS—Hallmark flags the conflict and prompts the user for clarification rather than making an arbitrary override [`skills/hallmark/SKILL.md#L88-L89`].

## Practical Code Examples

These snippets mirror Hallmark's internal logic for developers building custom tooling or debugging detection behavior.

### Reading the Cached Preflight JSON

```javascript
import { readFileSync, existsSync } from "fs";
import path from "path";

const preflightPath = path.resolve(".hallmark", "preflight.json");

if (existsSync(preflightPath)) {
  const cache = JSON.parse(readFileSync(preflightPath, "utf8"));
  console.log("Using cached pre‑flight:", cache);
}

```

### Extracting Tailwind Spacing Scale

```javascript
import fs from "fs";

function getTailwindSpacing() {
  const cfgPath = fs.existsSync("tailwind.config.js")
    ? "tailwind.config.js"
    : fs.existsSync("tailwind.config.ts")
    ? "tailwind.config.ts"
    : null;
  
  if (!cfgPath) return null;

  const cfg = require(`./${cfgPath}`);
  return cfg.theme?.extend?.spacing || null;
}

console.log("Tailwind spacing scale:", getTailwindSpacing());

```

### Detecting Framework from [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json)

```javascript
import { readFileSync } from "fs";

const pkg = JSON.parse(readFileSync("package.json", "utf8"));
const deps = { ...pkg.dependencies, ...pkg.devDependencies };

const framework = Object.keys(deps).find((name) =>
  ["next", "astro", "vue", "svelte", "@sveltejs/kit", "@remix-run"].some(
    (kw) => name.includes(kw)
  )
);

console.log("Detected framework:", framework ?? "vanilla HTML");

```

## Key Files in Hallmark's Detection Pipeline

| File | Purpose |
|:---|:---|
| [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) | Master specification defining pre‑flight steps, signal priority, and edge‑case handling |
| [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) | Cached scan results; reused across CLI runs |
| [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) | Source for framework, font libraries, and motion library detection |
| `tailwind.config.{js,ts}` | Source for spacing scales and extended color palettes |
| [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) / [`DESIGN.md`](https://github.com/Nutlope/hallmark/blob/main/DESIGN.md) | Optional locked design system that supersedes all automatic detection |

## Summary

- **Hallmark's pre‑flight scan** runs automatically on [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json), Tailwind configs, HTML, or CSS presence—no user interaction needed.
- **Six prioritized signals** detect fonts, palettes, motion stance, spacing, and framework; [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) overrides all if present.
- **Caching in [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json)** speeds subsequent runs while respecting file modification times.
- **Conflict detection** prompts users when signals contradict, preventing accidental overwrites of existing design systems.

## Frequently Asked Questions

### What happens if Hallmark finds conflicting design signals?

Hallmark flags the conflict in its output and asks the user for clarification rather than guessing. For example, if [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) includes `@fontsource/inter` but [`globals.css`](https://github.com/Nutlope/hallmark/blob/main/globals.css) hard‑codes a different font stack, the CLI pauses to request direction.

### Can I force Hallmark to ignore my existing design system?

Yes—remove or rename [`design.md`](https://github.com/Nutlope/hallmark/blob/main/design.md) if present, then run Hallmark with a flag or prompt requesting a fresh scan. Without the locked file, Hallmark re‑evaluates all six signal sources and may propose its own defaults.

### Does the pre‑flight scan slow down CI/CD pipelines?

No. The scan is lightweight and results are cached in [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json). Subsequent runs read this cache unless source files change, making the detection step negligible in automated environments.