A token-first React UI kit. Every margin, padding, and control height comes from one shared scale, so everything lines up by construction. The visual language follows modern Apple design: generous padding, capsule controls, and translucent glass materials.
| Package | What it is |
|---|---|
@glacier/tokens |
Source of truth: OKLCH 12-step color ramps + semantic layer, glass materials + blur, fluid space scale, modular type scale, radius ramp, elevation, motion tokens, density. TypeScript in, css/tokens.css out. |
@glacier/motion |
The micro-animation vocabulary as real TS enums (Motion, Speed, Ease, Spring) with framer-motion presets (motionProps, springTransition, press, lift). |
@glacier/react |
React 19 components styled with CSS Modules over semantic tokens only, organized by atomic design. Atoms: Button, IconButton, Input, Checkbox, Radio, Switch, Card, Surface, Text, Heading, Label, Link, Kbd, Pill, Divider. Molecules: Field, Select, SegmentedControl. Organisms: Modal. |
@glacier/icons |
Reserved for the icon set. |
apps/docs |
Custom Vite docs app: live token galleries, motion playground, per-component documentation with copy-paste examples and props tables, theme + density toggles. |
npm install # once, at the repo root
npm run gen # regenerate css/tokens.css after editing token source
npm run dev # docs app at http://localhost:5199
npm test # vitest: token math + component behavior + axe checks
npm run test:visual # playwright screenshot regression (needs: npx playwright install chromium)- No raw values in components. Every color, size, radius, duration comes from a
--glacier-*token. If a value isn't a token, it doesn't ship. - Components consume the semantic layer, never ramp steps. Themes flip underneath.
- Spatial values come off the space scale. Control heights come from
--glacier-control-height-*so mixed rows always align. - Motion is enum-only. Pick from
Motion/Speed/Ease/Spring; never hand-roll a duration. - Edit tokens in TypeScript (
packages/tokens/src), thennpm run gen. Never edittokens.cssby hand. - Atomic direction only. Atoms never import from molecules or organisms; shared contracts
(like the Field context) live in
internal/. - No aliased imports. Write
motion, notmotion as m;styles, nots.
data-theme="light" | "dark"on<html>(defaults toprefers-color-scheme)data-density="compact"for dense UIs--glacier-radius-scaleto sharpen/soften every corner globally- Accent is the
accentramp inpackages/tokens/src/color.ts- retune once, everything follows.