npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orbias/elements

v0.3.0

Published

Orbias Elements — embeddable Surface B custom elements (ADR-0008).

Readme

@orbias/elements

Embeddable web components that render live Orbias device state — machine status, consumable levels, uptime — on any web page, with data-freshness honesty built in. Framework-agnostic (built on Lit): drop a custom element into plain HTML, React, Vue, or Svelte — no rendering or polling logic to re-implement.

Status: 0.x — pre-stable. The component API and the --oe-* theming token contract are still forming and may change on a minor bump. Pin with ^0.3 and expect 0.x minors to break. The real-time stream transport is beta.

Migrating from 0.2.x. 0.3.0 fixes a --oe-* self-reference cycle that silently prevented published defaults from ever applying. If you relied on the previously-broken (unstyled/un-inherited) rendering, set the --oe-* tokens you need explicitly; otherwise you'll now see the documented defaults — including a new prefers-color-scheme: dark step — for the first time.

Install

npm install @orbias/elements @orbias/client

@orbias/client is a peer dependency: the components render off a client instance you inject, so a page with several elements opens one authenticated connection rather than one per component.

Quick start

Register the elements once, create a client, and share one live stream across every element on the page:

import { createOrbiasClient } from "@orbias/client";
import { defineOrbiasElements, ClientDeviceStream } from "@orbias/elements";

// 1. Register the <orbias-*> custom element tags (idempotent — call once).
defineOrbiasElements();

// 2. One client + one stream, shared by every element.
const client = createOrbiasClient({ baseUrl: "https://api.orbias.com/v1" });
const stream = new ClientDeviceStream(client, {
  // The token must carry the `stream:subscribe` scope.
  headers: { authorization: `Bearer ${token}` },
});

// 3. Point each element at a device and hand it the shared stream.
const el = document.querySelector("orbias-machine-status");
el.stream = stream;
<orbias-machine-status device-id="dev_a1b2c3"></orbias-machine-status>

An element subscribes when it connects, re-subscribes if you change device-id or stream, and tears the subscription down when it's removed from the DOM.

Components

Device tiles — one device stream each, freshness-honest:

| Tag | Renders | | --------------------------- | ----------------------------------------- | | <orbias-machine-status> | A machine's running / idle / fault status | | <orbias-consumable-level> | A consumable's remaining level | | <orbias-uptime-tile> | A derived uptime figure |

Composition components — the "thread family" (Surface B/C), for building a portal on your own tokens. They take record-shaped data via properties and invent nothing: no data renders a stated empty state, never a placeholder.

| Tag | Renders | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | <orbias-timeline> | A timeline of events — refuses any entry without a person and a time | | <orbias-thread> | A thread (order / visit / alert) with its messages, under the same gate | | <orbias-waiting-on> | What is waiting on whom, grouped by who has to act, counted | | <orbias-site-card> | A site card built only from record fields (no free-text) | | <orbias-room-card> | A room's assets and latest cited reading, freshness-honest | | <orbias-compliance-pack> | Compliance packs — a verified mark set by the record, never the portal | | <orbias-approval> | A one-tap approve / decline; emits orbias-approval, the portal writes | | <orbias-ask-for-help> | The embedded "Need help?" card — three verbs, carries the site card, emits orbias-ask-for-help, the host opens the thread | | <orbias-room-free> | Room occupancy (free / in-use) from entry/exit counts, per-room honesty, counts never identities |

The composition components carry the same honesty gates in code: a timeline or thread drops (and visibly counts) any entry missing a person or a time; a compliance pack shows "Verified" only when the record carries a signer, a time and a measurement source — there is no portal-facing way to set the mark; an approval never manufactures a decision stamp, and the Approve / Decline buttons dispatch an orbias-approval event for the host to act on; an ask-for-help card only renders its confirmation stamp once a receipt names who raised the request and when. Every one renders on tokens v5 and on a tenant's tokens with no code change (the --oe-* contract below) and uses tabular numerals throughout; the two that take a live reading — <orbias-site-card> and <orbias-room-card> — also carry the stale de-ink signature when their freshness goes stale.

Spatial components (FOR-883, v0) — a background image + declarative pins, binding to a device id or an estate-node id (FOR-811: operator/site/space/ asset), never a tag:

| Tag | Renders | | ------------------------ | -------------------------------------------------------- | | <orbias-image-overlay> | An SVG/PNG background with pinned tiles positioned by id |

<orbias-image-overlay> positions — it does not re-implement — a value tile: pass any existing device tile or composition component as a light-DOM child with slot="pin" and a data-pin-id matching a key in the element's pins map ({ [id]: { x, y } }, percentage offsets over the background image). The slotted tile keeps its own honesty machine, freshness, and attribution untouched; a pin id with no matching map entry stays visible and is counted in a refused note, never silently dropped. The element exposes ::part(root | canvas | image) for host chrome. See demo/image-overlay.html.

<oe-floorplan>/<oe-map> (true 2D/3D floorplan and map rendering) are deferred behind an external-provider seam rather than an in-house spatial editor (Akenza's precedent: smplrspace.com). Not built in this pass: the provider exists and ships a JS SDK (verified via its GitHub org), but its concrete integration contract — auth model, the actual data-layer API, and whether the specific device-binding pattern is real — is UNVERIFIED (its docs site was unreachable from this session's network). See the comment at the bottom of src/spatial/image-overlay.ts.

Data-freshness honesty

Every component surfaces one of four freshness states — fresh · delayed · stale · offline — derived from server-authoritative timestamps, never a local clock. The indicator carries colour and glyph and text (plus a screen-reader description), so it survives an arbitrary theme: a host can recolour it via the state tokens (--oe-ok / --oe-warn / --oe-bad) but cannot hide it or drop the label. If a device goes quiet or the stream drops, the component visibly ages to stale / offline on its own — and the stale/offline states de-ink the value and dash the card border, so a reading is never dressed as current.

Theming

Style everything through --oe-* CSS custom properties — no shadow-DOM piercing and no subclassing. Map your design tokens onto the surface in one stylesheet:

orbias-machine-status {
  --oe-surface: var(--card-bg);
  --oe-surface-2: var(--card-well);
  --oe-ink: var(--card-fg);
  --oe-muted: var(--card-muted);
  --oe-dim: var(--card-dim);
  --oe-ok: var(--good);
  --oe-warn: var(--warn);
  --oe-bad: var(--danger);
  --oe-accent: var(--brand);
  --oe-radius: 12px;
  --oe-font: var(--font-sans);
  --oe-mono: var(--font-mono);
}

Tokens may be set on the element itself (as above) or on any ancestor — custom properties inherit across the open shadow boundary. Internally the stylesheets read a private --_oe-* mirror of each token; that name is an implementation detail, never set it.

The full token contract — --oe-surface, --oe-surface-2, --oe-ink, --oe-muted, --oe-dim, --oe-line, --oe-ok, --oe-warn, --oe-bad, --oe-interpreted, --oe-accent, --oe-accent-fg (the label ink on the accent), --oe-action-border (the secondary button's ≥3:1 boundary), --oe-target-min (the touch-target floor calibration raises), --oe-radius, --oe-font, --oe-font-size, --oe-mono, --oe-space, --oe-motion-duration — is what a host maps once, at the embed boundary. Defaults render sensibly on a bare page and meet 4.5:1 contrast. ::part(root | body | attribution) are exposed for host chrome; the honesty indicator deliberately is not.

Token meanings:

  • --oe-surface — the primary background (card / panel).
  • --oe-surface-2 — a secondary surface, used for wells, insets, and layered backgrounds.
  • --oe-ink — primary text colour (headings, values).
  • --oe-muted — secondary text colour (sublines, captions, helper text). Verified ≥4.5:1 contrast.
  • --oe-dim — lowest-contrast informative colour (stale/offline state ink). Verified ≥4.5:1 contrast.
  • --oe-line — UI borders (cards, dividers). Verified ≥3:1 non-text contrast.
  • --oe-ok, --oe-warn, --oe-bad — semantic state colours (freshness honesty states).
  • --oe-accent — brand / accent colour.
  • --oe-radius — corner rounding (cards, buttons).
  • --oe-font — primary typeface (typically a sans-serif system stack).
  • --oe-mono — monospace typeface (for room refs, ids, technical values).
  • --oe-space — base spacing unit (margins, padding, gaps).
  • --oe-motion-duration — transition timing (animations, honesty state changes).

Token migration (0.1.x → 0.2.0). The theming tokens were renamed to the canonical Surface B contract. Update any host token map:

| Old (0.1.x) | New (0.2.0) | | ---------------------------- | -------------- | | --oe-color-surface | --oe-surface | | --oe-color-foreground | --oe-ink | | --oe-color-muted | --oe-muted | | --oe-color-accent | --oe-accent | | --oe-color-honesty-fresh | --oe-ok | | --oe-color-honesty-delayed | --oe-warn | | --oe-color-honesty-stale | --oe-bad | | --oe-color-honesty-offline | --oe-dim |

New tokens added: --oe-surface-2, --oe-dim, --oe-line, --oe-mono. The accent default changed from blue to a quiet teal (#0e6e63). --oe-font, --oe-radius, --oe-space and --oe-motion-duration are unchanged.

Dark mode (FOR-915)

Every component ships a @media (prefers-color-scheme: dark) default step for the --oe-* colour tokens — the OS preference selects it; nothing flips it by script. A host-set token (on the element or any ancestor, in either scheme) always wins, because the dark step only changes what an UNSET token falls back to. To force one value in both schemes, set it explicitly:

orbias-machine-status {
  --oe-surface: #131417; /* wins over both the light and dark default */
}

The dark step is the estate's existing --oe-* dark palette (the tenant sign-in theme): surface #131417, ink #f7f8f8, muted #8a8f98, honesty #4ecb8f / #e8a33d / #df5b5b. --oe-accent is not restepped — the estate has one accent (#5e6ad2, FOR-1061), which clears 3:1 as a mark on the dark surface. Every pair is measured by bun run gate:contrast.

Calibration (FOR-915)

calibration is a property (and reflected attribute) on every component — device tile or thread-family composition — set to one of desk | hand | hub | wall | tile, the same five viewing distances the dashboard spec below carries:

<orbias-machine-status device-id="dev_a1b2c3" calibration="hub"></orbias-machine-status>

It scales --oe-font-size and --oe-space, and — at hub/wall, the FOR-915 glove/distance floor — raises every touch target (the honesty stamp, a status pill, an .oe-action button) to a 64px minimum via the shared --oe-target-min token. It never changes what a component means or its honesty state — only its targets and type scale (FOR-915 Frame 12).

Dashboards as a spec (FOR-882)

A dashboard is a declarative spec — JSON or YAML — that binds components to estate nodes (operator → site → space → asset → device; ADR-0004), not tags, and carries --oe-* theme tokens and an optional calibration (desk / hand / hub / wall / tile; FOR-915). The same spec renders two ways.

import { parseDashboardSpec } from "@orbias/elements/render";

const spec = parseDashboardSpec({
  version: 0,
  title: "Bench",
  layout: { columns: 3, gap: 16 },
  tokens: { "--oe-accent": "#5e6ad2" }, // FOR-1061: the estate's one accent
  components: [
    { type: "machine-status", binding: { node: "device", id: "dev_a1b2c3" } },
    {
      type: "consumable-level",
      binding: { node: "asset", id: "ast_tank" },
      measurement: { measurementType: "level", unit: "%" },
    },
    { type: "uptime-tile", binding: { node: "site", id: "sit_bench" } },
  ],
});

1. Live — the host mounts the Elements from the spec (the normal Surface B path). mountDashboard resolves each binding to a device, injects the shared stream, applies the tokens, and lays the tiles out on a CSS grid:

import { defineOrbiasElements, mountDashboard } from "@orbias/elements";

defineOrbiasElements();
const handle = mountDashboard(spec, {
  container: document.querySelector("#dashboard"),
  stream, // the one shared ClientDeviceStream
  nodes, // estate nodes, so a site/asset binding resolves to its device
});
// handle.unmount() removes it (each tile tears down its subscription).

2. Machine-render — a headless renderer takes the spec + a point-in-time estate snapshot and emits SVG (or PNG). It runs the reading through the same stale-honesty machine the live tiles use, so a stale tile renders stale in the image — dashed border, de-inked value, the state's glyph and label:

import { renderDashboardSvg, renderDashboardPng } from "@orbias/elements/render";

const snapshot = {
  observedNow: Date.parse("2026-09-11T10:00:00Z"), // server-authoritative "now"
  readings: { dev_a1b2c3: reading /* Surface A wire shape */ },
  nodes,
};

const svg = renderDashboardSvg(spec, snapshot); // a standalone <svg> string

// PNG rasterises that SVG through an INJECTED rasteriser — the SDK carries no
// native image binary (inject resvg in Node, or a canvas in the browser):
import { Resvg } from "@resvg/resvg-js";
const png = await renderDashboardPng(spec, snapshot, {
  rasterize: (svg) => new Resvg(Buffer.from(svg)).render().asPng(),
});

@orbias/elements/render is DOM-free, so a Node service or a Worker can import the spec + SVG/PNG path without a DOM (the live mountDashboard helper is on the main @orbias/elements entry, since it needs the DOM).

v0 scope: the three device tiles above; JSON/YAML spec (YAML authors parse to an object first — the SDK carries no YAML dependency); live-mount; SVG/PNG. Not yet: PDF, a hosted "just send me a link" page, and headless rendering of the composition components (they consume record models, not a device snapshot). The measurement binding is validated and carried today; the renderer consumes it (unit-aware formatting, counterType aggregation) once FOR-847's metric dictionary lands. Headless rendering of the eight thread-family components has a recorded v1 plan (FOR-1066 tracking comment) but is not built.

A per-COMPONENT calibration (falling back to the spec's) is threaded through both render paths: live, mountDashboard sets it as the mounted element's calibration attribute; headless, renderDashboardSvg scales that tile's own type/target sizing by it — the GRID geometry (cell size) still comes from the dashboard-level calibration.

See demo/thread-family.html for the eight thread-family components composed on the synthetic fixtures, with dark and tenant-accent toggles.

Attribution

Components render a "Powered by Orbias" line by default, via the attribution property (and a same-named slot for custom markup).

Requirements

  • A modern browser with Custom Elements and ES modules (this is an ESM-only package).
  • An @orbias/client instance and a Surface A token carrying the stream:subscribe scope for live data.