# LumeSec Elements > 211 interactive components from the LumeSec design lab: controls, meters, dot-matrix displays, network and service maps. React and TypeScript, installed with the shadcn CLI. You own the source. --- # Accessibility > Keyboard support, ARIA roles and live regions, native form validation, visible focus, and a reduced-motion mode that keeps every number. Source: https://elements.lumesec.ai/docs/accessibility The effects in Elements are decoration on top of working controls. With the effects off, each component is still a usable control. This page describes the shared behaviour; each component page lists its own keyboard map and roles. ## Keyboard * Sliders, dials and knobs move with the arrow keys and jump with Home and End. * Lists, grids and segmented controls use a roving tab index: one Tab stop, arrows inside. * Buttons and toggles respond to Enter and Space. Dialogs and popovers close with Escape and return focus. ## Roles and labels Components set the role that matches their behaviour, such as `slider`, `meter`, `switch`, `tablist` or `grid`, together with `aria-valuenow`, `aria-valuetext` and `aria-checked` as they change. Status text that updates on its own is in an `aria-live` region. Canvases that carry meaning get an `aria-label` with the value they show. ## Forms Pixel UI inputs are React components built on native form controls, or on a hidden input where the control is custom. They submit under their `name`, take part in native validation where the original control does, and reset with the form. Custom-element inputs in the other collections are form-associated through `ElementInternals`: they submit under their `name`, report validity to the form and reset with it. Every input is labelled by its `label`. ## Focus Focus rings use `:focus-visible` with a ring in the accent colour, so mouse users do not see them and keyboard users always do. ## Text stays text Every word and number a person reads is real text in a regular font: labels, body copy, counters and large display numerals alike. Pixels are the effect layer around the text, never the text itself, so values are selectable, translatable and read by assistive technology as they appear. ## Reduced motion When the system asks for reduced motion, loops stop, traffic and spark pixels switch off, and values jump to their target. Every number and every state remains. See [Motion](/docs/motion). ## Contrast The default tokens meet WCAG 2.1 AA for text in both themes. If you change `--muted-foreground` or `--lumesec`, check text contrast against `--card`. --- # Use with AI > Every page has a Markdown twin, the whole documentation is available as one file, and each component can be opened in ChatGPT, Claude or v0. Source: https://elements.lumesec.ai/docs/ai The documentation is written for people first and is published in forms that language models read well. ## Markdown for every page Add `.md` to any documentation or component URL to get the page as Markdown, with the preview replaced by its markup and the install and usage blocks written out as code. ```bash curl https://elements.lumesec.ai/components/pixel-hd/gauge.md ``` Every page also has **Copy page** and **View as Markdown** under its title. ## llms.txt | File | Contents | | -------------------------------- | ----------------------------------------------------------------- | | [/llms.txt](/llms.txt) | An index of every guide and component with a link to its Markdown | | [/llms-full.txt](/llms-full.txt) | Every guide and every component page in one file | ## Open in **Open in** on each page starts a conversation in ChatGPT, Claude or Perplexity that reads the page first. Component pages add **Open in v0**, which loads the registry item into a new v0 project. ## In your editor Register `@lumesec` in `components.json` and run the shadcn MCP server. See [Registry and MCP](/docs/registry). --- # Changelog > New collections, components and changes to the registry, newest first. Source: https://elements.lumesec.ai/docs/changelog ## 0.2.0 · 2026-10-02 Every component is now real, strict TypeScript. * **Interaction and Pixel UI are native React components.** 41 components rewritten as React 19 function components styled with Tailwind CSS v4 and `cn()`, in the way of shadcn/ui: controlled and uncontrolled state (`value` / `defaultValue` / `onValueChange`, `checked` / `onCheckedChange`), typed callbacks instead of `CustomEvent`s, `ref` handles for imperative actions, `data-slot` and `data-state` attributes, full server rendering. Pixel UI inputs submit with native forms. * **Pixel Lab, Pixel HD, Network and Service Map are typed custom elements.** 170 elements and their three engines converted from JavaScript to strict TypeScript, with typed attributes, methods and event maps, and their tags registered in `HTMLElementTagNameMap`. The React wrappers are typed from the element classes. * **Your shadcn theme drives everything.** Components read `--background`, `--card`, `--foreground`, `--muted`, `--border` and the other shadcn tokens directly, in any colour format including `oklch()`. The new `lumesec-theme` item adds the `--lumesec` accent tokens and their Tailwind colours. The `--ui-*` properties remain as optional overrides for the custom elements. * **Shared React modules** in `lib/lumesec`: theme colour reading for canvas, motion hooks that pause off screen, sparks, rolling labels, the pixel font and controllable state. Each is its own registry item and installs once. * **No type escape hatches.** The registry contains no `any`, `@ts-ignore` or `@ts-nocheck`, and every usage snippet in the docs type-checks. * **Docs**: React API reference (props, ref handles, subcomponents) for the React components, a React playground, updated guides for React, plain HTML and theming. * **Breaking.** React users of Interaction and Pixel UI move from event objects to callbacks (`onChange={(e) => e.detail.value}` becomes `onValueChange={(value) => …}`) and from attributes to props. The plain-HTML builds of Interaction and Pixel UI are retired; the other collections keep theirs. ## 0.1.0 · 2026-10-01 The first public release of LumeSec Elements. * **211 components in six collections**: Interaction (11), Pixel Lab (50), Pixel UI (30), Pixel HD (60), Network (30) and Service Map (30). * **shadcn registry** under `@lumesec`, with shared engines and React bindings as their own items so they install once. * **Typed React wrappers** for every component: props from attributes, `on` handlers from events, refs with methods. * **Plain HTML modules** on the CDN, one per component and one per collection. * **One theming contract.** Every collection now reads the same `--ui-*` tokens with Screen Line fallbacks. The `lumesec-theme` item maps them onto shadcn themes. * **Server-safe modules.** Importing a component on the server no longer touches the DOM. * **Documentation** for every component: live preview, install, usage, API reference, keyboard and accessibility. * **Machine-readable docs**: Markdown twins, `llms.txt` and `llms-full.txt`. ### Collections by date | Date | Added | | ---------- | --------------------- | | 2026-10-01 | Network, Service Map | | 2026-09-30 | Pixel HD, second set | | 2026-09-29 | Pixel HD | | 2026-09-28 | Pixel UI | | 2026-09-27 | Pixel Lab, second set | | 2026-09-26 | Pixel Lab | | 2026-09-25 | Interaction | | 2026-09-24 | Ultracode slider | --- # FAQ > Licensing, frameworks, server rendering, bundle size, browser support and the plans for Elements Pro. Source: https://elements.lumesec.ai/docs/faq ## Is it free? Yes. Every component on this site is free under the MIT license, including for commercial work. Attribution is welcome and not required. ## Do I need React? For Interaction and Pixel UI, yes: they are native React 19 components. Pixel Lab, Pixel HD, Network and Service Map are custom elements that run in plain HTML through the CDN modules, or in Vue, Svelte or Angular, and ship with a typed React wrapper for React projects. See [Plain HTML](/docs/html). ## Do I need Tailwind CSS? For the React components, yes, Tailwind CSS v4 as set up by `shadcn init`. They are styled with utility classes on your theme tokens, like shadcn/ui. The custom elements style themselves inside their shadow roots and need no CSS framework. ## Is everything TypeScript? Yes. Every file the CLI installs is strict TypeScript: no `any`, no `@ts-ignore`. The custom elements register their tags in `HTMLElementTagNameMap`, so `document.querySelector` and refs are typed with their properties and methods. ## Does it work with server rendering? Yes. The React components render their full markup on the server; canvas layers draw after hydration. The custom-element modules do not touch the DOM when imported on the server and upgrade in the browser. Both can be imported from Next.js server components. ## How large is a component? A React component is one file of a few hundred lines plus small shared modules (colour reading, motion, sparks) that every component reuses. A custom element and its engine are typically 10 to 30 KB minified, before compression; components from the same family share the engine, so the second one costs only its own file. ## Which browsers are supported? Current versions of Chrome, Edge, Firefox and Safari. The components use canvas 2D, `ResizeObserver`, `IntersectionObserver` and the Web Animations API; the custom elements also use shadow DOM and `ElementInternals` for form controls. ## Some components show data I didn't provide. Components such as the network topology or the service map ship with a demo data set for one site so that they run on their own. Their pages list which attributes select a record. To connect real data, edit the typed data in the engine file or set the records from your code; the source is yours. ## How do I change the colours? Change your shadcn theme, or the `--lumesec` accent tokens. To restyle only the custom elements, set their `--ui-*` overrides. See [Theming](/docs/theming). ## What will Elements Pro be? Templates and composite blocks built from these components, such as a network operations console or an AI workspace. Pro items will need a licence key; the free components will stay free. Create an account to hear when it opens. ## Who makes this? LumeSec Technologies GmbH. LumeSec builds SecureGrid and the AI Operating Platform. Elements is where the design team publishes the components it builds along the way. ## Where do I report a problem? Use **Report an issue** on any page, or open an issue on [GitHub](https://github.com/lumesec/elements/issues). --- # Plain HTML > The custom-element collections run without React. Load one ES module per component, or a whole collection, and use the tags in any page or framework. Source: https://elements.lumesec.ai/docs/html Pixel Lab, Pixel HD, Network and Service Map are standard custom elements. They work in plain HTML and in every framework that renders the DOM, and React is optional for them. Interaction and Pixel UI are native React components. They are installed with the shadcn CLI and have no HTML build. ## From the CDN Each custom element has its own module with its engine inlined. Load it once and use the tag anywhere on the page. ```html title="index.html" ``` A collection bundle registers every element in it: ```html ``` | Bundle | Contains | | --------------------- | -------------------------- | | `/cdn/{tag}.js` | One element and its engine | | `/cdn/pixel-lab.js` | Pixel Lab | | `/cdn/pixel-hd.js` | Pixel HD | | `/cdn/network.js` | Network | | `/cdn/service-map.js` | Service Map | Loading two modules that share an engine is safe: each tag registers once. ## Events and methods ```html ``` Events bubble and cross the shadow boundary, so a parent can listen too. ## Self-hosting and TypeScript For production, copy the files from the Manual tab of a component page into your codebase and bundle them with your app. The CDN is for prototypes and pages without a build step. The element modules are TypeScript. Each one registers its tag in `HTMLElementTagNameMap`, so `document.querySelector("px-orb")` is typed with the element's properties and methods, and exports a typed event map where the element fires events. ## Theme Elements read your page's CSS variables through their shadow root, the same ones shadcn/ui uses (`--card`, `--foreground`, `--border`…) plus `--lumesec` for the accent. Without them they use built-in light and dark values that follow `prefers-color-scheme`. See [Theming](/docs/theming). ## Vue Tell Vue that tags with a dash are custom elements: ```ts title="vite.config.ts" vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.includes("-") } } }); ``` Then use the tags in templates and listen with `@change`. ## Svelte, Angular and others Svelte handles custom elements without configuration. Angular needs `CUSTOM_ELEMENTS_SCHEMA` in the component or module that uses them. ## Content Security Policy The elements inject their styles into their own shadow roots and do not use `eval`. If your policy restricts `style-src`, allow `'unsafe-inline'` for styles or serve the modules from your own origin. --- # Introduction > Interactive components from the LumeSec design lab, published as a shadcn registry. Install one, read the source, ship it. Source: https://elements.lumesec.ai/docs LumeSec Elements is where the LumeSec design team publishes the components it builds for its own products: controls, meters, dot-matrix displays, and network and service maps. Every component is strict TypeScript. You install it with the shadcn CLI and the source lands in your repository. Register the registry once and add your first component. 211 components in six collections, all running live. Controlled and uncontrolled state, typed callbacks, ref handles. Your shadcn theme plus one `--lumesec` accent drives every component. ## What you get * **Source, not a package.** The CLI copies the files into your project. You can read, change and delete any line. * **Two kinds, one standard.** Interaction and Pixel UI are native React 19 components styled with Tailwind CSS v4, written like shadcn/ui. Pixel Lab, Pixel HD, Network and Service Map are canvas-heavy custom elements that also run in plain HTML, Vue or Svelte, with a typed React wrapper. Both are strict TypeScript with no `any`. * **No extra dependencies.** React components need React and `cn`; custom elements need their family's engine (one file). No animation library, no icon set, no UI kit. * **Your theme.** Colours and fonts come from your shadcn theme variables, plus one set of `--lumesec` accent tokens. Light and dark follow your theme. * **Accessible by default.** Keyboard support, ARIA roles and live regions, inputs that submit with native forms, and a reduced-motion mode that keeps every number. ## How the components behave The components share a short list of rules. They came out of design reviews and they are why the effects feel deliberate rather than decorative. 1. **Plain until earned.** Most states are an ordinary control. The effect switches on for the state that matters: the top effort level, live traffic, a completed upload. 2. **Growth has a direction.** Effects grow from an origin and travel one way, like a trail growing out of a slider thumb. 3. **Legibility beats pixels.** Text is never drawn as dots. Numerals, labels and headlines are set in Geist; the dot field glows, fills and reacts around them. 4. **Few pixels, meaningful pixels.** Density follows the data, logarithmic and capped. If a frame looks busy, it is halved. 5. **One accent moment per component.** Electric marks the one thing that matters. Primary buttons use the foreground colour. 6. **Numbers are mechanical.** Rates, counts, IDs and times use a monospace face with tabular figures. ## Collections | Collection | Components | Kind | What it covers | | -------------------------------------- | ---------- | -------------- | ------------------------------------------------------------------------------ | | [Interaction](/components/interaction) | 11 | React | Micro-interactions on everyday controls, including the Ultracode slider | | [Pixel Lab](/components/pixel-lab) | 50 | Custom element | Components that live in a pixel lattice: meters, gauges, radars, model moments | | [Pixel UI](/components/pixel-ui) | 30 | React | Form controls you can ship, each with one pixel detail | | [Pixel HD](/components/pixel-hd) | 60 | Custom element | Regular controls on a fine dot field with bloom and ordered dither | | [Network](/components/network) | 30 | Custom element | Topology, devices, traffic and security, with traffic as the only pixels | | [Service Map](/components/service-map) | 30 | Custom element | Hosts, ports, services and routes, with requests as pixels | ## Free, and later Pro Every component on this site is free under the MIT license, for personal and commercial work. Larger templates and composite blocks will follow as Elements Pro. The free components stay free. --- # Installation > Register the @lumesec registry with the shadcn CLI and add a component, a whole collection, or the accent tokens. Source: https://elements.lumesec.ai/docs/installation Elements uses the shadcn CLI to copy components into your project. If you already use shadcn/ui, there is nothing new to set up apart from the registry. ## Requirements * React 19 and TypeScript. Every file the CLI installs is strict TypeScript. * Tailwind CSS v4 for the React components (Interaction, Pixel UI), as set up by `shadcn init`. The custom elements (Pixel Lab, Pixel HD, Network, Service Map) style themselves inside a shadow root and need no CSS framework. Skip this if your project already has a `components.json`. ```bash npx shadcn@latest init ``` This adds the namespace to `components.json`, so you can install by name. ```bash npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json ``` The result in `components.json`: ```json title="components.json" { "registries": { "@lumesec": "https://elements.lumesec.ai/r/{name}.json" } } ``` ```bash npx shadcn@latest add @lumesec/effort-slider ``` Or a whole collection, by its name: ```bash npx shadcn@latest add @lumesec/pixel-ui ``` You can also skip the registry setup and install by URL: ```bash npx shadcn@latest add https://elements.lumesec.ai/r/effort-slider.json ``` Every component depends on the `lumesec-theme` item, so the first install also adds the `--lumesec` accent tokens to your global CSS. See [Theming](/docs/theming). ## What lands in your project A React component brings its file and the shared modules it imports. Adding `ui-dial`: ```bash title="Files" lib/lumesec/math.ts # shared helpers, installed once lib/lumesec/color.ts # theme colours for canvas drawing lib/lumesec/motion.ts # reduced motion, animation loop, springs lib/lumesec/roll-text.tsx # rolling labels lib/lumesec/use-controllable-state.ts components/lumesec/ui-dial.tsx # the component ``` A custom element brings its module, a typed React wrapper and its family's engine. Adding `hf-gauge`: ```bash title="Files" lib/lumesec/pixel.ts # Pixel engine for Pixel Lab and Pixel HD, installed once lib/lumesec/react.ts # React bindings for custom elements, installed once components/lumesec/hf-gauge.element.ts # the custom element (registers ) components/lumesec/hf-gauge.tsx # the typed React wrapper ``` The next component of the same kind only adds its own files. The CLI rewrites the `@/lib` and `@/components` imports to the aliases in your `components.json`. ## Use it ```tsx title="app/page.tsx" import { HfGauge } from "@/components/lumesec/hf-gauge"; import { UiDial } from "@/components/lumesec/ui-dial"; export default function Page() { return ( <> ); } ``` Both are client components, so you can render them from a server component without extra setup. Continue with [React](/docs/react) or [plain HTML](/docs/html). ## Update a component Run `add` again. The CLI shows a diff for files you changed and asks before it overwrites them. ```bash npx shadcn@latest add @lumesec/hf-gauge --diff ``` ## Without the CLI Every component page has a **Manual** tab under Installation. It lists the files in install order with their source, ready to copy. --- # License > The components are released under the MIT license. You may use, copy, modify and distribute them, including in commercial products. Source: https://elements.lumesec.ai/docs/license The components, engines and React bindings in the LumeSec Elements registry are released under the MIT license. The LumeSec name and logo are not covered by it and may not be used to suggest endorsement. ```md title="LICENSE" MIT License Copyright (c) 2026 LumeSec Technologies GmbH Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` Elements Pro items, when they are released, will come with their own licence terms. --- # Motion > How the components move, why they stay still most of the time, and what they cost to run. Source: https://elements.lumesec.ai/docs/motion Motion in Elements marks a change of state. It is not ambient decoration. The rules below apply to every collection. ## Rules 1. **Plain until earned.** A slider is a slider until it reaches its special state. The Ultracode trail only grows at the top level. 2. **Directional growth.** Effects start at an origin and travel one way, with a slightly irregular front, and stop where they should: the effort trail covers three quarters of the track. 3. **Bursts reach past the edge.** When a state is reached, sparks may fly past the component's bounds on an overflow layer, with a brief flash. A small sparkle does not register. 4. **Labels roll.** A changing label rolls in like a picker wheel, from above or below to match the direction of the change. 5. **Springs, slightly under-damped.** Thumbs and indicators settle with a short overshoot, then stop. 6. **Numbers are mechanical.** Counters roll digit by digit in tabular figures, so their width never changes. ## Performance * Canvases are sized to the device pixel ratio and redrawn only while something changes. When a component settles, its animation loop stops. * Components off screen pause: an intersection observer stops their loop and their demo data timers. * There are no runtime dependencies beyond React for the React components. Animation, colour reading and sparks come from small shared modules in `lib/lumesec`; a custom element and its engine are one module, typically 10 to 30 KB minified. * Live previews on this site load each component's module only when it scrolls near the viewport. * React components keep animation state in refs and draw from one requestAnimationFrame loop per canvas, so an animation never re-renders the component tree. ## Reduced motion With `prefers-reduced-motion: reduce`: * Loops, shimmer and pulses stop. * Traffic, spark and burst pixels are not drawn. * Springs and rolls are replaced by an immediate change. * Values, labels and colours still update, so no information is lost. You can test this in Chrome DevTools under Rendering, Emulate CSS media feature `prefers-reduced-motion`. --- # React > Native React components with controlled and uncontrolled state, typed callbacks and ref handles. Custom elements with typed wrappers, events and element refs. Source: https://elements.lumesec.ai/docs/react Every component is used from React through a named export from its file: `ui-dial.tsx` exports `UiDial`, `hf-gauge.tsx` exports `HfGauge`. What sits behind the export depends on the collection. | Collections | Kind | Props | Events | Ref | | ----------------------------------------- | ----------------------------------- | --------------------------------------- | --------------------------------------------- | ----------------------------------- | | Interaction, Pixel UI | Native React component | React props, controlled or uncontrolled | Typed callbacks with plain values | Root DOM element, or a typed handle | | Pixel Lab, Pixel HD, Network, Service Map | Custom element with a typed wrapper | Attributes as camelCase props | `on` handlers receiving a typed `CustomEvent` | The element, typed with its methods | ## Native React components They are ordinary React 19 function components, written like shadcn/ui: Tailwind classes on your theme tokens, `cn()` for `className`, the remaining props spread onto the root element, `data-slot` and `data-state` attributes for styling. Open the file and change anything. ### State Stateful components follow the Radix naming. Pass `value` and a change callback to control them, or `defaultValue` to let them keep their own state. ```tsx import * as React from "react"; import { EffortSlider, type EffortLevel } from "@/components/lumesec/effort-slider"; export function Effort() { const [level, setLevel] = React.useState("medium"); return ; } ``` ```tsx save({ thinking: checked })}> Extended thinking ``` | State | Controlled | Uncontrolled | Callback | | -------------- | ---------- | ---------------- | -------------------------- | | Value | `value` | `defaultValue` | `onValueChange(value)` | | On or off | `checked` | `defaultChecked` | `onCheckedChange(checked)` | | Open or closed | `open` | `defaultOpen` | `onOpenChange(open)` | Callbacks fire for user actions. Changing a controlled prop from your code animates the component to the new value without calling the callback back. Some controls also report a second moment, such as `onValueCommit` when a drag ends on a dial or slider; each component page lists its callbacks. ### Imperative actions Where an action is naturally a command (show a toast, compact the context, finish thinking), the component's `ref` is a typed handle instead of a DOM node: ```tsx import * as React from "react"; import { UiContextMeter, type UiContextMeterHandle } from "@/components/lumesec/ui-context-meter"; export function Context() { const meter = React.useRef(null); return ( <> ); } ``` Each component page lists its ref under **API reference**. Everywhere else, `ref` points at the root element. ### Forms Pixel UI inputs render native form controls, or a hidden input where the control is custom, so they submit with any `
`, including server actions, and reset with it: ```tsx ``` ### Server rendering The components are client components (`"use client"`) and render their full markup on the server, so text, labels and layout are there on first paint. Canvas layers draw after hydration, and animation loops pause while a component is off screen. ## Custom elements with wrappers The wrapper registers the element, renders it, and types its attributes and events. The element itself is a strict TypeScript class in `{tag}.element.ts`. ### Props are attributes Attribute names become camelCase props. Numbers can be passed as numbers, presence attributes as booleans. `className`, `style`, `id`, `slot`, `aria-*` and `data-*` pass through to the element, and children render into its slots. ```tsx import { HfSlider } from "@/components/lumesec/hf-slider"; ; ``` ### Events are handlers Each custom event becomes an `on` prop. The handler receives the `CustomEvent`, typed from the element's event map: ```tsx setVolume(event.detail.value)} /> ``` Events bubble and cross the shadow boundary, so a parent can also listen with `addEventListener`. ### Refs give you the element The ref is the element class, with its properties and methods: ```tsx import * as React from "react"; import { PxOrb, type PxOrbElement } from "@/components/lumesec/px-orb"; export function Agent() { const orb = React.useRef(null); return ( <> ); } ``` Outside React, the tags are registered in `HTMLElementTagNameMap`, so `document.querySelector("px-orb")` is typed the same way. ### Why attribute names are upper-cased React 19 assigns a prop to a same-named element property when one exists. Several elements expose read-only properties, such as `name` on form controls, which would throw. The bindings in `lib/lumesec/react.ts` pass attribute names upper-cased: React finds no property, calls `setAttribute`, and the browser stores the lower-case name. You never see this unless you inspect the props. --- # Registry and MCP > How the @lumesec registry is laid out, how to browse it from the CLI, and how to give your AI editor access through the shadcn MCP server. Source: https://elements.lumesec.ai/docs/registry Elements is a standard shadcn registry. Anything that reads shadcn registries can read it: the CLI, the MCP server, v0 and your own tools. ## Addresses | What | URL | | ------------------ | --------------------------------------------- | | Item | `https://elements.lumesec.ai/r/{name}.json` | | Index of all items | `https://elements.lumesec.ai/r/registry.json` | | Namespace | `@lumesec` | Item names are the component tags, for example `ui-dial`, `hf-gauge` or `ln-topology`. Shared files are items too, and components list them as dependencies, so the CLI installs each one once: | Item | What it installs | | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `lumesec-theme` | The `--lumesec` accent tokens and their Tailwind colours | | `lumesec-math`, `lumesec-color`, `lumesec-motion`, `lumesec-canvas` | Helpers the React components share: maths, theme colour reading, motion hooks, canvas sizing | | `lumesec-pixel-canvas`, `lumesec-pixel-font`, `lumesec-sparks`, `lumesec-roll-text`, `lumesec-use-controllable-state`, `lumesec-fuzzy` | Building blocks of the Interaction and Pixel UI components | | `lumesec-engine-pixel`, `lumesec-engine-network`, `lumesec-engine-service` | The runtime of each custom-element family | | `lumesec-react` | Bindings that render custom elements from React | React components also depend on shadcn's `utils` item (`cn`), which every shadcn project already has. Each collection is an item as well: `interaction`, `pixel-lab`, `pixel-ui`, `pixel-hd`, `network` and `service-map` install every component in it. ## Browse from the CLI ```bash npx shadcn@latest search @lumesec --query gauge npx shadcn@latest view @lumesec/hf-gauge ``` ## MCP The shadcn MCP server lets an editor agent search the registries in your `components.json` and install items. With `@lumesec` registered: ```bash npx shadcn@latest mcp init --client claude ``` Other clients: `cursor`, `vscode`, `codex`, `opencode`. Then ask, for example, "add a network topology view from the lumesec registry". ## Open in v0 Each component page has **Open in v0** under **Open in**. v0 loads the registry item, so you can try the component in a new project. ## Pro items Pro items will be served to holders of a licence key. The registry accepts the key as a header, which the shadcn CLI reads from `components.json`: ```json title="components.json" { "registries": { "@lumesec": { "url": "https://elements.lumesec.ai/r/{name}.json", "headers": { "Authorization": "Bearer ${LUMESEC_KEY}" } } } } ``` The free components never need a key. --- # Theming > Components follow your shadcn theme. One extra set of --lumesec tokens adds the accent; --ui-* overrides restyle the custom elements on their own. Source: https://elements.lumesec.ai/docs/theming Every component reads the same variables your shadcn/ui components already use: `--background`, `--foreground`, `--card`, `--muted`, `--muted-foreground`, `--border`, `--input`, `--destructive`, `--font-sans` and `--font-mono`. Change your theme and the components change with it, in light and dark. On top of that, LumeSec components have one accent, Electric, and a few signal colours. They come from the `--lumesec` tokens. ## Add the accent tokens ```bash npx shadcn@latest add @lumesec/lumesec-theme ``` Every component installs this item as a dependency, so you usually already have it. It writes the tokens into your global CSS, under `:root` and `.dark`, and registers them as Tailwind colours (`bg-lumesec`, `text-lumesec-foreground` and so on): ```css title="app/globals.css" :root { --lumesec: #6219f3; --lumesec-foreground: #fafafa; --lumesec-soft: #a685ff; --lumesec-shine: #3f12b0; --lumesec-glint: #c9bdff; --lumesec-success: #00a14b; --lumesec-warning: #d97706; --lumesec-info: #1e40af; } .dark { --lumesec: #8654fb; --lumesec-foreground: #fafafa; --lumesec-soft: #a685ff; --lumesec-shine: #ffffff; --lumesec-glint: #ffffff; --lumesec-success: #00c758; --lumesec-warning: #eeb154; --lumesec-info: #4ab8e8; } @theme inline { --color-lumesec: var(--lumesec); --color-lumesec-foreground: var(--lumesec-foreground); /* … one entry per token */ } ``` | Token | Tailwind colour | Used for | Light | Dark | | ---------------------- | -------------------- | -------------------------------- | --------- | --------- | | `--lumesec` | `lumesec` | The one accent moment | `#6219f3` | `#8654fb` | | `--lumesec-foreground` | `lumesec-foreground` | Text on the accent | `#fafafa` | `#fafafa` | | `--lumesec-soft` | `lumesec-soft` | Secondary accent shades, traffic | `#a685ff` | `#a685ff` | | `--lumesec-shine` | `lumesec-shine` | Highlights on dot fields | `#3f12b0` | `#ffffff` | | `--lumesec-glint` | `lumesec-glint` | Sparks on Interaction controls | `#c9bdff` | `#ffffff` | | `--lumesec-success` | `lumesec-success` | Success | `#00a14b` | `#00c758` | | `--lumesec-warning` | `lumesec-warning` | Warning | `#d97706` | `#eeb154` | | `--lumesec-info` | `lumesec-info` | Information, upstream traffic | `#1e40af` | `#4ab8e8` | To use your own brand colour, change `--lumesec` in both blocks. Errors use your `--destructive`. ## How each kind of component reads the theme **React components** (Interaction, Pixel UI) are styled with Tailwind classes on these tokens, like any shadcn component: `bg-card`, `text-muted-foreground`, `border-border`, `bg-lumesec`. Edit the classes in the file to restyle one. Canvas layers resolve the same variables at runtime. **Custom elements** (Pixel Lab, Pixel HD, Network, Service Map) draw inside a shadow root, so your stylesheet cannot reach into them. Custom properties inherit through the shadow boundary, so they read the same tokens from the page. Both resolve any CSS colour format, including the `oklch()` values shadcn generates, `color-mix()` and `var()` chains. Canvas layers re-read their palette when the `class`, `data-theme` or `style` attribute of `` changes, so a theme switch applies on the next frame. Themes that store bare HSL channels (`--border: 214 32% 91%`, the format of older shadcn/ui versions) are not colours on their own. With such a theme, set the `--ui-*` overrides below to `hsl(var(--border))` and so on. ## Overrides for custom elements Every custom element reads a private chain: an optional `--ui-*` override first, then your theme token, then a built-in fallback. Set an override to restyle LumeSec elements without touching the rest of your app. | Override | Falls back to | Used for | | ------------------------------------- | ------------------------------------------------------------ | ----------------------------- | | `--ui-page` | `--background` | Page behind a component | | `--ui-surface` | `--card` | Cards and panels | | `--ui-raised` | `--muted` | Hover fills, segmented tracks | | `--ui-track` | `--muted` | Slider and meter tracks | | `--ui-border` | `--border` | Hairlines | | `--ui-border-strong` | `--input` | Inputs, emphasised borders | | `--ui-fg` | `--foreground` | Text and primary buttons | | `--ui-fg2` | a mix of `--foreground` and `--muted-foreground` | Secondary text | | `--ui-muted` | `--muted-foreground` | Labels and captions | | `--ui-faint` | a mix of `--muted-foreground` and `--background` | Ticks and inactive dots | | `--ui-accent` | `--lumesec` | The accent | | `--ui-accent-soft` | `--lumesec-soft` | Secondary accent shades | | `--ui-on-accent` | `--lumesec-foreground` | Text on the accent | | `--ui-shine` | `--lumesec-shine` | Highlights on dot fields | | `--ui-ok` / `--ui-warn` / `--ui-info` | `--lumesec-success` / `--lumesec-warning` / `--lumesec-info` | Signal colours | | `--ui-danger` | `--destructive` | Errors | | `--ui-font` / `--ui-mono` | `--font-sans` / `--font-mono` | Text, and numbers, IDs, code | Overrides cascade like any custom property. To give one panel its own accent: ```css .billing { --ui-accent: #0f766e; } ``` For a React component, pass a class instead: `className="[--lumesec:#0f766e]"` on the component (or a wrapper) recolours its accent. ## Without a theme With none of these variables on the page, every component falls back to the light and dark values above and follows the operating system's colour scheme. ## Dark mode Components follow whichever mechanism your theme uses, a `.dark` class, a `data-theme` attribute or `prefers-color-scheme`, because the tokens change, not the components. Every component page lists the tokens it reads under **Theming**. --- # Context meter > Context-window meter that fills a pixel strip behind a glowing front, turns amber at 80% and red at 95%, and animates compaction. - React: `import { UiContextMeter } from "@/components/lumesec/ui-context-meter"` - Collection: Interaction (https://elements.lumesec.ai/components/interaction) - Registry item: https://elements.lumesec.ai/r/ui-context-meter.json - Page: https://elements.lumesec.ai/components/interaction/context-meter Live preview: https://elements.lumesec.ai/view/ui-context-meter Demo source: ```tsx "use client"; import * as React from "react"; import { UiContextMeter, type UiContextMeterHandle } from "@/components/lumesec/ui-context-meter"; const ACTION = "h-[30px] rounded-lg border border-border bg-card px-[11px] text-[12.5px] font-medium text-foreground hover:border-[color-mix(in_srgb,var(--lumesec)_50%,var(--border))]"; export default function UiContextMeterDemo() { const meter = React.useRef(null); return (
); } ``` ## Playground Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over. ## Installation ```bash npx shadcn@latest add @lumesec/ui-context-meter ``` First time with the @lumesec registry? Register it once, or install by URL: ```bash npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json npx shadcn@latest add https://elements.lumesec.ai/r/ui-context-meter.json ``` ## Usage React: ```tsx "use client"; import * as React from "react"; import { UiContextMeter, type UiContextMeterHandle } from "@/components/lumesec/ui-context-meter"; export function Example() { const meter = React.useRef(null); return (
); } ``` ## Behaviour Usage fills a strip of pixels behind a glowing front, turns amber past 80 % and red near the limit. Compacting sends a bright band back across the strip as the count drops. ## API reference ### Props Also accepts every prop of `
` (`React.ComponentProps<"div">`), spread onto the root element. | Prop | Type | Default | Description | | --------------- | ------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `value` | `number` | — | Controlled share of the context window in percent, clamped to 0–100. The strip animates to each new level. Use with `onValueChange`. | | `defaultValue` | `number` | `0` | Initial percentage when uncontrolled. | | `capacity` | `number` | `200000` | Window size in tokens, used only for the "used / total" readout, which is shown in thousands. | | `label` | `string` | `"Context"` | Caption before the percentage. | | `onValueChange` | `(value: number) => void` | — | Called with the new percentage when `add()` or `compact()` changes it. | | `onCompact` | `(from: number, to: number) => void` | — | Called when `compact()` runs, with the percentage before and after. | | `ref` | `React.Ref` | — | Exposes `add()` and `compact()`. | ### Ref `ref` receives a `UiContextMeterHandle` handle with these methods. | Method | Description | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `add(percent: number): void` | Adds `percent` percentage points (negative to subtract), clamped to 0–100. | | `compact(): void` | Drops usage to 28% of its current value (at least 12%), runs a bright sweep and shows "Compacting…" for 1.5 s. Does nothing at 15% or below. | ## Accessibility * The strip is a canvas with `role="meter"`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-valuenow` and the `aria-label` "Context window N% full". * The `aria-label` is fixed English and does not use `label`. * There is no live region; changes are not announced. * Reduced motion: the fill jumps to the new level, the compaction sweep is skipped, the percentage stops blinking near the limit and text swaps without rolling. ## Theming Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming). This component reads `--lumesec`, `--lumesec-glint`, `--lumesec-warning`, `--destructive`, `--foreground` and `--muted-foreground`. ## Notes * `value` is a percentage, not a token count; the token readout is derived from `capacity`. * The root carries `data-zone` set to `ok`, `warn` (80% and up) or `full` (95% and up), which can be used for styling. * The strip is 18 px tall and fills the available width. Its colours follow the theme and are re-read when it changes. --- # Copy button > Copy-to-clipboard button whose icon turns into a drawn check as the label rolls to "Copied"; it says so when the browser refuses. - React: `import { UiCopyButton } from "@/components/lumesec/ui-copy-button"` - Collection: Interaction (https://elements.lumesec.ai/components/interaction) - Registry item: https://elements.lumesec.ai/r/ui-copy-button.json - Page: https://elements.lumesec.ai/components/interaction/copy-button Live preview: https://elements.lumesec.ai/view/ui-copy-button Demo source: ```tsx import { UiCopyButton } from "@/components/lumesec/ui-copy-button"; // short enough to fit next to the button in a gallery card without an ellipsis const COMMAND = "npx shadcn add @lumesec/ui-copy-button"; export default function UiCopyButtonDemo() { return (
{COMMAND}
); } ``` ## Playground Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over. ## Installation ```bash npx shadcn@latest add @lumesec/ui-copy-button ``` First time with the @lumesec registry? Register it once, or install by URL: ```bash npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json npx shadcn@latest add https://elements.lumesec.ai/r/ui-copy-button.json ``` ## Usage React: ```tsx import { UiCopyButton } from "@/components/lumesec/ui-copy-button"; export function Example() { return ; } ``` ## Behaviour The clipboard icon spins away as a check draws itself in, the label rolls to “Copied”, and a small pop of pixels confirms it. If the browser refuses the copy, it says so instead. ## API reference ### Props Also accepts every prop of `
); } ``` ## Playground Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over. ## Installation ```bash npx shadcn@latest add @lumesec/ui-thinking ``` First time with the @lumesec registry? Register it once, or install by URL: ```bash npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json npx shadcn@latest add https://elements.lumesec.ai/r/ui-thinking.json ``` ## Usage React: ```tsx "use client"; import * as React from "react"; import { UiThinking } from "@/components/lumesec/ui-thinking"; export function Example() { const [done, setDone] = React.useState(false); React.useEffect(() => { const timer = window.setTimeout(() => setDone(true), 4000); return () => window.clearTimeout(timer); }, []); return ( console.log(`thought for ${seconds}s`)}> The reasoning, shown once thinking is done. ); } ``` ## Behaviour A pixel wave and a shimmering label while the model works, with a seconds counter that rolls on every tick. When it finishes, the glyph draws a check and the label rolls to “Thought for 6s”, which opens the reasoning. ## API reference ### Props Also accepts every prop of `
` (`React.ComponentProps<"div">`), spread onto the root element. | Prop | Type | Default | Description | | -------------- | --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `done` | `boolean` | — | Whether thinking has finished (controlled). Use with `onDoneChange`. When it turns true, the glyph draws a check, the label rolls to "Thought for Ns" and the reasoning becomes expandable. Turning it false returns to thinking; the counter keeps running from the last start. | | `defaultDone` | `boolean` | `false` | Whether it starts finished, when uncontrolled. A component that starts done reads "Thought for 1s". | | `onDoneChange` | `(done: boolean) => void` | — | Called when `finish()` or `restart()` changes the state. | | `onDone` | `(seconds: number) => void` | — | Called when the state changes to done, with the whole seconds elapsed (at least 1). Not called when the component mounts already done. | | `children` | `React.ReactNode` | — | The reasoning, shown in a collapsible panel once done. | ### Ref `ref` receives a `UiThinkingHandle` handle with these methods. | Method | Description | | ----------------- | ------------------------------------------------------------------------------------ | | `finish(): void` | Finishes thinking. Same as setting `done`. | | `restart(): void` | Resets the counter to 0 and returns to the thinking state, collapsing the reasoning. | ## Keyboard | Keys | Action | | ------------- | ---------------------------------------------------- | | Enter / Space | On the label, once done: show or hide the reasoning. | ## Accessibility * The label is a native `
); } ``` ## Behaviour New toasts spring up from below and older ones tuck in behind. Hovering fans the stack out and pauses the timers; swipe a toast sideways to throw it away. ## API reference ### Props Also accepts every prop of `
` (`React.ComponentProps<"div">`), spread onto the root element. | Prop | Type | Default | Description | | --------- | ------------------------------- | ------- | ------------------------------------------------------------------------------------- | | `trigger` | `boolean` | `true` | Render the "Show toast" button under the stack, which shows the next built-in sample. | | `ref` | `React.Ref` | — | Exposes `show()`. | ### Ref `ref` receives a `UiToastStackHandle` handle with these methods. | Method | Description | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `show(toast?: ToastInput): void` | Adds a toast `{ title: string; description?: string; tone?: "accent" \| "success" \| "warning" \| "destructive" }`. Without an argument it shows the next built-in sample. | ## Keyboard | Keys | Action | | ------------- | ---------------------------------------- | | Space / Enter | On a toast's dismiss button, dismiss it. | ## Accessibility * Toasts are placed in an element with `role="region"`, `aria-label="Notifications"` and `aria-live="polite"`; each toast has `role="status"`. * Each toast has a native dismiss button labelled "Dismiss". Buttons on toasts hidden at the back of the stack are taken out of the tab order. * Moving focus into the stack expands it and pauses the timers, as hovering does. * Swiping is pointer-only; the dismiss button is the keyboard path. * Reduced motion: toasts appear, fan out, settle and leave without transitions; a swipe still follows the pointer. ## Theming Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming). This component reads `--card`, `--muted`, `--border`, `--foreground`, `--muted-foreground`, `--lumesec`, `--lumesec-success`, `--lumesec-warning` and `--destructive`. ## Notes * Ships with six sample toasts (published, copied, connector added, upload failed, memory updated, files uploaded) that `show()` cycles through when called without an argument. * Each toast lives 5 s, and timers pause while the stack is expanded or a toast is held. At most five toasts are kept and three are visible; a sixth removes the oldest. * A swipe of more than 80 px, or a fast flick, throws the toast away. The stack area is 196 px tall and up to 340 px wide. --- # Toggle > Switch with a label and hint whose thumb stretches as it travels and pops a few pixel sparks when it turns on. - React: `import { UiToggle } from "@/components/lumesec/ui-toggle"` - Collection: Interaction (https://elements.lumesec.ai/components/interaction) - Registry item: https://elements.lumesec.ai/r/ui-toggle.json - Page: https://elements.lumesec.ai/components/interaction/toggle Live preview: https://elements.lumesec.ai/view/ui-toggle Demo source: ```tsx import { UiToggle } from "@/components/lumesec/ui-toggle"; export default function UiToggleDemo() { return (
Extended thinking
Web search
); } ``` ## Playground Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over. ## Installation ```bash npx shadcn@latest add @lumesec/ui-toggle ``` First time with the @lumesec registry? Register it once, or install by URL: ```bash npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json npx shadcn@latest add https://elements.lumesec.ai/r/ui-toggle.json ``` ## Usage React: ```tsx import { UiToggle } from "@/components/lumesec/ui-toggle"; export function Example() { return ( Extended thinking ); } ``` ## Behaviour The thumb stretches like a drop as it travels, the accent floods out from under it, and a few pixel sparks pop when it switches on. Clicking the label works too. ## API reference ### Props Also accepts every prop of `
` (`React.ComponentProps<"div">`), spread onto the root element. | Prop | Type | Default | Description | | ----------------- | ---------------------------- | --------------------- | ------------------------------------------------------------------------------------------ | | `checked` | `boolean` | — | Controlled state. Use with `onCheckedChange`. | | `defaultChecked` | `boolean` | `false` | Initial state when uncontrolled. | | `children` | `React.ReactNode` | `"Extended thinking"` | Label text. It is also the switch's accessible name. | | `hint` | `React.ReactNode` | — | Secondary text under the label, linked to the switch with `aria-describedby`. | | `onCheckedChange` | `(checked: boolean) => void` | — | Called when the user toggles the switch. Changing `checked` from outside does not call it. | ### Ref `ref` points at the root `HTMLDivElement`. ## Keyboard | Keys | Action | | ------------- | -------------------------- | | Space / Enter | Toggle the focused switch. | ## Accessibility * The switch is a native `