Skip to content
Vitops
GuidesComponentsPackagesThemeReferenceChangelog

Start here

VitopsInstallationYour design systemYour config

Live preview

Theme previewAnimation libraryIconsPatterns

Components

OverviewCSS classesWeb componentsAstro componentsBricks elements

Packages

@getvitops/cli@getvitops/astro@getvitops/vite@getvitops/generator@getvitops/core@getvitops/utils@getvitops/emdash@getvitops/create

Reference

Config referenceOutput formatsColour systemType & space scalesComponent patternsIconsConsent gateConversion trackingSearchLegal documentsCSS class vocabularyBricks elements

Releases

Changelog

Your design system

How design-system.json is structured — colours, scales, patterns and animations — and what each section generates.

What each section drivesColours are seeded, not enumeratedPatterns are declarative

design-system.json is the only file you edit. Everything the toolchain emits is derived from it, and the JSON Schema is published so editors give you autocomplete and hover docs:

{
  "$schema": "./node_modules/@getvitops/generator/schema.json"
}

vitops init stamps that for you.

What each section drives

Section Generates
colors 11-step OKLCH scales per hue, functional role tokens, automatic dark mode, colour utilities
typeScale / spaceScale Fluid modular scales as clamp() steps
typography Font families and semantic type roles → font-<role> utilities
patterns Component CSS (.cta, .btn, .card, .badge, …) plus the token cascade
animations Effect and journey classes, layered over the hand-written animation engine
shadows --shadow-<name> tokens and .drop-shadow-<name> utilities

The Config reference documents every field, rendered from the schema itself — so it can’t fall out of step with what validation accepts. The token fields are under designSystem; filter the tree to jump to one.

Colours are seeded, not enumerated

You give a hue a seed; the generator derives the full scale and the functional tokens over it.

{
  "colors": {
    "palette": { "pine": { "seed": "#4A9075" } },
    "roles": { "brand-primary": "pine", "ui-primary": "pine" }
  }
}

That yields --color-pine-50 … 950 on the shared lightness ladder, plus role tokens named --color-<target>-<role>[-<variant>] (--color-bg-brand-primary-solid, --color-text-on-brand-primary, --color-text-brand-primary, …) and matching utilities — the class name is the token name minus --color-. Dark mode re-points which step each token reads, not a second palette you maintain. Contrast targets — text at APCA Lc ≥ 75, secondary ≥ 60, icons and boundaries ≥ 45, in both appearances — are enforced at build time, so a violation fails generate rather than shipping.

A role is either kind: "surface" (a page or panel colour, with a bare bg-<role>) or chromatic — the default, and what the bare-string form above means — whose backgrounds split into tints and solids with no bare bg-<role>.

See Colour system for the full model.

Patterns are declarative

A pattern is base declarations, interaction states, and semantic role variants:

{
  "cta": {
    "group": "control",
    "class": "cta",
    "fill": true,
    "default_role": "ui-primary",
    "overrides": { "p": "0.75em 1.5em" },
    "base": { "padding": "var(--p-cta-group)", "font-weight": "600" },
    "states": { "hover": { "step": 1, "lift": "1px" }, "active": { "scale": 0.97 } },
    "roles": ["success", "danger", "warning", "info"]
  }
}

Two things worth internalising:

  • Geometry resolves through the group alias layer. Write var(--p-cta-group), not var(--p-control, 0.75em). Both render the same, but the first keeps the pattern → group mapping in CSS where you can inspect and change it in devtools. The chain is --p-cta (your override hook) → --p-cta-group → --p-control → --p-default.
  • element + class emit one zero-specificity rule. "element": "button", "class": "btn" produces :where(button, .btn), so a bare <button> is styled with no class, .btn carries the styling to any other tag, and any explicit class overrides it without !important.

See Component patterns for the full cascade.

Built with the design system it documents.

@getvitops on npm