# hex-ui-platform
> Production-ready React component system + LLM-native design tooling.
## packages
- @hex-core/components (1.4.0): 59 Radix + CVA components incl. layout primitives + ColorPicker, Tailwind v4 entry. https://hex-ui.dev/docs/packages/components
- @hex-core/tokens (1.2.2): HSL design tokens, theme presets, and CSS/Tailwind transformers. https://hex-ui.dev/docs/packages/tokens
- @hex-core/themes (0.1.1): Premium theme catalog — midnight, ember, and future presets. https://hex-ui.dev/docs/packages/themes
- @hex-core/registry (0.3.1): Zod schemas + TypeScript types for components, themes, and recipes. https://hex-ui.dev/docs/packages/registry
- @hex-core/payload (0.2.1): Pure-function builders for the canonical LLM context markdown. https://hex-ui.dev/docs/packages/payload
- @hex-core/cli (0.2.3): The hex binary — init, add, list, theme set, recipe add. https://hex-ui.dev/docs/packages/cli
- @hex-core/mcp (0.4.2): Stdio MCP server: emit_app_context, emit_figma_tokens, resolve_spec, and more. https://hex-ui.dev/docs/packages/mcp
- @hex-core/preview (0.2.0): DemoSurface wrapper for showcasing components on flat-white pages. https://hex-ui.dev/docs/packages/preview
## live tools
- /studio — interactive theme editor that emits canonical LLM payload
- /studio/copy — text/plain canonical app-context for any theme (incl. ## Packages section)
- /docs/packages — full per-package mini-guides for human readers
- @hex-core/mcp — stdio MCP server: emit_app_context, emit_figma_tokens, resolve_spec, …
## see also
- https://hex-ui.dev/llms-full.txt — full mini-guide bundle (one fetch ingests the whole stack)
---
# Per-package guides
# @hex-core/components
> 59 Radix + CVA components incl. layout primitives + ColorPicker, Tailwind v4 entry.
Version: `1.4.0`
Install: `pnpm add @hex-core/components`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/components
## What it does
`@hex-core/components` is the runtime React component library. It ships 59 Radix + CVA components, including six layout primitives and an HSL ColorPicker.
The package owns the visual contract. `@hex-core/tokens` decides what colors mean; `@hex-core/components` decides how a Button looks when it's `variant="outline" size="sm"`. Consumers wire the two together via Tailwind v4's `@theme` block in their globals.css.
In Tailwind v4, utility classes inside published bundles are not auto-scanned. A `tailwind.css` entry (since 1.2.1) ships that adds the right `@source` directive — one `@import "@hex-core/components/tailwind.css"` and you're done.
## Public API
### Button
```ts
import { Button, type ButtonProps } from "@hex-core/components";
interface ButtonProps {
variant?: "default" | "outline" | "secondary" | "ghost" | "link" | "destructive";
size?: "default" | "sm" | "lg" | "icon";
asChild?: boolean;
}
```
Polymorphic button with six variants and four sizes. `asChild` swaps the rendered element for the child component while preserving the variant classes — useful for wrapping `` or anchor tags without losing the visual contract.
```tsx
import { Button } from "@hex-core/components";
export function ConfirmRow() {
return (
);
}
```
### Stack / Cluster / Grid / Container / Spacer / AspectRatio
```ts
import {
Stack, Cluster, Grid, Container, Spacer, AspectRatio,
} from "@hex-core/components";
interface StackProps {
gap?: "0" | "1" | "2" | "3" | "4" | "6" | "8";
align?: "start" | "center" | "end" | "stretch";
justify?: "start" | "center" | "end" | "between";
asChild?: boolean;
}
```
Layout primitives shipped in 1.2.1. Stack = vertical flex; Cluster = horizontal flex with wrap; Grid = 1/2/3/4/6 columns or `auto-fit` with `minColWidth`; Container = max-width + padding; Spacer = declarative whitespace; AspectRatio = Radix re-export. They all share the same `gap` scale (drawn from `--space-*` tokens), so mixing them never produces uneven seams.
```tsx
Account
```
### ColorPicker
```ts
import { ColorPicker, type ColorPickerProps } from "@hex-core/components";
interface ColorPickerProps {
mode: "hsl";
value: string; // "240 5.9% 10%" — same triplet @hex-core/tokens emits
onChange: (next: string) => void;
}
```
HSL color picker. Round-trips losslessly through the same `% %` triplet `@hex-core/tokens` exports, so binding it to a token override doesn't introduce float drift.
```tsx
import { ColorPicker } from "@hex-core/components";
import { useState } from "react";
export function PrimaryEditor() {
const [hsl, setHsl] = useState("240 5.9% 10%");
return ;
}
```
### Color utilities
```ts
import {
parseHslTriplet, formatHslTriplet,
hslToRgb, rgbToHsl,
hslTripletToHex, hexToHslTriplet,
type HslTriplet, type RgbColor,
} from "@hex-core/components";
```
Pure conversions between the four canonical color formats the design system speaks: HSL triplets, HSL objects, RGB objects, and hex. Use these instead of hand-rolled regex — they handle the percent-vs-decimal lightness format that bites every consumer.
```tsx
import { hexToHslTriplet, hslTripletToHex } from "@hex-core/components";
const triplet = hexToHslTriplet("#FF5733"); // "11 100% 60%"
const hex = hslTripletToHex("240 5.9% 10%"); // "#18181B"
```
### tailwind.css entry
```ts
/* @hex-core/components/tailwind.css — exported entry, not a TS API */
@source "./dist/*.js";
```
Single-line replacement for the manual `@source "../../node_modules/@hex-core/components/dist/*.js"` Tailwind v4 directive. Required for utility classes inside the published bundle to compile in your app. Add the import to your globals.css after `@import "tailwindcss";`.
```css
@import "tailwindcss";
@import "@hex-core/components/tailwind.css";
@theme {
--color-background: hsl(0 0% 100%);
--color-foreground: hsl(240 10% 3.9%);
/* ... */
}
```
## Workflows
### Add the package to a fresh Next.js + Tailwind v4 app
Three commands and one CSS import. Works the same on Vite, Remix, or any Tailwind v4 host.
```bash
pnpm add @hex-core/components @hex-core/tokens
# ensure tailwindcss + @tailwindcss/postcss are already installed
```
### Compose a settings card with layout primitives
Showcases Stack + Cluster + Grid sharing the same gap scale. No hand-rolled flex utilities.
```tsx
import {
Stack, Cluster, Grid, Card, CardHeader, CardContent,
Button, Input, Label, Switch,
} from "@hex-core/components";
export function NotificationSettings() {
return (
Notifications
);
}
```
## Compatibility
- Peer deps: React 18 or 19, Tailwind CSS v4.
- Optional peers: `@tanstack/react-table` 8 or 9 (only for the DataTable component); `react-hook-form` 7 (only for the Form helpers).
- Bundles `@hex-core/registry@^0.2.1` as a transitive dep — no `workspace:^` republish bug.
- All components ship as ESM only.
## See also
- GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/components
- Browse the component catalog: https://hex-ui.dev/docs
- @hex-core/tokens: https://hex-ui.dev/docs/packages/tokens
- @hex-core/themes: https://hex-ui.dev/docs/packages/themes
---
# @hex-core/tokens
> HSL design tokens, theme presets, and CSS/Tailwind transformers.
Version: `1.2.2`
Install: `pnpm add @hex-core/tokens`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/tokens
## What it does
`@hex-core/tokens` is the design-token data layer. It exports three theme objects (`defaultTheme`, `midnightTheme`, `emberTheme`) plus four transformers that turn those objects into the formats your build pipeline understands: CSS, Tailwind config, raw token sets, and runtime-injectable scoped CSS.
Tokens are the *names* that components reference (`--color-primary`, `--space-4`). Themes are the *values* assigned to those names. The transformers are the bridges. Components, the studio, and the MCP server all read from this single source.
Two namespaces exist intentionally: `themeToCss` emits raw triplets (`--primary: 240 5.9% 10%`) for alpha-composition utilities; `themeToScopedRuntimeCss` emits both the raw form and the `--color-: hsl(...)` form Tailwind v4 expects in `@theme`. Don't hand-roll the second.
## Public API
### defaultTheme / midnightTheme / emberTheme
```ts
import { defaultTheme, midnightTheme, emberTheme } from "@hex-core/tokens";
import type { Theme } from "@hex-core/registry";
const t: Theme = defaultTheme; // strict; tokens align with @hex-core/registry@^0.2.1
```
Three built-in theme objects shaped against `@hex-core/registry`'s strict `Theme` type. Each carries `tokens.light`, `tokens.dark`, and metadata. New presets land in `@hex-core/themes`, not here — `tokens` ships only the foundational three.
```tsx
import { defaultTheme } from "@hex-core/tokens";
console.log(defaultTheme.tokens.light["--color-primary"]);
// → { value: "240 5.9% 10%", type: "color" }
```
### themeToCss
```ts
function themeToCss(theme: Theme, options?: {
mode?: "light" | "dark";
scope?: string;
}): string;
```
Emit the raw-triplet CSS namespace (`--: % %`). This is what the canonical `globals.css` ships in `:root {}` and `.dark {}` blocks. Useful when you need alpha composition (`hsl(var(--primary) / 0.5)`).
```tsx
import { themeToCss, defaultTheme } from "@hex-core/tokens";
const css = themeToCss(defaultTheme, { mode: "light" });
// → ":root { --primary: 240 5.9% 10%; --background: 0 0% 100%; ... }"
```
### themeToScopedRuntimeCss
```ts
function themeToScopedRuntimeCss(theme: Theme, options?: {
mode?: "light" | "dark";
scope?: string;
}): string;
```
Emit BOTH namespaces in one rule: raw `--: ;` AND `--color-: hsl();`. Designed for runtime overrides (think: a studio that mutates the canvas without rebuilding Tailwind). Non-color tokens emit only the raw form.
```tsx
import { themeToScopedRuntimeCss, defaultTheme } from "@hex-core/tokens";
const css = themeToScopedRuntimeCss(defaultTheme, {
mode: "dark",
scope: ".studio-canvas",
});
// → ".studio-canvas.dark { --primary: 0 0% 98%; --color-primary: hsl(0 0% 98%); ... }"
```
### themeToTailwindConfig
```ts
function themeToTailwindConfig(theme: Theme): {
theme: { extend: { colors: Record; ... } };
};
```
Generate a Tailwind config object whose `colors`, `borderRadius`, `boxShadow`, etc. all reference the token CSS variables. Drop the result into `tailwind.config.ts` if you're still on Tailwind v3 — Tailwind v4 consumers prefer the `@theme {}` block instead.
```tsx
import { themeToTailwindConfig, defaultTheme } from "@hex-core/tokens";
export default {
content: ["./src/**/*.{ts,tsx}"],
...themeToTailwindConfig(defaultTheme),
};
```
### generateGlobalsCss
```ts
function generateGlobalsCss(theme: Theme): string;
```
One-shot helper that emits the full `globals.css` body — `@theme {}` block + `:root {}` + `.dark {}`. Used by the CLI's `hex init` and the MCP `emit_app_context` tool. Suitable for code generation; not for runtime injection.
```tsx
import { generateGlobalsCss, defaultTheme } from "@hex-core/tokens";
import { writeFileSync } from "node:fs";
writeFileSync("./globals.css", generateGlobalsCss(defaultTheme));
```
### listThemes
```ts
function listThemes(): readonly { name: string; theme: Theme }[];
```
Enumerate the three built-in themes with their machine-readable names. The studio's theme switcher uses this; so do the per-theme static-param routes inside the docs site.
```tsx
import { listThemes } from "@hex-core/tokens";
for (const { name, theme } of listThemes()) {
console.log(name, theme.tokens.light["--color-background"].value);
}
```
## Workflows
### Swap themes at runtime in the studio canvas
Inject a `;
```
### Build a custom theme by extending an existing one
Themes are plain objects. Spread + override. The `Theme` type from `@hex-core/registry` is strict — TypeScript will tell you if you forget a token.
```tsx
import { defaultTheme } from "@hex-core/tokens";
import type { Theme } from "@hex-core/registry";
export const brandTheme: Theme = {
...defaultTheme,
name: "brand",
tokens: {
...defaultTheme.tokens,
light: {
...defaultTheme.tokens.light,
"--color-primary": { value: "12 100% 50%", type: "color" },
},
},
};
```
## Compatibility
- Strict types against `@hex-core/registry@^0.2.1` (`Record`, not `Record`).
- Zero React or DOM dependencies — works in Node generators, Vite plugins, edge runtimes.
- Token values use HSL triplets (`% %`), the format `` and the brand-native ColorPicker both accept.
## See also
- GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/tokens
- Theming guide: https://hex-ui.dev/docs/theming
- @hex-core/themes (premium catalog): https://hex-ui.dev/docs/packages/themes
- @hex-core/registry (Theme type): https://hex-ui.dev/docs/packages/registry
---
# @hex-core/themes
> Premium theme catalog — midnight, ember, and future presets.
Version: `0.1.1`
Install: `pnpm add @hex-core/themes`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/themes
## What it does
`@hex-core/themes` is the premium-theme catalog. Today it re-exports `midnightTheme` and `emberTheme` from `@hex-core/tokens` and adds catalog helpers shaped to mirror `tokens.listThemes()`. Future presets — `fintech-dark`, `editorial-warm`, `data-dense`, `pastel-soft`, `monochrome-strict` — land here without bumping `tokens`.
The split exists for release independence. `@hex-core/tokens` ships the foundational three themes plus the transformers; tagging a new preset shouldn't force every consumer to retest the transformers. Keeping the catalog separate gives both surfaces their own minor cadence.
If you only need the default theme, depend on `tokens` and skip this package. If you want the studio's full theme switcher (or want your own switcher to discover new presets automatically), depend on `themes`.
## Public API
### premiumThemes
```ts
import { premiumThemes } from "@hex-core/themes";
import type { Theme } from "@hex-core/registry";
declare const premiumThemes: Record;
```
Catalog object keyed by theme name. Re-exports `midnightTheme` + `emberTheme` from `@hex-core/tokens` and adds future premium presets here without tokens needing a release.
```tsx
import { premiumThemes } from "@hex-core/themes";
console.log(Object.keys(premiumThemes));
// → ["midnight", "ember"]
```
### listPremiumThemes
```ts
function listPremiumThemes(): readonly { name: string; theme: Theme }[];
```
Enumerate the catalog. Mirrors the shape of `tokens.listThemes()` so the studio's theme switcher can concat the two arrays without normalizing.
```tsx
import { listPremiumThemes } from "@hex-core/themes";
for (const { name, theme } of listPremiumThemes()) {
console.log(name, theme.tokens.light["--color-background"].value);
}
```
### getPremiumTheme
```ts
function getPremiumTheme(name: string): Theme | undefined;
```
Look up a single premium theme by name. Returns `undefined` if the name isn't in the catalog — callers should fall back to `defaultTheme` from `tokens`.
```tsx
import { getPremiumTheme } from "@hex-core/themes";
import { defaultTheme } from "@hex-core/tokens";
const theme = getPremiumTheme(slug) ?? defaultTheme;
```
## Workflows
### Build a unified theme switcher across both packages
Concat the two catalogs and dedupe by name. Drop into the studio sidebar or any settings panel.
```tsx
import { listThemes } from "@hex-core/tokens";
import { listPremiumThemes } from "@hex-core/themes";
const all = [...listThemes(), ...listPremiumThemes()];
const byName = new Map(all.map((entry) => [entry.name, entry]));
export function ThemePicker({ value, onChange }: { value: string; onChange: (n: string) => void }) {
return (
);
}
```
### Resolve a theme name to its strict object
Walk the catalogs in order; if neither owns the name, fall back to `defaultTheme`. Pass the result into the `tokens` transformers.
```tsx
import { defaultTheme, listThemes } from "@hex-core/tokens";
import { getPremiumTheme } from "@hex-core/themes";
import type { Theme } from "@hex-core/registry";
export function resolveTheme(name: string): Theme {
const builtIn = listThemes().find((t) => t.name === name);
if (builtIn) return builtIn.theme;
return getPremiumTheme(name) ?? defaultTheme;
}
```
## Compatibility
- Peer-free — depends only on `@hex-core/registry@^0.2.1` and `@hex-core/tokens@^1.2.0`.
- Zero React dependencies. Same edge/runtime story as `@hex-core/tokens`.
- `@hex-core/tokens` continues to export `midnightTheme` and `emberTheme` directly — moving them into `themes` is non-breaking.
## See also
- GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/themes
- @hex-core/tokens (transformers): https://hex-ui.dev/docs/packages/tokens
- Theming guide: https://hex-ui.dev/docs/theming
- Studio (live theme switcher): https://hex-ui.dev/studio
---
# @hex-core/registry
> Zod schemas + TypeScript types for components, themes, and recipes.
Version: `0.3.1`
Install: `pnpm add @hex-core/registry`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/registry
## What it does
`@hex-core/registry` is the schema package — Zod schemas plus the TypeScript types they generate. It defines the shape every other hex-core package speaks: `Theme`, `TokenValue`, `RegistryItem`, `Recipe`, the strict variants of each.
Most consumers never `import` from this package directly; they use it transitively through `@hex-core/components`, `@hex-core/tokens`, `@hex-core/themes`, or `@hex-core/payload`. You install it directly when you need to type a function parameter as `Theme`, validate user input against `strictThemeSchema`, or build a tool that produces registry items.
The 0.2.0 release tightened `Theme.tokens.{light,dark}` from `Record` to the strict `Record` shape. Type-version skew between sibling packages is now caught at `tsc` time instead of at runtime.
## Public API
### Theme
```ts
export interface Theme {
name: string;
displayName: string;
colorScheme: "light" | "dark";
tokens: {
light: Record;
dark: Record;
};
}
```
The canonical Theme shape. Every theme object the design system consumes — `defaultTheme`, `midnightTheme`, anything you author — must satisfy this type.
```tsx
import type { Theme } from "@hex-core/registry";
const myTheme: Theme = {
name: "brand",
displayName: "Brand",
colorScheme: "light",
tokens: { light: {/* ... */}, dark: {/* ... */} },
};
```
### TokenValue / TokenSet
```ts
export interface TokenValue {
value: string;
type: "color" | "spacing" | "typography" | "radius" | "shadow" | "duration" | "easing";
}
export type TokenSet = Record;
```
A token is a `value` (HSL triplet, CSS length, easing function, etc.) plus a `type` discriminant. Discriminating by `type` lets transformers emit the right wrapper — `hsl()` for colors, raw value for everything else.
```tsx
import type { TokenValue } from "@hex-core/registry";
const primary: TokenValue = { value: "240 5.9% 10%", type: "color" };
const radius: TokenValue = { value: "0.5rem", type: "radius" };
```
### RegistryItem
```ts
export interface RegistryItem {
name: string;
displayName: string;
description: string;
category: "primitive" | "component" | "block" | "hook";
props: PropDef[];
variants: VariantDef[];
examples: Example[];
ai: AIHints;
dependencies: { npm: string[]; internal: string[]; peer: string[] };
tags: string[];
}
```
Schema for one entry in `registry/items/.json`. Components, the CLI's `hex add`, and the MCP server's `get_component` tool all serialize to this shape. The `ai` block is what makes hex-ui LLM-native — `whenToUse`, `commonMistakes`, `accessibilityNotes`.
```tsx
import { registryItemSchema } from "@hex-core/registry";
const parsed = registryItemSchema.parse(rawJson);
// → typed RegistryItem with full validation
```
### strictThemeSchema / strictTokenSetSchema
```ts
import { strictThemeSchema, strictTokenSetSchema } from "@hex-core/registry";
import type { z } from "zod";
declare const strictThemeSchema: z.ZodType;
declare const strictTokenSetSchema: z.ZodType;
```
Zod schemas for runtime validation. Use these at trust boundaries — parsing user-submitted theme overrides, validating an MCP tool input, ingesting a third-party token set.
```tsx
import { strictThemeSchema } from "@hex-core/registry";
const result = strictThemeSchema.safeParse(input);
if (!result.success) {
throw new Error("Invalid theme: " + result.error.message);
}
const theme = result.data;
```
## Workflows
### Validate a user-uploaded theme JSON file
Users sometimes ship custom themes as JSON. Parse with `strictThemeSchema` before handing the result to any transformer.
```tsx
import { strictThemeSchema } from "@hex-core/registry";
import { themeToCss } from "@hex-core/tokens";
export async function compileUploadedTheme(json: unknown) {
const result = strictThemeSchema.safeParse(json);
if (!result.success) {
return { ok: false, errors: result.error.issues };
}
return { ok: true, css: themeToCss(result.data, { mode: "light" }) };
}
```
### Build a typed registry-item generator
Authoring a custom component? Type your scaffold against `RegistryItem` so missing fields surface at `tsc` time.
```tsx
import type { RegistryItem } from "@hex-core/registry";
export function makeRegistryItem(name: string): RegistryItem {
return {
name,
displayName: name,
description: "TODO",
category: "component",
props: [],
variants: [],
examples: [],
ai: {
whenToUse: "",
whenNotToUse: "",
commonMistakes: [],
relatedComponents: [],
accessibilityNotes: "",
tokenBudget: 0,
},
dependencies: { npm: [], internal: [], peer: [] },
tags: [],
};
}
```
## Compatibility
- Depends only on `zod@^4.3.6`. No React, no DOM, no Node-specific APIs.
- Compiled to ESM with `.d.ts` types. Tree-shakable — importing only `Theme` doesn't pull the Zod runtime.
- Strict-mode schema versioning: 0.2.x line is back-compatible at the type level; ingesting older theme JSON usually still parses cleanly.
## See also
- GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/registry
- @hex-core/tokens (consumes Theme): https://hex-ui.dev/docs/packages/tokens
- @hex-core/payload (consumes RegistryItem): https://hex-ui.dev/docs/packages/payload
---
# @hex-core/payload
> Pure-function builders for the canonical LLM context markdown.
Version: `0.2.1`
Install: `pnpm add @hex-core/payload`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/payload
## What it does
`@hex-core/payload` is the pure-function builder for the canonical LLM context blob. Pass it a theme + components (+ optional recipes, density), get markdown back.
It exists so non-MCP-client surfaces — Next.js Server Components, generator scripts, CI fixtures, CLI tools — can render the canonical payload without spawning a subprocess and speaking JSON-RPC over stdio. The MCP server (`@hex-core/mcp@0.4.0+`) is now a thin transport shell that wraps this package.
The package also bundles the registry data (~59 items at last release) inside its tarball, so loaders work without filesystem coupling to the consumer's repo. This is what unblocked the studio's `/copy` route from re-implementing the markdown format locally.
## Public API
### buildAppContext
```ts
function buildAppContext(input: {
theme: { requested: string; resolved: Theme };
components: { slug: string; item: RegistryItem | null }[];
recipes?: { slug: string; recipe: Recipe }[];
density?: "compact" | "comfortable" | "spacious";
overrides?: Record;
}): string;
```
Build the full canonical markdown blob: install commands, `globals.css`, `tailwind.config.ts`, components, recipes, and the LLM context prompt. The `theme.requested` field surfaces in the markdown so the LLM knows whether the user picked the theme or fell back to default.
```tsx
import { buildAppContext, loadRegistryItem } from "@hex-core/payload";
import { defaultTheme } from "@hex-core/tokens";
const components = ["button", "card", "input"].map((slug) => ({
slug,
item: loadRegistryItem(slug),
}));
const markdown = buildAppContext({
theme: { requested: "default", resolved: defaultTheme },
components,
density: "comfortable",
});
// Render markdown in a Server Component, write to disk, etc.
```
### buildFigmaTokens
```ts
function buildFigmaTokens(theme: Theme): {
$schema: string;
[collection: string]: unknown;
};
```
Build a Figma Variables JSON document from a theme. Drop the result into the Figma plugin's import slot and the design system's tokens land in the file as variables. Round-trips with the same `Theme` shape that powers `themeToCss`.
```tsx
import { buildFigmaTokens } from "@hex-core/payload";
import { defaultTheme } from "@hex-core/tokens";
import { writeFileSync } from "node:fs";
writeFileSync(
"./design-tokens.figma.json",
JSON.stringify(buildFigmaTokens(defaultTheme), null, 2),
);
```
### loadRegistryItem / loadRegistry
```ts
function loadRegistryItem(slug: string): RegistryItem | null;
function loadRegistry(): readonly RegistryItem[];
```
Read from the bundled registry snapshot. `loadRegistryItem` returns `null` for an unknown slug; `loadRegistry` enumerates the whole catalog. Server-only — both functions perform synchronous filesystem reads, so don't import them from a Client Component.
```tsx
import { loadRegistry, loadRegistryItem } from "@hex-core/payload";
const all = loadRegistry();
console.log(all.length); // 59 (at @0.2.0)
const button = loadRegistryItem("button");
if (button) {
console.log(button.ai.whenToUse);
}
```
### loadRecipes / loadRecipe
```ts
function loadRecipes(): readonly Recipe[];
function loadRecipe(slug: string): Recipe | null;
```
Same shape as the component loaders, but for the multi-component recipes (auth-form, settings-page, command-palette, etc.). Pass results into `buildAppContext`'s optional `recipes` field to bundle them into the LLM payload.
```tsx
import { loadRecipe } from "@hex-core/payload";
const auth = loadRecipe("auth-form");
console.log(auth?.components); // ["button", "input", "label", ...]
```
### getTheme / listThemes
```ts
function getTheme(name: string): Theme | undefined;
function listThemes(): readonly { name: string; theme: Theme }[];
```
Re-exports of the theme catalog from `@hex-core/tokens`. Convenient when you already have `@hex-core/payload` installed and don't want to add a second dependency just to look up a theme by name.
```tsx
import { getTheme, listThemes } from "@hex-core/payload";
const theme = getTheme("midnight") ?? getTheme("default");
console.log(listThemes().map((t) => t.name));
```
### resolveSpec
```ts
function resolveSpec(brief: string): {
components: string[];
recipes: string[];
rationale: string;
};
```
Deterministic brief-to-shortlist resolver. Pass a natural-language description ("settings page with profile, billing, notifications"); get back a ranked list of registry slugs + rationale. Same logic the MCP `resolve_spec` tool wraps.
```tsx
import { resolveSpec } from "@hex-core/payload";
const result = resolveSpec("confirm-destructive dialog with checkbox and dual-action footer");
console.log(result.components); // ["dialog", "checkbox", "button"]
console.log(result.recipes); // ["confirm-destructive"]
```
## Workflows
### Render the canonical payload from a Next.js Server Component
This is what the studio's `/copy` page does. No subprocess, no JSON-RPC, no MCP transport — direct function call.
```tsx
// app/llm-context/page.tsx
import { buildAppContext, loadRegistryItem } from "@hex-core/payload";
import { defaultTheme } from "@hex-core/tokens";
export default function LlmContextPage() {
const components = ["button", "card", "input", "dialog"].map((slug) => ({
slug,
item: loadRegistryItem(slug),
}));
const markdown = buildAppContext({
theme: { requested: "default", resolved: defaultTheme },
components,
});
return
{markdown}
;
}
```
### Generate a Figma tokens file in a CI script
Run on every theme change to keep design and code in sync.
```ts
// scripts/sync-figma-tokens.ts
import { buildFigmaTokens, getTheme } from "@hex-core/payload";
import { writeFileSync } from "node:fs";
const theme = getTheme(process.env.THEME ?? "default");
if (!theme) throw new Error("Unknown theme");
writeFileSync(
"./design/figma-tokens.json",
JSON.stringify(buildFigmaTokens(theme), null, 2),
);
console.log("Wrote figma-tokens.json");
```
## Compatibility
- Pure ESM. Server-only — `loadRegistry*` and `loadRecipe*` perform synchronous `fs` reads. Do not import from a Client Component.
- Bundles `registry/` data into the published tarball. Works in fresh `npm install` outside the hex-core monorepo.
- Depends on `@hex-core/registry@^0.2.1` and `@hex-core/tokens@^1.2.0`. Re-exports `Theme`, `RegistryItem`, `Recipe` types so consumers don't need a second dep.
## See also
- GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/payload
- @hex-core/mcp (transport wrapper): https://hex-ui.dev/docs/packages/mcp
- Studio /copy page (live consumer): https://hex-ui.dev/studio/copy
- Spec-driven development: https://hex-ui.dev/docs/spec-driven
---
# @hex-core/cli
> The hex binary — init, add, list, theme set, recipe add.
Version: `0.2.3`
Install: `pnpm dlx @hex-core/cli init`
Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/cli
## What it does
`@hex-core/cli` is the `hex` binary. It scaffolds projects, copies components into `src/components/ui/`, swaps theme presets in `globals.css`, and installs multi-component recipes.
It's *not* a runtime dependency. You invoke it via `pnpm dlx @hex-core/cli` (or `npx @hex-core/cli`); nothing sticks to your `package.json`. The CLI bundles the registry data, so it works against fresh installs outside the hex-core monorepo.
For LLM-driven workflows, the equivalent surface is the MCP server (`@hex-core/mcp`). Both speak the same registry — the CLI is invoked by humans; MCP is invoked by agents.
## Public API
### hex init
```ts
pnpm dlx @hex-core/cli init
```
Scaffold the Tailwind v4 setup: writes `globals.css` with the default theme's `@theme` block + `:root {}` + `.dark {}`, adds the `@import "@hex-core/components/tailwind.css"` directive, and prints next steps. Idempotent — re-running won't double-write existing tokens.
```bash
cd my-next-app
pnpm dlx @hex-core/cli init
# → wrote src/app/globals.css
# → next: pnpm dlx @hex-core/cli add button
```
### hex add
```ts
pnpm dlx @hex-core/cli add [--lib]
```
Copy one or more components (and their internal deps) into your project. Component sources land in `src/components/ui/.tsx`; the `cn` helper and other shared utilities go to `src/lib/utils.ts` unless `--lib` overrides the path. Skips files that already exist so you can run it freely after edits.
```bash
pnpm dlx @hex-core/cli add button card input
# → installed button → src/components/ui/button.tsx
# → installed card → src/components/ui/card.tsx
# → installed input → src/components/ui/input.tsx
```
### hex list [--category ]
```ts
pnpm dlx @hex-core/cli list [--category primitive|component|block|hook]
```
Print every component (or recipe) the bundled registry knows about. Useful when scripting bulk installs.
```bash
pnpm dlx @hex-core/cli list --category primitive
# button
# card
# input
# label
# ...
```
### hex theme set
```ts
pnpm dlx @hex-core/cli theme set
```
Swap the `:root {}` and `.dark {}` blocks in your `globals.css` for the named preset. Recognized names: the three built-ins from `@hex-core/tokens` plus everything in `@hex-core/themes`. Leaves your `@theme {}` block alone.
```bash
pnpm dlx @hex-core/cli theme set midnight
# → updated src/app/globals.css :root and .dark blocks for theme "midnight"
```
### hex recipe add
```ts
pnpm dlx @hex-core/cli recipe add
```
Install every component a recipe needs in one call, in the order the recipe declares. Resolves to the same six recipes the MCP `list_recipes` tool exposes.
```bash
pnpm dlx @hex-core/cli recipe add settings-page
# → installs: tabs, card, input, switch, separator, button
# → next steps: see docs/recipes/settings-page
```
## Workflows
### Bootstrap a new project
Three commands gets you a Next.js + Tailwind v4 app with the design system installed and a Button + Card on the page.
```bash
pnpm create next-app@latest my-app --tailwind --app
cd my-app
pnpm dlx @hex-core/cli init
pnpm dlx @hex-core/cli add button card
```
### Switch your theme without re-running init
Useful when you're A/B-testing a brand. The command rewrites only the token blocks; your custom CSS stays.
```bash
pnpm dlx @hex-core/cli theme set ember
# … inspect output …
pnpm dlx @hex-core/cli theme set default # roll back
```
### Install an entire recipe
Recipes are vetted multi-component compositions. The CLI fetches every primitive the recipe needs and prints the post-install checklist.
```bash
pnpm dlx @hex-core/cli recipe add auth-form
# → installs: button, input, label, card, separator
# → checklist: wire