Open Analytics' design language, extracted from the shipped product: an ink-derived neutral system, squircle surface anatomy, one small spring vocabulary, pixel-matched skeletons, and a plain-spoken copy voice, with type-checked component recipes. Use this whenever you build or restyle a dashboard, SaaS app, analytics UI, settings screen, onboarding flow, or marketing/landing page that should feel calm, dense and native, and whenever the user mentions Open Analytics' look, 'clean SaaS design', cards, dropdowns, tab bars, empty states, skeletons, or UI animation quality, even if they never say the words 'design system'.
npx skills add https://github.com/OpenLabs-so/oa-design --skill oa-design
The design language of Open Analytics, written down so
an agent can reproduce it. Nothing here is aspirational: every value is
lifted from the shipped product, springs and hex codes included.
The look in one sentence: **white surfaces with continuous-curvature corners,
resting on a quiet grey stage, drawn in a single ink, moved by a single
spring.**
Start by dropping _root.css into the project's global stylesheet: every
recipe reads from those token names. Then read the recipe for what you are
building. Build with real content, never lorem.
--ink, mixed into transparency at fixed percentages: borders 12%, hover
washes 5%, inputs 14%. Never introduce a second grey; when you need a new
neutral, mix ink.
holding a recessed grey inset; sections are plates and the page background
between them is the only divider. No horizontal rules.
continuous-curvature corners; everything clickable that is not a card is a
pill. A rounded-lg rectangle is the smell of a foreign component.
below). Do not invent an eighth.
swaps from a pixel-matched skeleton, arriving by blur, not by pop.
Hierarchy comes from size, color and spacing. Data aligns with
tabular-nums; code is Geist Mono.
the primary chart line; semantic colors are text tints, never fills.
non-dismissable strips or pills that live exactly as long as the state;
one-off outcomes are toasts that retire alone.
errors name the cause and the way out, without blame. Read _copy.md.
10. Quality floor, always. Focus rings, role="status", aria-hidden
decorations, prefers-reduced-motion, no horizontal page scroll.
| Name | Value | Used for |
| --- | --- | --- |
| PANEL | 550 / 38 | dropdowns, menus, boards, toggles |
| LAYOUT | 550 / 40 | measured height/width, traveling pills |
| POP | 400 / 26 | modal entrance |
| POP_EXIT | 380 / 28 | modal exit |
| BANNER | 400 / 30 | floating pills, page banners |
| FLICK | 900 / 50 | icon micro-moves |
| CHART | 300 / 28 | chart tooltips, crosshair |
Micro fades: 0.1s out, 0.16s in, easeOut; nothing in app chrome tweens past
0.2s. The constants ship as code in components/_lib/springs.ts.
Each recipe is self-contained: when to use it, the load-bearing details, and
the full type-checked source embedded.
| File | What |
| --- | --- |
| 01-squircle-card.md | the surface system and the fixed-height mini card |
| 02-button.md | pills that press, the bevel, honest loading |
| 03-dropdown.md | menus, selects, switchers; one anchored-panel pattern |
| 04-tab-bar.md | the traveling highlight and the label mask |
| 05-modal.md | pop in, softer pop out |
| 06-multi-step-dialog.md | the measured-height choreography |
| 07-skeleton.md | pixel-matched waits and the blur arrival |
| 08-notice-strip.md | explaining a standing state |
| 09-floating-pill.md | the app chrome's one word |
| 10-toast.md | success pulses, error shakes |
| 11-header-morph.md | the landing glass pill |
| 12-reveal.md | scroll reveals in 80ms beats |
| File | What |
| --- | --- |
| _tokens.md | the full palette, dark theme, type, radius, shadows |
| _layout.md | plates, widths, page anatomy, settings screens |
| _components.md | the component patterns in prose, cross-referenced |
| _motion.md | the vocabulary and the signature moves, with rules |
| _landing.md | marketing pages: hero, reveals, furniture |
| _copy.md | voice, buttons, errors, states, numbers |
| _root.css | the installable token block every recipe reads from |
Stack assumptions: React + Tailwind v4 + the motion package; but every
value is plain CSS numbers and spring constants, so port freely. If the
project already has a design system, theirs wins; use this to fill gaps, not
to overwrite their identity.
Take openlabs-so/oa-design from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.