Installation
Register the Gesso registry, add the tokens, wire the CSS, and install a first component and a look.
This page takes a project from nothing to a Gesso component on screen in a look you chose, in
five steps. You need a project with Tailwind CSS v4 and the shadcn CLI set up, which means a
components.json and a cn helper at your utils alias (@/lib/utils by default), because
items import cn from there. The token files use Tailwind v4's @theme inline and @utility.
Run the commands with your package manager's runner (npx, pnpm dlx, or bunx), and note that
the other pages write shadcn add for short.
1. Register the namespace
Add the registry to your components.json, so any @gesso/* item resolves.
{
"registries": {
"@gesso": "https://gesso.ramson.tech/r/{name}.json"
}
}The CLI fills in {name}, so @gesso/tokens is read from https://gesso.ramson.tech/r/tokens.json.
2. Add the tokens
npx shadcn@latest add @gesso/tokensThis writes four files to a styles/dry/ folder, inside src/ when your project has one:
primitives.css, brand.css, system.css, and bindings.css. Add the tokens before any
component, because a few small items, such as Button, Card, Badge, and Input, do not pull
@gesso/tokens in themselves, while most others reach it through their own dependencies.
3. Wire the CSS
Import the four files after Tailwind, in this order, from your CSS entry file. Import them
directly there and not through another CSS file, so Tailwind resolves @theme inline in
bindings.css. Adjust the path to where styles/dry/ sits relative to your entry file.
@import "tailwindcss";
@import "./styles/dry/primitives.css";
@import "./styles/dry/brand.css";
@import "./styles/dry/system.css";
@import "./styles/dry/bindings.css";primitives.css, brand.css, and system.css wrap themselves in gesso.* layers, and
bindings.css is unlayered. Your own retune and any prefab are unlayered too, so they beat the
brand layer wherever their import sits. The Theming overview shows what each
file holds.
Toggle dark mode by putting a dark class on the root element, the same element that carries
data-theme. The kit does not ship a toggle.
4. Add a first component
npx shadcn@latest add @gesso/buttonButton lands in your ui alias, @/components/ui by default, and the CLI installs its npm
dependencies. An item with registryDependencies brings those items too, so
@gesso/alert-dialog adds Button and the tokens with it.
import { Button } from "@/components/ui/button";
export function Example() {
return <Button>Save changes</Button>;
}With no look set the kit is dry, which is gray chrome and an ink primary, so this renders a near-black button.
5. Choose a look
A look is a data-theme value on your root element. Start from a prefab and import its file
after the token imports.
npx shadcn@latest add @gesso/washi@import "./styles/dry/themes/washi.css";<html data-theme="washi">@gesso/ics, @gesso/ramson, and @gesso/vistula install the same way, and Prefabs
compares the four. @gesso/ramson-brand and
@gesso/ascora-brand bring a prefab together with that brand's marks and
a fonts.css. Prefabs name their faces and do not load them, so load the font files in your app.
To make your own look, write one [data-theme] block, which is the path most projects take.
Chrome is gray until a look sets the warm or cool knobs, and a look can set them with a few
lines.
[data-theme="acme"] {
--brand-primary: oklch(0.546 0.245 262);
--brand-primary-fg: var(--neutral-50);
--chrome-chroma: var(--warm-chroma);
--chrome-chroma-tag: var(--warm-chroma-tag);
--chrome-hue: var(--warm-hue);
}Leave that block unlayered. Do not put it in @layer gesso.brand.
Updating items
Run shadcn add again to pull an item's latest version. It resolves the item's dependencies
too, and for each file you already have it skips the file when the incoming copy matches yours
exactly and asks before overwriting when it differs. A formatter that reflows kit files after
install, with a different line width or sorted imports, makes every file differ, so each add
asks about dependencies like Badge that never changed.
Keep kit files as shadcn wrote them by leaving their folders out of your formatter. In Biome,
with the paths set to where your project keeps the ui alias and styles/dry:
{
"files": {
"includes": ["**", "!src/components/ui", "!src/styles/dry"]
}
}Unchanged dependencies are then skipped without a prompt. When you have no local edits to
protect, --overwrite takes the latest of everything without asking. Changes you need belong in
your own wrapper components, since an overwrite drops edits to kit files.
Next
Tint the room on Chrome & temperature, retune color and type on Retune, or browse the components.