86 / Agent UI
Stream Glow
An edge that breathes along a region while tokens land in it, and stops the moment they do.
The edge breathes while tokens land, and stops the moment they do.
Answering
"use client"
import * as React from "react"
import { StreamGlow } from "mischief-ui/stream-glow"
export function StreamGlowDemo() {
const [streaming, setStreaming] = React.useState(true)
return (
<div className="grid w-full max-w-md gap-4">
<StreamGlow
active={streaming}
rate={0.8}
className="border-border bg-card rounded-[var(--radius)] border p-6"
>
<p className="text-sm">
The edge breathes while tokens land, and stops the moment they do.
</p>
<p className="text-muted-foreground mt-2 text-xs" role="status">
{streaming ? "Answering" : "Finished"}
</p>
</StreamGlow>
<button
type="button"
className="border-border mx-auto inline-flex min-h-11 items-center rounded-full border px-4 text-sm font-semibold"
onClick={() => setStreaming((value) => !value)}
>
{streaming ? "Stop" : "Start"}
</button>
</div>
)
}Installation
Copy the source into your project, or keep it behind a package.
npx shadcn@latest add Tinkerers-Labs/mischief-ui/stream-glowimport { StreamGlow } from "mischief-ui/stream-glow"Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.
"use client" import * as React from "react"import { cn } from "@/lib/utils" export type StreamGlowProps = React.HTMLAttributes<HTMLDivElement> & { /** Whether anything is arriving. */ active?: boolean /** Nought to one. Faster arrival breathes faster and reaches further. */ rate?: number color?: string /** Thickness of the glow in pixels. */ spread?: number}Usage
export function Answer({ streaming, tokensPerSecond }) {
return (
<StreamGlow active={streaming} rate={tokensPerSecond / 60} className="rounded-xl border p-6">
<Message>{/* the answer so far */}</Message>
</StreamGlow>
)
}What it is allowed to mean
Only that something is arriving. It cannot say what, or how far through, or whether it went wrong, so it belongs next to a stop control and a written status rather than standing in for either.
It is CSS, not a canvas. There is nothing to draw here that a shadow and an opacity cannot do, and staying in CSS means it costs nothing and inherits the border radius of whatever you put it on.
Tying it to the throughput
Rate changes both how quickly the edge breathes and how far it reaches, so a fast answer looks fast. Normalise your tokens per second into nought through one before passing it, and keep the value smoothed: a glow driven by a raw per-frame figure flickers.
API
activebooleanWhether anything is arriving. Off by default.ratenumberNought to one. Faster arrival breathes faster and reaches further. Defaults to 0.5.colorstringA theme property or CSS colour. Defaults to "--primary".spreadnumberThickness of the glow in pixels. Defaults to 22.Accessibility
The glow is a hidden decorative layer and announces nothing. Under reduced motion the breathing stops and a steady edge remains, so the region is still marked. As with any ambient signal, the words next to it are what actually reports the state.