@zumer/orbit-kit
v0.1.0
Published
High-level, declarative web components on top of the Orbit CSS framework — gauges, charts, activity rings, knobs, pie menus, cockpit instruments, analog clocks, compasses and radars, each in one tag.
Maintainers
Readme
@zumer/orbit-kit
High-level, declarative web components built on top of the Orbit CSS framework.
Orbit gives you primitives — a CSS engine for radial layout. It's powerful,
but composing a single widget means nesting five levels
(.bigbang > .gravity-spot > .orbit-N > .satellite > .capsule) and getting the
rules exactly right. That depth is the main barrier to entry, for humans and
for LLMs.
orbit-kit wraps the common radial patterns into one-line custom elements — gauges, charts, activity rings, knobs, pie menus, cockpit instruments, analog clocks, compasses and radars:
<!-- Before: raw primitives -->
<div class="bigbang" style="width:200px;aspect-ratio:1">
<div class="gravity-spot">
<div class="orbit-4" style="--o-range:270deg;--o-from:225deg">
<o-progress value="72" shape="rounded"
style="--o-fill:#6366f1;--o-stroke-width:8"></o-progress>
</div>
<div class="orbit-0">
<div class="satellite at-center"><div class="capsule">72%</div></div>
</div>
</div>
</div>
<!-- After: orbit-kit -->
<o-gauge value="72" unit="%"></o-gauge>Install
npm install @zumer/orbit @zumer/orbit-kitimport '@zumer/orbit/style' // Orbit CSS engine
import '@zumer/orbit' // Orbit core web components (<o-arc>, <o-progress>)
import '@zumer/orbit-kit' // registers every kit componentOr straight from a CDN — no build step:
<link rel="stylesheet" href="https://unpkg.com/@zumer/orbit@latest/dist/orbit.css">
<script src="https://unpkg.com/@zumer/orbit@latest/dist/orbit.js"></script>
<script type="module" src="https://unpkg.com/@zumer/orbit-kit@latest/src/orbit-kit.js"></script>@zumer/orbit is a peer dependency — the kit assumes the Orbit core (CSS +
<o-arc> / <o-progress>) is present on the page.
Every component is a standard custom element, so it works in plain HTML and in any framework (React, Vue, Svelte, Angular). Import the whole kit, or just the components you use:
import '@zumer/orbit-kit/src/o-gauge.js'
import '@zumer/orbit-kit/src/o-clock.js'Components
| Tag | What it is |
|-----|------------|
| <o-gauge> | Single-value radial gauge |
| <o-donut> | Data-driven donut / pie chart |
| <o-rings> | Apple-style concentric activity rings |
| <o-knob> | Interactive rotary control (drag / wheel / keys) |
| <o-menu> | Radial / pie menu — single- & multi-level |
| <o-instrument> | Cockpit / dashboard gauges (tach, speedo, fuel, airspeed…) |
| <o-clock> | Analog clock / watch face — the flagship |
| <o-compass> | Heading indicator |
| <o-radar> | Radar / scope display |
Common conventions across the kit:
sizesets the widget's pixel width (square aspect). Components scale Orbit's--o-forceinternally so they actually fill that box.glowis an opt-in neon drop-shadow tinted with the indicator color (gloworglow="12"for the blur radius).data/items/zones/targetstake a JSON array in the attribute.- Set attributes to update live (
el.setAttribute('value', 88)); interactive components also expose JS properties and events.
<o-gauge>
A single value on an arc, with a center readout.
<o-gauge value="72" unit="%"></o-gauge>
<o-gauge value="125" max="240" label="125 km/h" range="360" glow></o-gauge>| Attribute | Default | Description |
|---|---|---|
| value | 0 | Current value. |
| max | 100 | Value that fills the whole arc. |
| range | 270 | Arc span in degrees (360 = full ring, 180 = semicircle). |
| from | auto | Start angle; defaults so the gap sits at the bottom. |
| size | 200px | Widget width. |
| label | — | Center text; overrides the auto value+unit. |
| unit | "" | Suffix on the value (%, km/h). |
| fill | #6366f1 | Progress color. |
| track | #262d38 | Background ring color. |
| stroke-width | 8 | Ring thickness. |
| shape | rounded | Arc cap shape (rounded, none). |
| glow | off | Neon glow on the progress arc. |
<o-donut>
A donut / pie chart from a JSON data array. Values are normalized to their sum,
or to an explicit total for a partial ring.
<o-donut label="$2.4k"
data='[{"value":52,"color":"#f97316","label":"Rent"},
{"value":28,"color":"#eab308"},
{"value":20,"color":"#22c55e"}]'></o-donut>| Attribute | Default | Description |
|---|---|---|
| data | [] | [{ value, color?, label? }]. Colors fall back to a palette. |
| total | sum | Denominator; set it for a partial ring (e.g. total="100"). |
| range / from | 360 / 0 | Arc span and start angle. |
| stroke-width | 14 | Ring thickness. |
| gap | 2 | Spacing between segments. |
| shape | none | Segment caps (none, or rounded to opt in). |
| track | faint | Background ring color. |
| label / unit | — | Center text. |
| glow | off | Neon glow per segment. |
<o-rings>
Apple-style concentric activity rings (outer ring first). Each ring gets a dim, solid track in its own color.
<o-rings data='[{"value":80,"color":"#fa114f"},
{"value":55,"color":"#a3ff00"},
{"value":92,"color":"#00fff0"}]'></o-rings>| Attribute | Default | Description |
|---|---|---|
| data | [] | [{ value, max?, color?, label? }]. |
| range / from | 360 | Arc span and start angle. |
| stroke-width | 12 | Ring thickness. |
| step | 1 | Orbit gap between rings. |
| track | auto | Track color (defaults to a dim wash of each ring's color). |
| shape | rounded | Cap shape. |
| label / unit | — | Center text. |
| glow | off | Neon glow per ring. |
<o-knob>
An interactive rotary control that behaves like a form input.
<o-knob value="65" unit="%" fill="#3da9fc"></o-knob>knob.addEventListener('input', e => console.log(e.detail.value)); // while dragging
knob.addEventListener('change', e => console.log(e.detail.value)); // on release
knob.value = 40; // read / writeDrag vertically, scroll the wheel, or use arrow keys / Page Up·Down / Home·End
when focused. role="slider" + ARIA values are set for you.
| Attribute | Default | Description |
|---|---|---|
| value | min | Current value. |
| min / max | 0 / 100 | Range. |
| step | 1 | Increment for keys / wheel and snapping. |
| range / from | 270 / auto | Arc span and start angle. |
| size | 160px | Widget width. |
| fill | #a1a1aa | Value color. |
| track | #27272a | Track color. |
| stroke-width | 14 | Ring thickness. |
| unit / label | — | Center readout. |
| disabled | off | Non-interactive + dimmed. |
| glow | off | Neon glow on the value arc. |
<o-menu>
A radial / pie menu. Items may nest via children for multi-level menus, with
two ways to reveal a branch.
<o-menu label="EDIT" expand="concentric"
items='[
{"label":"Size","icon":"🔠","children":[
{"label":"Bigger","value":"size.up"},
{"label":"Smaller","value":"size.down"}]},
{"label":"Format","icon":"✏️","children":[
{"label":"Bold","value":"fmt.bold"},
{"label":"Italic","value":"fmt.italic"}]},
{"label":"Color","icon":"🎨","value":"color"}]'></o-menu>menu.addEventListener('select', e => e.detail); // { value, label, item, path }
menu.addEventListener('navigate', e => e.detail); // { path, depth }
menu.back(); menu.reset(); menu.path; // navigation API| Attribute | Default | Description |
|---|---|---|
| items | [] | [{ label, value?, color?, icon?, children? }] (recursive). |
| expand | drill | drill (ring replaces itself, center = back) or concentric (parent stays, children fan out — the editor look). |
| theme | mono | mono (slate sectors tinted by accent on hover/active) or color (refined per-item palette). |
| accent | #3da9fc | Accent for the mono theme. |
| range / from | 360 | Arc span and start angle (270 for a quick action wheel). |
| size | 280px | Widget width. |
| gap | 6 | Spacing between sectors. |
| label | MENU | Center / breadcrumb text. |
Keyboard: arrows move focus, Enter activates, Esc / Backspace goes back.
<o-instrument>
Cockpit / dashboard gauges with major + minor ticks, color zones, a redline, a numeric scale, a needle and a digital readout. Driven by presets, or configured by hand.
<o-instrument preset="tachometer" value="6.2"></o-instrument>
<o-instrument preset="airspeed" value="120"></o-instrument>
<o-instrument min="0" max="100" value="40" unit="%" label="LOAD"
zones='[{"from":85,"to":100,"color":"#ef4444"}]'></o-instrument>Presets: tachometer, speedometer, fuel, temp, boost, voltmeter,
airspeed, altimeter, cpu, gpu, vu. Any attribute below overrides the
preset.
| Attribute | Default | Description |
|---|---|---|
| value | min | Current reading. |
| min / max | 0 / 100 | Scale range. |
| range / from | 270 / auto | Arc span and start angle. |
| ticks | 7 | Major tick / label count. |
| minor | 5 | Minor ticks between each pair of majors. |
| zones | [] | [{ from, to, color }] color bands (in value units). |
| redline | — | Sugar: a red zone from this value to max. |
| tick-labels | numeric | Custom scale labels, e.g. '["E","½","F"]'. |
| unit / label | — | Readout unit and caption. |
| digital | on | Show the numeric readout. |
| case | auto | round, square, rounded, or bare (auto for ≤180° arcs). |
| accent / needle-color / tick-color / face / bezel | — | Theming. |
| size | 240px | Widget width. |
| glow | off | Neon glow on the needle / zones. |
<o-meter>(a basic speedometer) still ships for back-compat but is superseded by<o-instrument preset="speedometer">.
<o-clock>
The flagship: an analog clock / watch face. Live or static, with case shapes, an oval (tonneau) dial, numerals, smartwatch complications, chronograph sub-dials, and an iOS activity-rings face.
<o-clock live seconds></o-clock> <!-- ticking wall clock -->
<o-clock time="10:08:42" numerals="roman" case="square"></o-clock>
<o-clock preset="smartwatch" live brand="ORBIT"></o-clock>
<o-clock preset="chrono" live></o-clock> <!-- tri-compax sub-dials -->
<o-clock case="rectangle" dial="oval" live smooth></o-clock> <!-- tonneau -->
<o-clock dial="rings" live seconds></o-clock> <!-- iOS activity-ring clock -->Presets: classic, roman, minimal, chrono, smartwatch.
| Attribute | Default | Description |
|---|---|---|
| time | now | Static HH:MM[:SS]. Omit for the current time. |
| live | off | Tick with the real clock. |
| smooth | off | Sweeping (not ticking) second hand; implies seconds. |
| seconds | off | Show a second hand. |
| numerals | arabic | arabic, roman, or none. |
| case | round | round, square, rounded, rectangle. |
| dial | round | round, oval (tonneau, matches the case), or rings (iOS face). |
| digital / date / brand | off / off / — | Complications. |
| subdials | off | Chronograph sub-dials (small-seconds / 24h / date). |
| accent / hand-color / tick-color / face / bezel / case-bg | — | Theming (also via CSS vars, e.g. --ok-clock-accent). |
| size | 300px | Widget width. |
| glow | off | Neon glow on the hands. |
<o-compass>
A heading indicator: a fixed dial with a top lubber index; the card (ticks +
cardinals) rotates so the current heading sits under the index.
<o-compass heading="045"></o-compass>
<o-compass heading="120" labels="N,NE,E,SE,S,SW,W,NW"></o-compass>| Attribute | Default | Description |
|---|---|---|
| heading | 0 | Heading in degrees (clockwise from North). |
| labels | N,E,S,W | Cardinal labels (comma-separated). |
| fill | #ef4444 | Accent (north tick + lubber). |
| unit | ° | Readout suffix. |
| size | 220px | Widget width. |
<o-radar>
A radar / scope: concentric range rings, cross-hair spokes, a rotating conic-gradient sweep, and glowing blips.
<o-radar rings="4" spokes="12" label="SCAN"
targets='[{"angle":60,"dist":0.8},
{"angle":200,"dist":0.45},
{"angle":310,"dist":0.65,"color":"#ef4565"}]'></o-radar>| Attribute | Default | Description |
|---|---|---|
| targets | [] | [{ angle, dist, color? }] — angle °CW from top, dist 0–1. |
| rings | 4 | Concentric range rings. |
| spokes | 8 | Radial cross-hair lines. |
| sweep | on | The rotating beam (sweep="false" to hide). |
| sweep-width | 110 | Beam span in degrees. |
| speed | 4 | Seconds per revolution. |
| color | #22d3ee | Scope color. |
| label | — | Center label. |
| size | 240px | Widget width. |
How it works
orbit-kit components render their structure into the light DOM (not shadow
DOM) on purpose. Orbit positions elements through global CSS (cos() / sin()
/ :has()) and inherited --o-* custom properties, so a layout-composing
component must live in the light DOM for the engine and the cascade to reach it.
The generated markup is exactly the documented Orbit structure — "view source"
stays honest. Inspect any component in devtools to see the rings, satellites and
arcs it expands into.
Everything is theme-able through plain CSS custom properties; the convenience attributes above just map onto them.
Examples
Live showcase of every component: zumerlab.com/orbit-kit
(source in docs/index.html).
To run it locally, serve the repo over HTTP so the ES modules load:
npx serve .
# then open /docs/index.htmlBrowser support
Modern evergreen browsers. Orbit relies on :has() and CSS trigonometric
functions (cos, sin); the radar/clock visuals use conic-gradient and
color-mix. Orbit shows an upgrade notice on unsupported browsers.
