The shadcn Binding
How brand tokens become installable shadcn registry resources.
Documentation for BrandBuilder 3.0.1. Official release and exact skill asset.
This layer maps approved brand decisions into the names a shadcn consumer uses.
An agent working in a Next.js project reaches for --primary, bg-card, text-muted-foreground, and --ring. The generated binding gives those slots approved source values and measurable pairings instead of leaving a consumer to choose a substitute.
Generator: templates/gen_nextjs.py. Inspect the exact generated nextjs/ directory in the selected kit for delivered values.
What gets emitted
nextjs/
globals.css Tailwind v4, @theme inline, :root and .dark in OKLCH
fonts.ts next/font/local against bundled faces
providers.tsx next-themes, dark by default
components.json.snippet the registries entry a consumer pastes
registry/
registry.json the catalog
theme.json registry:theme carrying every cssVar
<component>.json installable registry:ui payloads
README.md install instructions and the rules that outlive themFour decisions worth understanding
1. Keep shadcn's :root = light, .dark = dark convention
ShruggieTech is dark-first, and the tempting move is to invert those two blocks so dark is the default. Do not. Every third-party shadcn block, every copy-pasted component, and next-themes itself assume the standard convention. Inverting it breaks all of them for no gain.
Dark-first is expressed in providers.tsx with defaultTheme="dark" and
enableSystem={false}. Same outcome, nothing broken.
2. Radius pegs are set explicitly
shadcn derives its whole radius scale from one --radius by fixed ratios
(sm 0.6x, md 0.8x, lg 1x, xl 1.4x). That derivation cannot land 6/8/12 at once.
The generator writes the steps directly:
--radius-sm: 6px; /* chips */
--radius-md: 8px; /* Button, Input, Select, Popover, Dropdown */
--radius-lg: 10px;
--radius-xl: 12px; /* Card, Dialog */
--radius-2xl: 16px;The values are chosen so each brand system peg lands on the component that actually uses that utility. The pegs are non-negotiable; shadcn's ratio is not.
3. Every colour ships as OKLCH with the hex in a trailing comment
Hex stays canonical in brand.json for print, vinyl, and legal use. OKLCH is
what reaches the browser, matching current shadcn practice and making
programmatic derivation sane. The comment lets a human read the file and lets
verify assert the round-trip.
4. The accent appears twice, differently
--primary in .dark is the bright accent. --primary in :root is the
accessible variant. This is not a nicety. ShruggieTech's bright green
does not automatically clear the light-surface contrast floor. The generator
derives and measures the accessible light variant before publication.
--primary-foreground is measured, never assumed. White on ShruggieTech green
is 2.10:1; black is 9.99:1.
The chart formula and its checks
Rotate hue by 0, -52, +52, -104, +104 off the identity accent, hold chroma at 0.92x for entries two through five, then solve lightness against the actual surface, taking the value closest to the target that still clears 4.5:1.
Solve against the real surface in each theme. A value that passes on black may fail on a light ground. Take the nearest passing lightness rather than pushing every entry to an extreme, and do not darken a value twice after the light-theme variant has already been derived. Read measured current entries from the selected kit's tokens and VERIFY.md.
Distribution
The public registry.json is a discovery catalog. A consuming Next.js/Tailwind v4 project installs direct item endpoints with the pinned shadcn CLI:
npx [email protected] registry add @shruggietech=https://brand.shruggie.tech/shruggietech/brand/r/{name}.json
npx [email protected] add @shruggietech/themePrivate registries authenticate through components.json's registries
object with ${ENV_VAR} expansion in headers, so an internal namespace needs
no special client work.
Two things this unlocks beyond convenience:
- Each item endpoint is checked against the pinned registry schema and installed in a clean consumer fixture before publication. A catalog entry mirrors that endpoint rather than acting as an empty placeholder.
- The CLI does not install the whole kit or its enforcement instructions. Download the complete kit to obtain those files, local fonts, and the wider brand guidance.
Fonts
fonts.ts uses next/font/local for the role faces selected by typography.mode. House mode emits Geist, Geist Mono, and Space Grotesk. Fixed mode emits only the declared local faces and their measured weights and styles. Copy the kit's nextjs/fonts.ts and fonts/ tree together, preserving their relative paths, then apply fontVariables to <html>. A registry:font item cannot deliver these bundled faces with shadcn 4.21.0 because its schema only permits a Google provider. The catalog therefore does not advertise one. This manual step makes no font-network request.
The generated theme also resolves brand-emphasis and brand-cta from the explicit inheritance contract. House inheritance uses ShruggieTech orange. Independent inheritance uses the brand's required semantic colors and does not receive the house pair.
The generated README carries the warning that matters: never fetch fonts at
build time inside a sandbox. fonts.gstatic.com is blocked by the egress proxy
while fonts.googleapis.com resolves, so the fetch appears to succeed and then
dies at the binary step.
Verification
verify re-parses the generated globals.css and asserts:
- Every OKLCH value round-trips to its stated hex
- Every foreground/background pair meets 4.5:1, both modes
destructiveandringare legible on their surface, both modes- All five chart entries clear 4.5:1 on their surface, both modes
- The radius pegs are present and exact
- Dark-first comes from the provider and
:rootis still light
All six pass on the ShruggieTech instance. Check 4 is in the list because it caught a real failure during development.
Apply the binding in a host
First install the exact registry theme and verify the generated semantic variable names against the host's shadcn theming contract. For a form, bind the input to a visible label using the React input guidance; then inspect focus and error cues at rendered size. Use Tailwind state variants only for states the component recipe declares, and review the CSS custom-property scope before overriding a token. These framework references guide the host; the versioned kit files and local verifier remain the implementation authority.