# Cometeer Design Tokens — Reconciled

This doc explains where Cometeer's design tokens live, how the three layers
relate, and how to start or regenerate a project that uses them with Claude
Code + the Figma MCP.

It's the companion to [`tokens.json`](./tokens.json) and the
"AI Kit (MCP-friendly)" page in the Claude-Kit Figma file.

---

## Three sources, one truth

| Layer | What | Where | Authority |
|---|---|---|---|
| Engineering canonical | The values that ship to cometeer.com (Tailwind-derived). Two-tier graph: raw scales → globals → theme. | [`tokens.json`](./tokens.json), mirror of [Sean's gist](https://gist.github.com/seand7565/5c2b249e02cbf642a825e8414683539f) | **Source of truth for values** |
| Figma master library | Local variables + text styles consumed by every Cometeer Figma file | [Moondust DLS (2026)](https://www.figma.com/design/ujrVRTIth6srOWLXhm0KWs/Moondust-DLS--2026-) | Source of truth for design |
| AI / MCP friendly index | Single-page semantic inventory. Frame names = token names. Global swatches live-bound to Moondust variables. | "AI Kit (MCP-friendly)" page in [Claude-Kit](https://www.figma.com/design/aWT68n9nxtNBJVX8rntJaI/Claude-Kit) | Read-only projection; auto-updates when Moondust changes |

---

## How it works

Three layers, one direction of flow:

```
        gist tokens.json                    Moondust DLS                    AI Kit page
        (engineering canonical)             (Figma master library)          (semantic projection)
        ─────────────────────              ──────────────────────          ───────────────────────
        production CSS / Tailwind          variables + text styles         flat, named swatches
        cometeer.com runtime               every designer's library        single-page MCP inventory
                                            │                               ▲
                                            │  20 globals (primary/         │
                                            │   secondary/system) bound     │  live-bound (after
                                            │   to AI Kit swatch fills      │  Moondust variable
                                            ▼                               │  collection published)
                                            ─────────────────────────────────┘
```

**Each layer serves a different audience:**

- **`tokens.json`** → for code-gen, CI, runtime CSS. JSON tree readable by any tool. Resolves references (`{colors.neutral.300}` → `#f3f5e8`).
- **Moondust DLS** → for designers working in Figma. Polished kit, light/dark example, component variants.
- **AI Kit page** → for AI tools reading Figma via MCP. Flat naming, explainer text, ⚠ flags for known mismatches between Figma and gist. **Frame names are the API** — `get_metadata` on the page returns a self-documenting inventory.

**What's live-bound vs raw hex:**

- ✅ The 20 global swatches (primary 3 / secondary 13 / system 4) on the AI Kit page have their fills **bound to Moondust variables** by key. If Moondust changes a variable, the AI Kit swatch updates automatically.
- ⚠ The Theme swatches (foreground/background/accent/warning/error/info/success/input/border/overlay — ~37 semantic tokens) use **raw hex matching the gist canonical**. They aren't variable-bound because Moondust doesn't currently model theme.* as its own variable layer — the theme mapping lives only in the gist.
- The Typography section samples are **clones of existing text nodes** from the original "Ki - v1" page. Cloning preserves textStyleId + fontName, so Agipo/BauTF render correctly. The MCP plugin runtime cannot create new text in those fonts (they aren't team-managed), so cloning is the only path.

---

## Known mismatches (Figma library ≠ engineering canonical)

The AI Kit page tags these with ⚠ badges on the affected swatches.

| Token | Figma library has | Gist canonical has | Recommendation |
|---|---|---|---|
| `theme.accent.emphasisDarker` | `#2C2B2B` (`grey.800`) | `#1A1A1A` (`grey.900`) | **Fix Figma.** Library shows same color as `theme.accent.emphasis`, which is a bug — `emphasisDarker` should be a step darker. |
| `theme.accent.emphasisVariant` | `#D8DACF` (`neutral.500`) | `#F3F5E8` (`neutral.300`) | **Needs design call.** Values are semantically very different — Figma uses muted sage, gist uses cream. Both look suspicious. |
| `theme.info.emphasis` | `#3F90E5` (`blue.500`) | `#F0F7FF` (`blue.50`) | **Fix gist.** Gist value is the lightest tint, inconsistent with `warning.emphasis`, `error.emphasis`, `success.emphasis` which all use `*.400`/`*.500`. Figma value is correct. |

---

## Starting a new project based on this design system

Drop this into Claude Code (or any LLM session with Figma MCP + repo access):

> Build a Cometeer-branded `<page or feature>`. The brand is documented in
> three places:
>
> 1. `tokens.json` at the repo root — engineering canonical values (Tailwind-derived JSON)
> 2. Moondust DLS Figma library (`ujrVRTIth6srOWLXhm0KWs`) — variables + text styles
> 3. "AI Kit (MCP-friendly)" page in the Claude-Kit Figma file (`aWT68n9nxtNBJVX8rntJaI`) — flat semantic inventory. Use `get_metadata` on the page to enumerate every token; use `get_screenshot` for visual lookups.
>
> Constraints:
> - Use named tokens, never raw hex (`primary.cream` not `#F3F5E8`)
> - For semantic intent (buttons, cards, alerts) use `theme.*` tokens
> - For brand palette (backgrounds, hero accents) use `primary.*` or `secondary.*`
> - Typography uses Agipo for display + headings, BauTF for body. Family names are case-sensitive: `Agipo`, `BauTF-Regular`, `BauTF-Medium`.
> - Read `CLAUDE-KIT-TOKENS.md` before starting for the 3 known Figma↔gist mismatches.

**Starter checklist** when bootstrapping the project's `:root` CSS:
1. Copy color tokens from `tokens.json` → CSS custom properties (use lowercase + dashes: `--primary-cream`, `--theme-bg-surface`).
2. `@font-face` declare Agipo + BauTF (use the live cometeer.com /\_fonts/cometeer.css if hot-linking is OK; otherwise drop the files in `/fonts/`).
3. Apply `font-family: 'BauTF', system-ui, sans-serif` to body; reserve Agipo for `h1`–`h6` and display text.
4. Set body background to `--theme-bg-surface` (= `primary.cream`) for the default Cometeer look.

---

## How to update / regenerate the AI Kit from Moondust

The AI Kit page is a derived projection — never edit it by hand. Always regenerate when something upstream changes.

**When to regenerate:**
- Moondust adds, removes, or renames a variable
- A theme token value changes in `tokens.json` (the gist)
- One of the 3 known mismatches gets resolved
- Token naming convention drifts and needs realignment

**How to regenerate:**

In a Claude Code session with Figma MCP available, run:

```
Rebuild the "AI Kit (MCP-friendly)" page in the Claude-Kit Figma file
(fileKey aWT68n9nxtNBJVX8rntJaI) using scripts/figma/build-ai-kit.js.

Steps:
1. Read scripts/figma/build-ai-kit.js to get the token data + binding map.
2. Read tokens.json for any updated values.
3. In Moondust DLS (ujrVRTIth6srOWLXhm0KWs), re-query the variable catalog
   (name → key) so the binding map stays current if Moondust changed.
4. Delete the existing "AI Kit (MCP-friendly)" page on Claude-Kit.
5. Rebuild in 4 use_figma calls:
   - Page title + Colors section (Globals + Theme grids, w/ ⚠ badges)
   - Layout fix pass (wrap heights)
   - Typography section (clone Agipo/BauTF samples from "Ki - v1")
   - Brand Assets + Templates index + top-level Index frame
6. Re-bind every Global swatch to its Moondust variable via importVariableByKeyAsync.
7. Take a verifying screenshot and report any swatches that failed to bind.
```

The original `Ki - v1` page must remain untouched — it's the source of the cloned brand-font text nodes.

**Manual update of tokens.json:**

```bash
# From the repo root
curl -sSL https://gist.githubusercontent.com/seand7565/5c2b249e02cbf642a825e8414683539f/raw/ > tokens.json
git diff tokens.json  # review what changed
```

**Publishing Moondust changes:**

If you update Moondust variables, remember to re-publish the library (Assets panel → Publish library → check Variable collection). Subscribed files won't see your edits until you publish.

---

## Three-tier color graph

Cometeer uses a clear hierarchy:

```
Raw scales       →  Globals                   →  Theme (semantic intent)
─────────────────────────────────────────────────────────────────────────
colors.neutral.300  primary.cream                theme.background.surface
                                                 theme.background.canvas
                                                 theme.input.background
                                                 theme.foreground.onEmphasis

colors.grey.800     primary.black                theme.foreground.default
                                                 theme.accent.emphasis
                                                 theme.warning.foreground
                                                 theme.error.foreground
                                                 theme.info.foreground
                                                 theme.success.foreground

colors.gold.400     primary.frostedGold          theme.accent.default
```

**Pick the right tier for the job**:
- A color picker, a swatch grid, a brand reference → use `globals.*` (primary/secondary/system)
- A button, a card, a status alert → use `theme.*` (semantic intent)
- A literal hex in CSS → avoid; always reference a token name

---

## Typography

All ramps are in Moondust DLS as Figma text styles. Same names render in the AI Kit page.

| Group | Tokens | Family · Letter spacing |
|---|---|---|
| Display | `Display/Title/{Desktop\|Mobile}`, `Display/Subtitle/{Desktop\|Mobile}` | Agipo (titles) / BauTF-Medium (subtitles) · -2% (titles) / 0 (subs) |
| Headings — Desktop | `Heading/{1..6}/Desktop` | Agipo Bold Condensed · -2% · 72 / 48 / 32 / 24 / 18 / 16 |
| Headings — Mobile | `Heading/{1..6}/Mobile` | Agipo Bold Condensed · -2% · 48 / 32 / 24 / 20 / 18 / 16 |
| Body | `Body/{Large\|Regular\|Small\|Extra Small}/{Normal\|Bold\|Italic}` | BauTF-Regular (Normal/Italic) / BauTF-Medium (Bold) · 0 |
| Caption | `Caption/{Small\|Regular\|Large}` | BauTF-Medium · 20% letter spacing |
| Hyperlink | `Hyperlink/{Default\|Hover\|StandAlone}/{Light\|Dark}` | BauTF-Medium · 14 / 20 |

Note: a few tokens share specs across desktop and mobile (e.g.
`Heading/1/Mobile` == `Heading/2/Desktop`). They're listed separately
because they're applied in different contexts.

---

## How to look up a token

| You want to... | Do this |
|---|---|
| Find the hex for `primary.cream` | Read [`tokens.json`](./tokens.json) → `colors.primary.cream` → resolves `{colors.neutral.300}` → `#f3f5e8` |
| See every semantic theme token visually | Open AI Kit page → section "01 — Colors" |
| Inventory all tokens via AI | `get_metadata` on AI Kit page; every frame name is a token |
| Apply a brand font in code | Family names verbatim: `Agipo` (Bold Condensed only), `BauTF-Regular`, `BauTF-Medium`. CSS strings in `tokens.fonts`. |

---

## Naming conventions, by source

The same tokens appear with slightly different casing across the sources:

| Concept | tokens.json (canonical) | Moondust variable | AI Kit frame |
|---|---|---|---|
| Cream primary | `colors.primary.cream` | `Primary/Cream` | `primary/cream` |
| Foreground default | `colors.theme.foreground.default` | (not in Moondust variables) | `theme/foreground/default` |
| Heading 1 desktop | `typography.h1` | text style `Heading/1/Desktop` | `Heading/1/Desktop` |

When reconciling: **tokens.json wins on value**; AI Kit frame name is the
human-and-AI-readable canonical name (lowercase + slashes for colors,
Title Case + slashes for typography).

---

## What's intentionally not in scope here

- `colors.profile.*`, `colors.gradient.*`, `colors.roaster.*`, `colors.coffee.*`
  from `tokens.json` are domain-specific (coffee mood profiles, roaster
  brand colors) and aren't part of the AI Kit. They're available in code
  via `tokens.json` if you need them.
- `breakpoints`, `spacing.cometeer`, `spacing.navbarHeight`, `scale` —
  layout primitives that live in the gist but don't have Figma variable
  counterparts. Reference them from `tokens.json` directly.

---

## Historical note: the variable publish step

For the first iteration of this AI Kit, swatches used raw hex because
Moondust's variable collection had `remote: false` (never published).
Toan published the collection (Assets panel → Publish library → check
"Variable collection") on May 13, 2026, which unlocked
`importVariableByKeyAsync` and let the AI Kit's Global swatches bind live.
If you ever lose the live bindings, that's the first place to check.
