foundations
Star
@supertype.ai/foundations

Better foundations

Pre-made shadcn and tailwind components for semantic and legible interfaces. Built for the Supertype assembly line and open-source.

Install

Install it with three commands: add the package, initialize the CSS, and run the wiring check.

yarn add @supertype.ai/foundations
npx foundations init      # adds and reorders the CSS imports, prints the rest
npx foundations doctor    # checks the wiring

Every release is tagged and published, so you can pin a specific commit ahead of the next release.

Here is what init writes. This site uses the same block, unchanged:

/* app/global.css */
@import "tailwindcss";
@import "@supertype.ai/foundations/tokens.css";
@import "@supertype.ai/foundations/theme.css";
@import "@supertype.ai/foundations/type.css";
@import "@supertype.ai/foundations/prose.css";
@import "@supertype.ai/foundations/shiki.css";

@source '../node_modules/@supertype.ai/foundations/dist/**/*.js';

Do not skip the @source line

Tailwind generates only the classes it finds in the files it scans, and skips node_modules by default. Leave this line out and the package’s utility classes get purged from the build. The components render bare, with no error.

Fonts are the one part you wire up yourself. next/font runs in your app and hashes its variable names at build time, so the binding belongs in your layout:

// app/layout.tsx
import { Ubuntu_Sans, Ubuntu_Sans_Mono, Average } from "next/font/google";

const sans = Ubuntu_Sans({
  variable: "--font-ubuntu-sans",
  subsets: ["latin"],
});
const mono = Ubuntu_Sans_Mono({
  variable: "--font-ubuntu-sans-mono",
  subsets: ["latin"],
});
const serif = Average({
  variable: "--font-average",
  weight: "400",
  subsets: ["latin"],
});

const fonts = `${sans.variable} ${mono.variable} ${serif.variable}`;

<html className={`${fonts} font-sans`}>

If you use a coding agent

The package ships an llms.txt alongside its dist/: the public API, the rules, and the common mistakes that leave a build looking fine. One line is enough to point an agent at it, so it stops writing text-sm text-muted-foreground when a primitive already exists.

# CLAUDE.md, AGENTS.md, or your agent's equivalent

@node_modules/@supertype.ai/foundations/llms.txt

Coding agents covers what is in the file, how it stays current, and the lint rules and doctor run that catch what it misses.

Contrast you can check

A WCAG ratio scores both polarities alike. Swap the ink and the ground and it reports the same figure, while on screen dark glyphs on a bright field thin out and light glyphs on a dark field bloat. The two specimens below carry the same ratio to a tenth, both clear AA, and read half a ramp apart.

Six weeks after the migration the queue drained on its own, which nobody had predicted and nobody could explain.

Lightratio 4.87:1 · Lc 70.9

Six weeks after the migration the queue drained on its own, which nobody had predicted and nobody could explain.

Darkratio 4.79:1 · Lc 34.6

So the package measures its palette twice. contrast answers the compliance question and lc answers the design one: whether your secondary ink is meaningfully quieter than your primary, and whether it survived the trip to dark. Both read the resolved cascade, so what gets measured is the page a browser paints.

3.44:1

Light

6.75:1

Dark

WCAG ratio, tertiary ink

The dark theme measures nearly twice the light one.

59.5

Light

47.8

Dark

Lc, the same two inks

Polarity-aware, so it ranks them the other way.

4.5:1

Read

3:1

Marks

Floors held in CI

Both themes, every release.

checkLegibility and checkSignals hold those floors across both themes in CI. Every figure above was computed at build time from the stylesheet this site installs, including the two ratios in that row: the same tertiary ink measures 3.44:1 in light and 6.75:1 in dark, and reads 59.5 Lc against 47.8. Two measures has the maths and the call sites.

What is in here

The written reference lives in the repo: the README and docs.

In production

Sites running the package. Both install it from a tag, the way the instructions above describe, so you are seeing these components at full size on real content.