Pulse

Live Data Dot Grid Background for React

A background your data plays, not the pointer. A still grid of dots fills the box, and every event in your feed lands on it like a drop on water: a ring runs out from its point, swelling the dots it passes in the event's color, and the spot it hit stays lit for a moment after.

  • Background
  • Data
  • Canvas

Uses clsx, tailwind-merge

Open in ChatGPTOpen in Claude
ambient0/min
spacing18px
ringSpeed420px/s
ringDuration1.6s
<Pulse />

The demo follows as you drag.

Inference that runs where your users are

Lumbra routes every call to the closest free GPU. Each ring behind this text is traffic landing in one of our regions right now.

1,284,906 requests served today

Inference · fra1 · 41 ms

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Pulse: A background your data plays, not the pointer. A still grid of dots fills the box, and every event in your feed lands on it like a drop on water: a ring runs out from its point, swelling the dots it passes in the event's color, and the spot it hit stays lit for a moment after.
This demo, Live Regions: An inference platform's hero where requests land as small rings labelled with their region and deploys as orange ones, ticking the counter below.

1. Install it:
   npx shadcn@latest add @keyframeui/pulse-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/pulse-demo.json instead.)
   It adds the demo, components/pulse-demo.tsx, and the component, components/ui/pulse.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <Pulse> on its own.

3. These props set its feel. Change them before you change the file:
   - ambient (default 0): Events per minute it lands on its own while your feed is quiet, so it can play alone. A real event pushes the next one back. `0` turns it off.
   - spacing (default 18): Distance between dots, in px.
   - ringSpeed (default 420): How fast a ring runs out from its point, in px per second.
   - ringDuration (default 1.6): How long a ring takes to fade to nothing, in seconds. The spot it hit stays lit for 2s either way.

4. Don't change, in components/ui/pulse.tsx:
   - One rAF loop paints one canvas: the still grid is drawn once offscreen and blitted each frame, lifted dots are batched into one path per tone and level, and the loop stops when no ring is left.
   - Only ids new since the last `events` list land; the first list is history, and events that arrive off screen or in a hidden tab are dropped, not queued.
   - Rings add up where they cross and never cancel; past `maxRings` the oldest is dropped.
   - Labels are stroked with the ground's color so dots never cut through them, and a repeat from the same spot takes over the label already showing.
   - Under reduced motion there are no rings: a still spot lights by opacity alone (the dots keep one size), and labels fade in place without the rise.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/pulse.md

Installation

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

The CLI writes components/ui/pulse.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/pulse

Examples

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

Waitlist

A language tutor's waitlist where signups land on their cities and joining drops an orange ring labelled You, roughly where you are.

Talk your way into a new language

Parlance is a tutor you speak with, not tap at. It hears your accent, fixes it gently and remembers every word you trip on. The list opens in March.

12,481

people on the list

Latest · Lisbon

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Pulse: A background your data plays, not the pointer. A still grid of dots fills the box, and every event in your feed lands on it like a drop on water: a ring runs out from its point, swelling the dots it passes in the event's color, and the spot it hit stays lit for a moment after.
This demo, Waitlist: A language tutor's waitlist where signups land on their cities and joining drops an orange ring labelled You, roughly where you are.

1. Install it:
   npx shadcn@latest add @keyframeui/pulse-waitlist-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/pulse-waitlist-demo.json instead.)
   It adds the demo, components/pulse-waitlist-demo.tsx, and the component, components/ui/pulse.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <Pulse> on its own.

3. These props set its feel. Change them before you change the file:
   - ambient (default 0): Events per minute it lands on its own while your feed is quiet, so it can play alone. A real event pushes the next one back. `0` turns it off.
   - spacing (default 18): Distance between dots, in px.
   - ringSpeed (default 420): How fast a ring runs out from its point, in px per second.
   - ringDuration (default 1.6): How long a ring takes to fade to nothing, in seconds. The spot it hit stays lit for 2s either way.

4. Don't change, in components/ui/pulse.tsx:
   - One rAF loop paints one canvas: the still grid is drawn once offscreen and blitted each frame, lifted dots are batched into one path per tone and level, and the loop stops when no ring is left.
   - Only ids new since the last `events` list land; the first list is history, and events that arrive off screen or in a hidden tab are dropped, not queued.
   - Rings add up where they cross and never cancel; past `maxRings` the oldest is dropped.
   - Labels are stroked with the ground's color so dots never cut through them, and a repeat from the same spot takes over the label already showing.
   - Under reduced motion there are no rings: a still spot lights by opacity alone (the dots keep one size), and labels fade in place without the rise.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/pulse.md

Status Page

An API status page where every region's health checks pass as small rings, until one region turns red and an incident runs from investigating to resolved.

FerruleStatusSubscribe
All systems operational

Health checks are passing in all 9 regions.

Regions

99.98% over 90 days

  • sfo1operational
  • iad1operational
  • gru1operational
  • lhr1operational
  • fra1operational
  • bom1operational
  • sin1operational
  • syd1operational
  • nrt1operational
Incidents

No open incidents. Each region is checked every 30 seconds.

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Pulse: A background your data plays, not the pointer. A still grid of dots fills the box, and every event in your feed lands on it like a drop on water: a ring runs out from its point, swelling the dots it passes in the event's color, and the spot it hit stays lit for a moment after.
This demo, Status Page: An API status page where every region's health checks pass as small rings, until one region turns red and an incident runs from investigating to resolved.

1. Install it:
   npx shadcn@latest add @keyframeui/pulse-status-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/pulse-status-demo.json instead.)
   It adds the demo, components/pulse-status-demo.tsx, and the component, components/ui/pulse.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <Pulse> on its own.

3. These props set its feel. Change them before you change the file:
   - ambient (default 0): Events per minute it lands on its own while your feed is quiet, so it can play alone. A real event pushes the next one back. `0` turns it off.
   - spacing (default 18): Distance between dots, in px.
   - ringSpeed (default 420): How fast a ring runs out from its point, in px per second.
   - ringDuration (default 1.6): How long a ring takes to fade to nothing, in seconds. The spot it hit stays lit for 2s either way.

4. Don't change, in components/ui/pulse.tsx:
   - One rAF loop paints one canvas: the still grid is drawn once offscreen and blitted each frame, lifted dots are batched into one path per tone and level, and the loop stops when no ring is left.
   - Only ids new since the last `events` list land; the first list is history, and events that arrive off screen or in a hidden tab are dropped, not queued.
   - Rings add up where they cross and never cancel; past `maxRings` the oldest is dropped.
   - Labels are stroked with the ground's color so dots never cut through them, and a repeat from the same spot takes over the label already showing.
   - Under reduced motion there are no rings: a still spot lights by opacity alone (the dots keep one size), and labels fade in place without the rise.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/pulse.md

Props

events

TypePulseEvent[]

Your feed: { id, x?, y?, strength?, tone?, label? }. Each new id lands once as a ring; ids already there on mount count as history and don't. x and y are 0–1 of the box (a missing one gets a point picked from the id), strength 0–1 sets how far the ring carries (default 0.6), and tone is "ink" or "accent". A label (a region, a city) prints just above the point in the event's tone in small mono type for about a second, so a viewer can match a ring to its line in your log. Events that arrive while it's off screen are dropped.

ambient

TypenumberDefault0

Events per minute it lands on its own while your feed is quiet, so it can play alone. A real event pushes the next one back. 0 turns it off.

spacing

TypenumberDefault18

Distance between dots, in px.

ringSpeed

TypenumberDefault420

How fast a ring runs out from its point, in px per second.

ringDuration

TypenumberDefault1.6

How long a ring takes to fade to nothing, in seconds. The spot it hit stays lit for 2s either way.

paused

TypebooleanDefaultfalse

Draw the still grid and ignore new events.

inkClassName

TypestringDefault"text-zinc-900 dark:text-zinc-100"

A text-* color for the dots and ink rings. The canvas reads it, so dark: variants work; dots at rest draw it at low opacity.

accentClassName

TypestringDefault"text-[#ff5a1f] dark:text-[#ff6a3d]"

A text-* color that accent events paint as their ring passes.

onLand

Type(event: PulseEvent) => void

Called when an event's ring starts, including the ones ambient lands.

children

TypeReact.ReactNode

The section drawn over the dots.

className

Typestring

Extra classes for the root.