@hex-core/tokens
HSL design tokens, theme presets, and CSS/Tailwind transformers.
Install
1.2.2Runtime dependencypnpm add @hex-core/tokensWhat 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-<key>: hsl(...)` form Tailwind v4 expects in `@theme`. Don't hand-roll the second.
Public API
defaultTheme / midnightTheme / emberTheme
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.1Three 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.
import { defaultTheme } from "@hex-core/tokens";
console.log(defaultTheme.tokens.light["--color-primary"]);
// → { value: "240 5.9% 10%", type: "color" }themeToCss
function themeToCss(theme: Theme, options?: {
mode?: "light" | "dark";
scope?: string;
}): string;Emit the raw-triplet CSS namespace (`--<key>: <H> <S>% <L>%`). This is what the canonical `globals.css` ships in `:root {}` and `.dark {}` blocks. Useful when you need alpha composition (`hsl(var(--primary) / 0.5)`).
import { themeToCss, defaultTheme } from "@hex-core/tokens";
const css = themeToCss(defaultTheme, { mode: "light" });
// → ":root { --primary: 240 5.9% 10%; --background: 0 0% 100%; ... }"themeToScopedRuntimeCss
function themeToScopedRuntimeCss(theme: Theme, options?: {
mode?: "light" | "dark";
scope?: string;
}): string;Emit BOTH namespaces in one rule: raw `--<key>: <value>;` AND `--color-<key>: hsl(<value>);`. Designed for runtime overrides (think: a studio that mutates the canvas without rebuilding Tailwind). Non-color tokens emit only the raw form.
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
function themeToTailwindConfig(theme: Theme): {
theme: { extend: { colors: Record<string, string>; ... } };
};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.
import { themeToTailwindConfig, defaultTheme } from "@hex-core/tokens";
export default {
content: ["./src/**/*.{ts,tsx}"],
...themeToTailwindConfig(defaultTheme),
};generateGlobalsCss
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.
import { generateGlobalsCss, defaultTheme } from "@hex-core/tokens";
import { writeFileSync } from "node:fs";
writeFileSync("./globals.css", generateGlobalsCss(defaultTheme));listThemes
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.
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 `<style>` tag with `themeToScopedRuntimeCss` output. Change the input theme to repaint the scoped surface — no Tailwind rebuild required.
import { themeToScopedRuntimeCss, midnightTheme } from "@hex-core/tokens";
const css = themeToScopedRuntimeCss(midnightTheme, {
mode: "light",
scope: "[data-studio-canvas]",
});
// In a Server Component:
return <style>{css}</style>;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.
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<string, TokenValue>`, not `Record<string, unknown>`).
- Zero React or DOM dependencies — works in Node generators, Vite plugins, edge runtimes.
- Token values use HSL triplets (`<H> <S>% <L>%`), the format `<input type="color">` and the brand-native ColorPicker both accept.