Generate or update the IronClaw architecture overview video using Remotion. Use when asked to update, regenerate, or modify the architecture video, add/remove scenes, or reflect codebase changes in the video.
Generates and maintains the animated architecture overview video in docs/architecture-video/ using Remotion (React-based video framework).
Read these files to understand the current system architecture:
CLAUDE.md — top-level project structure, module specs, key traits, principlescrates/ironclaw_engine/CLAUDE.md — engine v2 primitives, execution loop, CodeActsrc/agent/CLAUDE.md — agent loop architecturesrc/llm/CLAUDE.mdsrc/db/CLAUDE.md — database dual-backend architecturesrc/tools/README.md — tool system architecturesrc/workspace/README.md — workspace/memory architectureRead docs/architecture-video/src/IronClawArchitecture.tsx to understand current scene order, durations, and transitions. Then read individual scenes in docs/architecture-video/src/scenes/ to see what's already covered.
Compare the architecture documentation with what the video covers. Look for:
docs/architecture-video/
├── package.json # Remotion deps
├── remotion.config.ts # Build config
├── src/
│ ├── Root.tsx # Remotion entry — registers the composition
│ ├── IronClawArchitecture.tsx # Main composition — scene order + transitions
│ ├── theme.ts # Color palette + font constants
│ ├── components/
│ │ └── Code.tsx # Syntax-highlighted code block component
│ └── scenes/ # One file per scene
│ ├── TitleScene.tsx
│ ├── PrimitivesScene.tsx
│ ├── ExecutionLoopScene.tsx
│ ├── CodeActScene.tsx
│ ├── ThreadStateScene.tsx
│ ├── SkillsPipelineScene.tsx
│ ├── ToolDispatchScene.tsx
│ ├── ChannelsRoutingScene.tsx
│ ├── ChannelImplsScene.tsx
│ ├── TraitsScene.tsx
│ ├── LlmDecoratorScene.tsx
│ └── OutroScene.tsx
Render script: scripts/render-architecture-video.sh
| # | Scene | File | Duration | Content |
|---|---|---|---|---|
| 1 | Title | TitleScene.tsx | 4s | Animated IronClaw logo + tagline |
| 2 | Five Primitives | PrimitivesScene.tsx | 8s | Thread / Step / Capability / MemoryDoc / Project |
| 3 | Execution Loop | ExecutionLoopScene.tsx | 8s | 7-step ExecutionLoop::run() pipeline |
| 4 | CodeAct | CodeActScene.tsx | 10s | Python code → host fns → suspend/resume flow |
| 5 | Thread State | ThreadStateScene.tsx | 7s | Created→Running⇄Waiting/Suspended→Completed/Failed→Done |
| 6 | Skills Pipeline | SkillsPipelineScene.tsx | 8s | Gating → Scoring → Budget → Attenuation |
| 7 | Tool Dispatch | ToolDispatchScene.tsx | 9s | 9-step ToolDispatcher::dispatch() pipeline |
| 8 | Channels Routing | ChannelsRoutingScene.tsx | 7s | Channel trait + stream::select_all merging |
| 9 | Channel Impls | ChannelImplsScene.tsx | 7s | REPL / HTTP / Web / Signal / TUI / WASM |
| 10 | Traits | TraitsScene.tsx | 8s | 8 traits with concrete implementers |
| 11 | LLM Decorators | LlmDecoratorScene.tsx | 7s | SmartRouting→CircuitBreaker→...→Base decorator chain |
| 12 | Outro | OutroScene.tsx | 5s | Start Contributing + getting-started steps |
All animations MUST be driven by useCurrentFrame() — never CSS transitions or Tailwind animation classes.
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const opacity = interpolate(frame, [0, 0.5 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const y = interpolate(frame, [0, 0.5 * fps], [30, 0], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
For items that appear one by one:
{items.map((item, i) => {
const delay = 0.4 + i * 0.3; // seconds
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return <div style={{ opacity }} key={item.id}>...</div>;
})}
Scenes are composed using TransitionSeries with alternating fade() and slide({ direction: "from-right" }) transitions, each 15 frames (0.5s):
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={s(8)}>
<MyScene />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={fade()}
timing={linearTiming({ durationInFrames: 15 })}
/>
<TransitionSeries.Sequence durationInFrames={s(7)}>
<NextScene />
</TransitionSeries.Sequence>
</TransitionSeries>
Use the CodeBlock component from ../components/Code for syntax-highlighted code:
import { CodeBlock } from "../components/Code";
<CodeBlock code={`pub trait Channel: Send + Sync {
async fn start(&self) -> Result<MessageStream>;
}`} fontSize={13} />
Import colors and fonts from ../theme:
import { COLORS, FONTS } from "../theme";
// Available colors:
// bg, bgLight, primary, primaryLight, accent, accentLight,
// success, danger, text, textMuted, border, purple, cyan, pink
// Available fonts:
// mono (monospace), sans (system-ui)
src/scenes/MyNewScene.tsx following existing patternsIronClawArchitecture.tsxSCENES array with duration and transition typeTOTAL_DURATION auto-computes from the arraynpx remotion still IronClawArchitecture --scale=0.25 --frame=<N>import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
export const MyNewScene: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const headingOpacity = interpolate(frame, [0, 0.4 * fps], [0, 1], {
extrapolateRight: "clamp",
});
return (
<AbsoluteFill
style={{
backgroundColor: COLORS.bg,
fontFamily: FONTS.sans,
padding: 60,
}}
>
<div
style={{
opacity: headingOpacity,
fontSize: 42,
fontWeight: 700,
color: COLORS.text,
marginBottom: 4,
}}
>
<span style={{ color: COLORS.primary }}>Title</span> — subtitle
</div>
{/* Scene content */}
</AbsoluteFill>
);
};
After making changes:
cd docs/architecture-video && npx tsc --noEmitnpx remotion still IronClawArchitecture --scale=0.25 --frame=<N>
./scripts/render-architecture-video.sh [output-path]cd docs/architecture-video && npm run devCodeBlock component with syntax highlighting