Circuit

Right-angle circuit traces between the cards you already have, with signals that travel through them. Mark any element with `data-circuit`, describe the graph in one string, and the traces route themselves: edge to edge side by side, top to bottom when the layout stacks, around anything in the way.

  • Diagram
  • SVG
  • Interaction
  • Landing

Uses clsx, tailwind-merge

Open in ChatGPTOpen in Claude
GitHubissue #482
Slack#support
LinearENG-219
ORCHESTRATOR

Triage & assign

Dedupes the event, pulls repo context and hands it to the next free agent.

128 routed today

Coder14 patched
Reviewer9 reviewed
Tester11 verified

Installation

Add the component on its own with the CLI, or copy the file in by hand.

The CLI writes components/ui/circuit.tsx and installs clsx and tailwind-merge. It needs the @keyframeui registry in components.json; add it once per project.

npx shadcn@latest add @keyframeui/circuit

Examples

Finished sections built with Circuit. Each one installs whole, with the component included.

Webhook Pipeline

A payment webhook through a queue and a worker to three destinations, fired by a button through `apiRef.send()` with `autoPlay={false}`. Each destination's trace carries its own `color`, and the delivery log fills from `onArrive`.

POST /webhooks/stripe

invoice.paid

Queue

events · fifo

Worker

handlePaid()

Postgres

upsert

Email

receipt

Slack

#revenue

  1. No deliveries yet.

Integrations Hub

Your product in the middle of a 3×3 grid of integrations, the flow built from arrays with a packet color per tool. `highlight="neighbors"` lights only a tile's own trace, and the tiles lift on hover: the traces follow them.

GitHub
Sentry
Figma
Linear
Relayyour app
Slack
Stripe
Email
Notion

Props

flowRequired

Typestring | (string | CircuitTrace)[]

Which nodes connect, by their data-circuit ids. "a, b -> c -> d, e" connects every node in a stage to every node in the next; separate chains with ; or a new line. Mix in { from, to, color?, fromSide?, toSide? } objects for a trace's own packet color or pinned sides.

autoPlay

TypebooleanDefaulttrue

Sources (nodes nothing flows into) send signals on their own. Off, signals only start on hover, focus, tap or apiRef.send().

interval

TypenumberDefault2.4

Seconds between signals from each source, with a little jitter.

speed

TypenumberDefault260

Packet speed in px per second, so short and long traces move alike.

fanout

Type"all" | "one"Default"all"

When a signal reaches a node with several outgoing traces, send it down all of them, or down one at a time in turn (a router handing work to the next agent).

highlight

Type"path" | "neighbors" | "none"Default"path"

What lights up when a node is hovered, focused or tapped: everything upstream and downstream of it, only its own traces, or nothing.

onArrive

Type(node: string, from: string) => void

Called when a signal lands on a node. Use it to tick a counter or log the event in the card.

apiRef

TypeReact.Ref<{ send(node: string): void }>

send(node) fires a signal out of a node from code: a button, a websocket message, a form submit.

radius

TypenumberDefault12

Corner radius of the bends, in px. Tight corners shrink to fit.

pinSpacing

TypenumberDefault12

Space between traces sharing a card edge, and between traces that would otherwise run on top of each other, in px.

pins

TypebooleanDefaulttrue

Draw a pin where a trace meets a card. It flashes in the packet color when a signal lands.

traceClassName

TypestringDefault"text-zinc-300 dark:text-zinc-700"

text-* classes for the traces and pins.

packetClassName

TypestringDefault"text-sky-500 dark:text-sky-400"

text-* classes for the packets and the lit path. A trace's own color wins.

className

Typestring

Your layout: the circuit is a plain div and its children stay its direct children, so put your grid or flex classes here. Nodes are any descendants with data-circuit="id"; they get data-circuit-state (active, linked or dimmed) while a node is highlighted and data-circuit-pulse for half a second when a signal lands, for you to style with data-* variants. Give cards a background: traces run underneath them.