Agent Session

AI Agent Terminal Demo for React

A coding agent at work in its terminal, beside the app it's changing. The prompt types itself, each command runs with a live timer and lands its output in one burst, and every line that writes a file shows up in the app a beat later, ringed. Point at a change on either side and its other half lights up.

  • AI
  • Code
  • Developer

Uses motion, clsx, tailwind-merge

Open in ChatGPTOpen in Claude
speed1.00×
theme
target.enter
target.duration0.42s(replays the demo)
target.bounce0.22(replays the demo)
<AgentSession />

replays the demo when you let go.

web — agent

localhost:3000/dashboard
Overview
Last 7 days

Visitors

12,480+8.2%

Signups

1,204+3.1%

No funnels yet

Ask for one, or add it from Funnels.

  1. You: Add a signup funnel to the dashboard and track each step
  2. Ran Bash: npx tern events list --match signup. signup_viewed page /signup. signup_submitted form #signup-form. email_verified server POST /api/verify
  3. Ran Bash: npx tern add funnel signup --to app/dashboard. + app/dashboard/signup-funnel.tsx SignupFunnel. ~ app/dashboard/layout.tsx Funnels (1)
  4. Ran Bash: npx tern track signup_viewed signup_submitted email_verified. + app/signup/page.tsx track("signup_viewed"). + app/signup/form.tsx track("signup_submitted"). + app/api/verify/route.ts track("email_verified")
  5. Agent: Added a three-step signup funnel to the dashboard. Last week 1,204 of 12,480 visitors finished, and most of the drop happens before the form is sent.

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

Agent Session: A coding agent at work in its terminal, beside the app it's changing. The prompt types itself, each command runs with a live timer and lands its output in one burst, and every line that writes a file shows up in the app a beat later, ringed. Point at a change on either side and its other half lights up.
This demo, Analytics Setup: An agent adds a signup funnel to a product analytics dashboard. The card arrives with its file, then each bar fills as the tracking call for that step is written.

1. Install it:
   npx shadcn@latest add @keyframeui/agent-session-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/agent-session-demo.json instead.)
   It adds the demo, components/agent-session-demo.tsx, and the component, components/ui/agent-session.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 <AgentSession> on its own.

3. These props set its feel. Change them before you change the file:
   - speed (default 1): Playback rate for typing, commands and output. `2` plays twice as fast.
   - theme (default "dark"): `"dark"` keeps a dark terminal in both color schemes. `"auto"` is light in light mode and dark in dark mode.
   - enter on <AgentSessionTarget> (default "pop"): How the content arrives: a springy pop out of a slight blur, a plain fade, or no motion of its own. The ring flashes either way.
   - duration on <AgentSessionTarget> (default 0.42): How long the pop takes to land, in seconds. Only for `enter="pop"`.
   - bounce on <AgentSessionTarget> (default 0.22): How much the pop overshoots before it settles, from `0` (none) up. Only for `enter="pop"`.

4. Don't change, in components/ui/agent-session.tsx:
   - The session is one plan built ahead by `buildPlan` and played on a ms clock, one `setTimeout` to the next event at a time; the screen is a function of `t`, so the clock stops and resumes cleanly.
   - A jump (Skip, Replay, a new script or `speed`) sets `jumped`, so everything lands in place without animating; typing jitter comes from `noise`, so every replay types the same.
   - Cause, reload, effect: a line with an `effect` lands, the address bar sweeps, and its target changes `hmr` ms later.
   - Lines, prompts and targets animate `transform` and `opacity` only (plus the pop's blur), and both target looks set every property, so switching to reduced motion leaves no blur behind.
   - Reduced motion still plays the session a step at a time, text whole and changes fading; the animated panes are `aria-hidden` and `<Transcript>` gives screen readers the script as text.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/agent-session.md

Installation

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

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

npx shadcn@latest add @keyframeui/agent-session

Examples

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

Localized Checkout

A checkout translated into German one label at a time, each English label as the `fallback` that its German line replaces. A teal accent through `--agent-session-accent`.

field-and-fold — agent

localhost:3000/de/checkout

Field & Fold

1 item

Contact
Email
lena@posteo.de
Shipping
Standard
3–5 days
0,00 €
Wool overshirt, oat
$128.00
Pay now
  1. You: Translate the checkout into German, with prices in euros
  2. Ran Bash: npx glossa extract app/checkout. 14 strings in 3 files. 2 prices · 1 date format
  3. Ran Bash: npx glossa translate de --glossary brand.json. + messages/de.json 14 strings · reviewed against glossary
  4. Ran Update: app/checkout/page.tsx. ~ "Contact" → "Kontakt". ~ "Email" → "E-Mail". ~ "Shipping" → "Versand". ~ "3–5 days" → "3–5 Werktage". ~ "$128.00" → "118,00 €". ~ "Pay now" → "Jetzt bezahlen"
  5. Agent: The checkout reads in German now, with euro prices from your price list. Delivery says Werktage, business days, which is how German shops write it.

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

Agent Session: A coding agent at work in its terminal, beside the app it's changing. The prompt types itself, each command runs with a live timer and lands its output in one burst, and every line that writes a file shows up in the app a beat later, ringed. Point at a change on either side and its other half lights up.
This demo, Localized Checkout: A checkout translated into German one label at a time, each English label as the `fallback` that its German line replaces. A teal accent through `--agent-session-accent`.

1. Install it:
   npx shadcn@latest add @keyframeui/agent-session-locale-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/agent-session-locale-demo.json instead.)
   It adds the demo, components/agent-session-locale-demo.tsx, and the component, components/ui/agent-session.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 <AgentSession> on its own.

3. These props set its feel. Change them before you change the file:
   - speed (default 1): Playback rate for typing, commands and output. `2` plays twice as fast.
   - theme (default "dark"): `"dark"` keeps a dark terminal in both color schemes. `"auto"` is light in light mode and dark in dark mode.
   - enter on <AgentSessionTarget> (default "pop"): How the content arrives: a springy pop out of a slight blur, a plain fade, or no motion of its own. The ring flashes either way.
   - duration on <AgentSessionTarget> (default 0.42): How long the pop takes to land, in seconds. Only for `enter="pop"`.
   - bounce on <AgentSessionTarget> (default 0.22): How much the pop overshoots before it settles, from `0` (none) up. Only for `enter="pop"`.

4. Don't change, in components/ui/agent-session.tsx:
   - The session is one plan built ahead by `buildPlan` and played on a ms clock, one `setTimeout` to the next event at a time; the screen is a function of `t`, so the clock stops and resumes cleanly.
   - A jump (Skip, Replay, a new script or `speed`) sets `jumped`, so everything lands in place without animating; typing jitter comes from `noise`, so every replay types the same.
   - Cause, reload, effect: a line with an `effect` lands, the address bar sweeps, and its target changes `hmr` ms later.
   - Lines, prompts and targets animate `transform` and `opacity` only (plus the pop's blur), and both target looks set every property, so switching to reduced motion leaves no blur behind.
   - Reduced motion still plays the session a step at a time, text whole and changes fading; the animated panes are `aria-hidden` and `<Transcript>` gives screen readers the script as text.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/agent-session.md

CLI Feature Cards

Two small terminals with `theme="auto"` and no preview, as feature cards: a hidden key prompt, and a typo that gets a suggestion instead of a write.

~/web

  1. $ npx tern login. ? Project key ••••••••••••••••••••. ✓ Signed in as maya@fieldandfold.co. key saved to ~/.config/tern/auth.json

Your key stays in your terminal

You paste it once at a hidden prompt. The agent only ever runs tern track, so the key never reaches its context or your repo.

~/web

  1. $ npx tern track signup_veiwed. error no event "signup_veiwed". did you mean signup_viewed?. nothing was written
  2. $ npx tern track signup_viewed. + app/signup/page.tsx track("signup_viewed"). ✓ 1 event tracked

A typo gets a question, not a write

Event names must match. A near miss suggests the real one, and nothing touches your code until the name is right.

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

Agent Session: A coding agent at work in its terminal, beside the app it's changing. The prompt types itself, each command runs with a live timer and lands its output in one burst, and every line that writes a file shows up in the app a beat later, ringed. Point at a change on either side and its other half lights up.
This demo, CLI Feature Cards: Two small terminals with `theme="auto"` and no preview, as feature cards: a hidden key prompt, and a typo that gets a suggestion instead of a write.

1. Install it:
   npx shadcn@latest add @keyframeui/agent-session-cli-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/agent-session-cli-demo.json instead.)
   It adds the demo, components/agent-session-cli-demo.tsx, and the component, components/ui/agent-session.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 <AgentSession> on its own.

3. These props set its feel. Change them before you change the file:
   - speed (default 1): Playback rate for typing, commands and output. `2` plays twice as fast.
   - theme (default "dark"): `"dark"` keeps a dark terminal in both color schemes. `"auto"` is light in light mode and dark in dark mode.
   - enter on <AgentSessionTarget> (default "pop"): How the content arrives: a springy pop out of a slight blur, a plain fade, or no motion of its own. The ring flashes either way.
   - duration on <AgentSessionTarget> (default 0.42): How long the pop takes to land, in seconds. Only for `enter="pop"`.
   - bounce on <AgentSessionTarget> (default 0.22): How much the pop overshoots before it settles, from `0` (none) up. Only for `enter="pop"`.

4. Don't change, in components/ui/agent-session.tsx:
   - The session is one plan built ahead by `buildPlan` and played on a ms clock, one `setTimeout` to the next event at a time; the screen is a function of `t`, so the clock stops and resumes cleanly.
   - A jump (Skip, Replay, a new script or `speed`) sets `jumped`, so everything lands in place without animating; typing jitter comes from `noise`, so every replay types the same.
   - Cause, reload, effect: a line with an `effect` lands, the address bar sweeps, and its target changes `hmr` ms later.
   - Lines, prompts and targets animate `transform` and `opacity` only (plus the pop's blur), and both target looks set every property, so switching to reduced motion leaves no blur behind.
   - Reduced motion still plays the session a step at a time, text whole and changes fading; the animated panes are `aria-hidden` and `<Transcript>` gives screen readers the script as text.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/agent-session.md

Props

script Required

TypeAgentSessionStep[]

What happens, in order. { prompt } types into the input box and moves into the transcript. { run, tool?, output?, more?, ms?, pace?, failed? } is the agent running a tool (tool defaults to "Bash"): it runs for ms, then its output lands in a burst, or a line every pace ms. { say, effect? } streams the reply a word at a time. { shell } is a command you type at a $ prompt, for plain CLI sessions. An output line is a string or { text, tone?, effect? }, where tone is "muted", "added", "removed", "success" or "error" and effect names the change it makes in the preview. A new script starts from the top.

children

TypeReact.ReactNode

The app being changed, shown in a browser window beside the terminal (under it in narrow containers). Wrap the parts that change in AgentSessionTarget. Leave it out for a terminal on its own.

title

TypestringDefault"agent"

Text in the terminal's title bar, like a folder and the agent's name.

url

TypestringDefault"localhost:3000"

Address in the preview window's bar.

autoPlay

TypebooleanDefaulttrue

Start by itself once a third of it is in view. Turned off, it waits for the Play button in the title bar.

paused

TypebooleanDefaultfalse

Stop the clock where it is. Off screen and in hidden tabs it stops by itself and picks up where it left off.

loop

Typeboolean | numberDefaultfalse

Play again from the top after a 4s pause: forever with true, or this many more times.

speed

TypenumberDefault1

Playback rate for typing, commands and output. 2 plays twice as fast.

theme

Type"dark" | "auto"Default"dark"

"dark" keeps a dark terminal in both color schemes. "auto" is light in light mode and dark in dark mode.

placeholder

TypestringDefault"Ask the agent to change something"

Shown in the input box before the first prompt is typed. Scripts with only shell steps have no input box.

onComplete

Type() => void

Called once when a run finishes, including after Skip. Use it to move on to the next script.

onEffect

Type(effect: string) => void

Called with an effect's name each time its change lands in the preview during playback.

className

Typestring

Extra classes for the root. Set --agent-session-accent for the glow, sweep and rings, --agent-session-height for the height of each window (24rem by default), and --agent-session-preview-height for the preview alone when it stacks under the terminal.

target.effect Required

Typestring

AgentSessionTarget: the name a script line gives in its effect. The target changes when that line lands.

target.fallback

TypeReact.ReactNode

AgentSessionTarget: shown until the change lands, like a placeholder icon, an empty state or the old label. Without it the target waits invisible, keeping its space.

target.children Required

TypeReact.ReactNode | ((landed: boolean) => React.ReactNode)

AgentSessionTarget: the changed content. A function gets landed, for parts that change in their own way, like a bar that fills. useAgentSessionEffect(effect) returns the same flag anywhere inside the session.

target.enter

Type"pop" | "fade" | "none"Default"pop"

AgentSessionTarget: how the content arrives: a springy pop out of a slight blur, a plain fade, or no motion of its own. The ring flashes either way.

target.duration

TypenumberDefault0.42

AgentSessionTarget: how long the pop takes to land, in seconds. Only for enter="pop".

target.bounce

TypenumberDefault0.22

AgentSessionTarget: how much the pop overshoots before it settles, from 0 (none) up. Only for enter="pop".

target.className

Typestring

AgentSessionTarget: classes for the wrapper, a grid that stacks the fallback and the content. Set --agent-session-ring-radius to match the corners of what it wraps.