# 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
to your auth handler; see docs/recipes/auth-form ``` ## Compatibility - Requires Node.js 20.9+ and a project that already has `package.json`. - Detects pnpm / npm / yarn / bun automatically when prompting peer-dep installs. - Bundles the registry into the tarball — works without network access after `pnpm dlx` caches the package. - Bin name: `hex` (not `hex-cli` or `hexui`). ## See also - GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/cli - Installation guide: https://hex-ui.dev/docs/installation - @hex-core/mcp (LLM-driven equivalent): https://hex-ui.dev/docs/packages/mcp - Spec-driven development: https://hex-ui.dev/docs/spec-driven --- # @hex-core/mcp > Stdio MCP server: emit_app_context, emit_figma_tokens, resolve_spec, and more. Version: `0.4.2` Install: `pnpm dlx @hex-core/mcp` Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/mcp-server ## What it does `@hex-core/mcp` is the stdio MCP (Model Context Protocol) server. It exposes the registry, themes, recipes, and the canonical LLM payload as structured tool calls for AI agents. Wire it into Claude Code, Cursor, Continue, Zed, ChatGPT Desktop, or any MCP-aware client and your agent gains tools like `search_components`, `get_component`, `list_recipes`, `emit_app_context`, and `emit_figma_tokens`. Every tool's I/O is schema-validated; agents can't pass unknown fields. As of `@hex-core/mcp@0.4.0`, the server is a thin transport shell over `@hex-core/payload`. The pure-function builders live in `payload`; this package wraps them in `@modelcontextprotocol/sdk`'s server primitives. If you want the same outputs without the stdio handshake, depend on `@hex-core/payload` directly. ## Public API ### search_components ```ts { name: "search_components", input: { query: string; limit?: number }, output: { results: { slug: string; score: number; matchedOn: string[] }[] } } ``` Fuzzy search across component names, descriptions, tags, and AI hints. Higher score = better match. Agents call this first when picking a primitive. ```ts // agent prompt: "find me a confirmation dialog" // → search_components({ query: "confirmation dialog" }) // → { results: [{ slug: "dialog", score: 0.94, ... }, { slug: "alert-dialog", score: 0.91, ... }] } ``` ### get_component / get_component_schema ```ts { name: "get_component", input: { slug: string }, output: RegistryItem } { name: "get_component_schema", input: { slug: string }, output: { props: PropDef[]; variants: VariantDef[]; ai: AIHints } } ``` `get_component` returns the full registry item — props, variants, examples, AI hints, source. `get_component_schema` returns the schema slice only, for agents reasoning about a component they've already installed. ```ts // agent has already added the button — only needs the schema // → get_component_schema({ slug: "button" }) ``` ### emit_app_context ```ts { name: "emit_app_context", input: { theme: string; // theme name components: string[]; // slugs recipes?: string[]; overrides?: Record; density?: "compact" | "comfortable" | "spacious"; }, output: { content: [{ type: "text", text: /* markdown */ }] } } ``` Returns the full canonical context markdown — install commands, `globals.css`, `tailwind.config.ts`, components, recipes, and the LLM context prompt. Same artifact `@hex-core/payload`'s `buildAppContext` produces. ```ts // One call powers the studio's /copy page workflow: // → emit_app_context({ // theme: "default", // components: ["button", "card", "input"], // density: "comfortable", // }) ``` ### emit_figma_tokens ```ts { name: "emit_figma_tokens", input: { theme: string }, output: { content: [{ type: "text", text: /* JSON */ }] } } ``` Emit a Figma Variables JSON document for the named theme. Same shape `@hex-core/payload`'s `buildFigmaTokens` returns — paste into the Figma plugin's import slot. ```ts // → emit_figma_tokens({ theme: "midnight" }) // → { content: [{ type: "text", text: '{"$schema":...}' }] } ``` ### list_recipes / get_recipe ```ts { name: "list_recipes", input: {}, output: { recipes: { slug: string; description: string }[] } } { name: "get_recipe", input: { slug: string }, output: Recipe } ``` Enumerate the recipe catalog (auth-form, settings-page, command-palette, …) or fetch one in full with its ordered install steps and post-install checklist. ```ts // → list_recipes() // → { recipes: [{ slug: "auth-form", ... }, { slug: "settings-page", ... }, ...] } ``` ### resolve_spec / verify_checklist ```ts { name: "resolve_spec", input: { brief: string }, output: { components: string[]; recipes: string[]; rationale: string } } { name: "verify_checklist", input: { installed: string[] }, output: { missingPeers: string[]; ok: boolean } } ``` `resolve_spec` turns a natural-language brief into a ranked component shortlist. `verify_checklist` cross-checks the agent's installed list against the registry's internal-dependency graph. ```ts // → resolve_spec({ brief: "settings page with profile, billing, notifications" }) // → { components: ["tabs", "card", "input", ...], recipes: ["settings-page"], rationale: "..." } ``` ## Workflows ### Wire the server into Claude Code Drop the snippet into `.claude/settings.json` (project) or `~/.claude/settings.json` (global). The next Claude session picks up the tools. ```json { "mcpServers": { "hex-ui": { "command": "npx", "args": ["@hex-core/mcp"] } } } ``` ### Wire the server into Cursor Cursor reads `.cursor/mcp.json` at the project root. ```json { "mcpServers": { "hex-ui": { "command": "npx", "args": ["@hex-core/mcp"] } } } ``` ### Skip the transport — call buildAppContext directly If you're inside a Server Component or a generator script and don't need the tool-call overhead, depend on `@hex-core/payload` instead. Same output, no stdio handshake. ```tsx import { buildAppContext, loadRegistryItem } from "@hex-core/payload"; import { defaultTheme } from "@hex-core/tokens"; const components = ["button", "card"].map((slug) => ({ slug, item: loadRegistryItem(slug), })); const markdown = buildAppContext({ theme: { requested: "default", resolved: defaultTheme }, components, }); ``` ## Compatibility - Requires Node.js 20.9+ on the client side (whatever spawns the server). The bundled registry travels with the tarball, so the server boots without network access. - Bin name: `hex-ui-mcp`. Most MCP clients invoke via `npx @hex-core/mcp` rather than the bin directly. - All tool I/O is Zod-validated with `additionalProperties: false`. Invalid input throws structured errors back to the client. - Depends on `@modelcontextprotocol/sdk@^1.12.0`, `@hex-core/payload@^0.2.0`, `@hex-core/registry@^0.2.1`. ## See also - GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/mcp-server - MCP server setup guide: https://hex-ui.dev/docs/mcp - @hex-core/payload (programmatic equivalent): https://hex-ui.dev/docs/packages/payload - Spec-driven development: https://hex-ui.dev/docs/spec-driven --- # @hex-core/preview > DemoSurface wrapper for showcasing components on flat-white pages. Version: `0.2.0` Install: `pnpm add @hex-core/preview` Source: https://github.com/oscarabcorona/hex-core/tree/main/packages/preview ## What it does `@hex-core/preview` is a tiny demo-surface helper. It exports ``, the elevated container the official docs site uses to wrap component previews so Outline / Secondary buttons read against an off-white background instead of a flat-white page. Hex UI's tokens are deliberately subtle — `--border` and `--input` sit close to `--card` to avoid heavy mid-grays. That choice looks great on already-elevated surfaces (Card, Popover, Dialog) but washes out on a plain page background. `` reproduces the official preview's elevation in one component so consumers' showcase pages match the docs site visually. This package is optional. If you're building a marketing site or a production app, you don't need it. If you're authoring component demos for your own design system or internal docs, drop a `` around each one and you're done. ## Public API ### DemoSurface ```ts import { DemoSurface } from "@hex-core/preview"; interface DemoSurfaceProps extends React.HTMLAttributes { minHeight?: string; } ``` Elevated div that mimics the docs-site preview wrapper. Pass any standard div attributes — `id`, `data-*`, `className` (merged with Tailwind). `minHeight` defaults to a comfortable showcase height; override when wrapping tall demos. ```tsx import { DemoSurface } from "@hex-core/preview"; import { Button } from "@hex-core/components"; export function ButtonShowcase() { return ( ); } ``` ## Workflows ### Wrap an entire showcase grid One surface around the grid is plenty — no need to nest one per cell. The grid inherits the elevation from its parent. ```tsx import { DemoSurface } from "@hex-core/preview"; import { Button, Grid } from "@hex-core/components"; export function VariantShowcase() { return ( ); } ``` ## Compatibility - Peer deps: `react ^18 || ^19`, `react-dom ^18 || ^19`. - Assumes the consumer's app already loads the Hex UI token CSS — utilities like `bg-muted` need to resolve. - Pure React component; no Radix dependency, no portal usage. ## See also - GitHub source: https://github.com/oscarabcorona/hex-core/tree/main/packages/preview - @hex-core/components: https://hex-ui.dev/docs/packages/components - Theming guide: https://hex-ui.dev/docs/theming ---