Hourglass
A monochrome design system: one set of tokens and 23 components, built eight times over so any project can take the one that matches its framework.
Every library is standalone. One command copies the folder into your repository and it works — no package to install, no build step, no configuration, and no dependency beyond the framework itself. See Installation.
The eight libraries
| Library | Dependencies | Notes |
|---|---|---|
| lib/html | None | Plain HTML, CSS and a little vanilla JavaScript. The canonical web implementation. |
| lib/react | react | TypeScript components for React 18+. |
| lib/nextjs | next, react | The React set, generated with "use client" where the App Router needs it. |
| lib/vue | vue | TypeScript single-file components for Vue 3.5+. |
| lib/svelte | svelte | Svelte 5, using runes. |
| lib/angular | @angular/core, @angular/common | Standalone components, signal inputs, OnPush. |
| lib/webcomponents | None | Native custom elements. Work in any framework, or none. |
| lib/reactnative | react, react-native | Core Animated only — no Reanimated, Skia, SVG or gesture library. |
What is in the box
- Tokens — colour (OKLCH with an sRGB fallback, light and dark), type, spacing, radius, elevation, motion and hit targets, as CSS custom properties, a typed TS object, a React Native theme, and an optional Tailwind preset.
- 23 components — actions, forms, controls, content, data and overlays. Every one of them in every library.
- One implementation per concern.
lib/html/hourglass.cssis the web stylesheet; the six web libraries all render the samehg-*markup, so a border radius is decided once rather than six times. The reel engine and the calendar arithmetic are shared the same way.
The rules the components follow
- Generic and stateless. Presentational only — no data fetching, no domain types, no knowledge of what the app is for.
- Controlled. A component takes its value as a prop and reports what the user asked for; it never owns the state it displays. A control that flips itself becomes a second copy of your state, and the two disagree the first time a save fails.
- Nothing formats anything. Durations, currencies and dates arrive as text you have already formatted, because all three differ per locale.
- Monochrome.
accentis near-black in light and near-white in dark — the same neutral scale, not a hue. Status is never colour-coded: an icon, a label and weight carry it, which survives printing, screenshots and screen readers. - Framework-native. React Native uses the built-in
AnimatedAPI, not Reanimated or Skia. The web uses CSS transitions and inline SVG, not a motion or charting library. - Accessible. 4.5:1 body and 3:1 large text in both modes, 44/48px hit targets, visible focus rings, and spoken labels on every mono numeral.
Repository layout
chronsyn/ui
├── tokens/ tokens.json · CSS custom properties · TS theme · RN theme · Tailwind preset
├── shared/ reel.ts (the odometer engine) · datetime.ts (calendar arithmetic)
├── tools/ sync.mjs (write the copies) · verify.mjs (fail if they drift)
├── docs_src/ this site
├── docs/ this site, built
└── lib/
├── html/ react/ nextjs/
├── vue/ svelte/ angular/
└── webcomponents/ reactnative/
Why the duplication is deliberate. Each library carries its own copy of the theme,
because a folder you can drop somewhere cannot reach back up to a shared parent.
tools/sync.mjs writes those copies from tokens/, and
tools/verify.mjs fails if one has been edited in place, if a library imports something
it may not have, or if the CSS and tokens.json disagree.
Fonts
The system asks for Inter (display and body) and JetBrains Mono , and falls back to the platform's own faces if they are not loaded. No font files ship with it — a folder you copy into someone else's project has no business carrying licensed binaries.
The mono is not a code style here. Every numeral, time, duration, eyebrow and caption is set in it; it is the loudest signal the system has.
Next
Installation — how to get the library for your framework into a project.
Design system — the foundations, and the decisions behind them.
Tokens — every value, and the name it answers to.
Components — all 23, with props, types and code samples.
github.com/chronsyn/ui — the source.