Start

Tokens as a package, components as code

Two halves. The tokens — colours, type, motion, the Tailwind preset — come from npm and upgrade in one place. The components are copied into your app with the shadcn CLI and become yours to adapt.

1 · The tokens package

bun add @fastrp/design-tokens

Peer dependency: tailwindcss@^3.4. Tailwind 4 is not supported — the game cannot run it.

2 · The preset and the stylesheet

tailwind.config.ts
import { fastPreset } from '@fastrp/design-tokens/preset';
import type { Config } from 'tailwindcss';

export default {
  presets: [fastPreset],
  content: ['./src/**/*.{ts,tsx}'],
} satisfies Config;
globals.css
@import '@fastrp/design-tokens/tokens.css';

@tailwind base;
@tailwind components;
@tailwind utilities;

What the preset leaves alone

It does not set screens, corePlugins, the spacing scale or content. The game keeps its breakpoints and its backdropBlur: false.

3 · cn() that knows the preset

Plain twMerge reads text-display-1 as a colour and drops it when text-white follows. Extend it once.
lib/utils.ts
import { fastTwMergeConfig } from '@fastrp/design-tokens/tw-merge';
import { type ClassValue, clsx } from 'clsx';
import { extendTailwindMerge } from 'tailwind-merge';

const twMerge = extendTailwindMerge(fastTwMergeConfig);

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

4 · Components from the registry

Add the registry to components.json, then add components by name. Files land in components/ds/, each marked // @fast-ds name@version under its imports so a copy can be compared with the registry later.
components.json
{
  "registries": {
    "@fastrp": "https://design.fast-rp.com/r/{name}.json"
  }
}
bunx shadcn@3 add @fastrp/section-heading

5 · The font

Load Barlow as --font-sans and Barlow Condensed as --font-display, with the latin-ext subset. See Typography.