Gesso
Getting started

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/tokens

This 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/button

Button 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.

On this page