Agent Run
A brand-neutral AI agent run that thinks, calls tools against a real-seconds timer and streams a markdown answer in bursts
$ pnpm dlx shadcn@latest add @remocn/agent-runUsage
AgentRun is the part of an AI product video that happens after the prompt.
The panel shows the prompt someone just sent, a Thinking status over a
short plan, then tool calls that resolve one after another while the header
timer counts real seconds. Then the answer streams in as markdown, in bursts.
It is brand-neutral: neutral surfaces, one accent for the running spinners and
the citation chips, and a light or dark theme.
import { Backdrop } from "@/components/remocn/backdrop";
import { AgentRun } from "@/components/remocn/agent-run";
export const AgentScene = () => (
<Backdrop
fill={{ type: "color", value: "#ececea" }}
padding={0}
radius={0}
shadow=""
>
<AgentRun />
</Backdrop>
);The component paints no background and centers its panel in the parent.
Sizes are reference pixels at a 720px-tall frame. They scale by
height / 720, capped so the 800px panel and its margins fit the width. The
panel height follows the frame, so square and vertical compositions show more
of the run at once. Everything derives from the Remotion frame and the seed,
so seeking and rendering are deterministic.
The component uses the system font stack. If your project loads Inter and
JetBrains Mono, for example with @remotion/google-fonts, it picks them up.
Your own run
Pass a run: the prompt, a short plan, the tool steps with their real
durations in seconds, and the answer as markdown. The answer supports these:
#and##headings- paragraphs
-bullets**bold**and inline code[n]citations- fenced code blocks
getAgentRunDuration(run) returns the composition length. If you also pass
seed, compression or speed to the component, pass the same values as the
second argument.
import { Composition } from "remotion";
import { Backdrop } from "@/components/remocn/backdrop";
import {
AgentRun,
type AgentRunScript,
getAgentRunDuration,
} from "@/components/remocn/agent-run";
const run: AgentRunScript = {
title: "Pro plan churn",
prompt: "Which Pro accounts are likely to churn this month?",
plan: [
"Pull weekly active seats for every Pro account",
"Compare them with renewal dates and support load",
],
steps: [
{
icon: "database",
name: "Run SQL",
detail: "active seats by account, last 60 days",
duration: 2.6,
},
{
icon: "book",
name: "Read 9 sources",
duration: 1.8,
sources: [
"CRM notes",
"Support tickets",
"Renewal calendar",
"billing.example.com",
"Usage report",
"QBR decks",
"Churn survey",
"Seat audit",
"Pricing page",
],
},
],
answer: [
"## 14 Pro accounts are at risk",
"",
"Active seats fell below 40% on 14 accounts that renew within 30 days [1].",
"",
"- 9 of them opened a billing ticket this month [2]",
"- 3 lost the admin who set up their workspace",
"",
"**Next:** send the list to account managers today.",
].join("\n"),
};
const ChurnScene = () => (
<Backdrop
fill={{ type: "color", value: "#0a0a0a" }}
padding={0}
radius={0}
shadow=""
>
<AgentRun run={run} theme="dark" accentColor="#22c55e" />
</Backdrop>
);
export const RemotionRoot = () => (
<Composition
id="ChurnScene"
component={ChurnScene}
durationInFrames={getAgentRunDuration(run)}
fps={30}
width={1280}
height={720}
/>
);Timing
At 30 fps with the default run, seed={1}, compression={3} and speed={1}:
| Frames | Beat |
|---|---|
| 0–14 | The panel fades up 14px, and the prompt bubble follows at 4–14 |
| 16 | The run starts: the timer reads 0.0s and Thinking fades in with its shimmer |
| 30–48 | The three plan lines stream in bursts |
| 56–64 | Thinking settles into Thought for 4s as the timer passes 4.0s |
| 61–75 | Query analytics runs, and its spinner closes into a check beside 1.4s |
| 80–103 | Run SQL, 2.3s on the timer |
| 108–120 | Search logs, 1.1s |
| 125–157 | Read 12 sources, 3.2s; five source chips and a +7 chip pop in at 129–148 |
| 165–178 | The heading streams in body style, then takes heading style when its line completes at 170 |
| 177–257 | The paragraph with its citations, then three bullets; the column starts gliding up at 201 |
| 262–275 | The code panel opens on its fence and four lines stream inside |
| 280–294 | The fix line lands, and the run ends at 294 with the timer at 27.7s |
| 294–310 | The header spinner closes into a check and the last chunk finishes fading; the column has glided 279px up |
| 310–355 | The docs preview holds the finished answer |
The answer arrives in chunks of 1–6 tokens that land on whole frames, 1–4
frames apart. Now and then a pause adds 4–7 more frames, and each new markdown
block starts on a fresh chunk after a 2–4 frame beat. Each chunk fades in over
5 frames. So the text comes in bursts, never at a constant rate per
character. seed changes the rhythm but not the content.
Every line's position is fixed in advance, and content only grows at the bottom. The column follows it with overlapping smoothstep glides of 24 frames, each starting 16 frames before its content arrives. A glide is three quarters done when its line lands, so a burst of new lines lands in view and nothing jumps.
compression sets how many real seconds pass per video second. A tool call
lasts duration / compression on screen, clamped to 12–120 frames. The timer
always advances by the step's real duration, so the rows and the header
agree. agentRunLength is 310, the component's own motion for the default
run. getAgentRunDuration(run, { seed, compression, speed }) adds a 45-frame
hold and scales the motion by speed.
| Prop | Type | Default | Description |
|---|---|---|---|
run | AgentRunScript | defaultAgentRun | The prompt, plan, tool steps and markdown answer; see the tables below |
theme | "light" | "dark" | "light" | Neutral panel theme |
accentColor | string | "#2563eb" | The one accent, used for running spinners and citation chips; any CSS color |
compression | number | 3 | Real seconds per video second, clamped to 0.25–20; tool calls last duration / compression on screen, clamped to 12–120 frames |
seed | number | 1 | Seeds the chunk sizes, intervals and pauses of the plan and answer streams |
speed | number | 1 | Playback multiplier; 0 freezes the first frame |
className | string | — | Optional class name on the full-frame root |
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Thread title in the panel header |
prompt | string | — | The message the user sent, shown as the bubble |
plan | string[] | — | Two or three short plan lines that stream under Thinking |
steps | AgentRunStep[] | — | Tool calls, run one after another |
answer | string | — | Markdown answer with # and ## headings, paragraphs, - bullets, bold, inline code, [n] citations and fenced code |
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Tool name, such as Run SQL |
detail | string | — | Short argument shown muted after the name |
duration | number | — | Real seconds; the timer advances by exactly this much during the step |
icon | "chart" | "database" | "search" | "book" | "globe" | "terminal" | "file" | "book" with sources, else "terminal" | Lucide icon for the row |
sources | string[] | — | Source labels; chips pop in during the step and the rest collapse into a +N chip |