feat(docs): animated architecture overview video for contributors (#2365)

* feat(docs): animated architecture overview video for contributors

Adds a Remotion-based animated video (82s, 12 scenes at 30fps) that
visualizes the IronClaw architecture for new contributors. Covers engine
v2 primitives, CodeAct execution, thread state machine, skills pipeline,
tool dispatch, channel routing, trait implementations, and LLM decorator
chain.

- docs/architecture-video/ — Remotion project with 12 animated scenes
- scripts/render-architecture-video.sh — render script
- .claude/skills/architecture-video/ — Claude Code skill to update the
  video when architecture changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs): address PR review feedback and fix cargo-deny CI

- Resolve relative output paths in render script before cd
- Use npm ci when package-lock.json exists for reproducible builds
- Fix file paths in TraitsScene, ChannelImplsScene, CodeActScene
- Label Channel trait code as simplified in ChannelsRoutingScene
- Fix TypeScript version (5.9.3 → 5.7.3) and update lockfile
- Add dom/esnext to tsconfig lib for React 19 compatibility
- Fix license to MIT OR Apache-2.0 to match repo
- Fix TOTAL_DURATION to count only scenes with transitions
- Fix cargo-deny: add publish = false, ignore RUSTSEC-2026-0097

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs): address remaining PR review feedback

- Remove `publish = false` from Cargo.toml (unrelated build policy change,
  should be a separate PR if desired)
- Add `--` before output path in render script to prevent argument injection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs): address second round of PR review feedback

- Add npm command check to render script (was only checking node/npx)
- Memoize highlight() tokenization in CodeBlock — Remotion re-renders every
  frame and code is static per instance, so useMemo avoids repeated work
- Rewrite README to describe the IronClaw architecture video project instead
  of the default Remotion template

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Illia Polosukhin
2026-04-18 16:43:54 +09:00
committed by GitHub
parent 96aa31bb42
commit 7f5b02d7f0
28 changed files with 7730 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
---
name: architecture-video
description: 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.
---
# Architecture Video Generator
Generates and maintains the animated architecture overview video in `docs/architecture-video/` using Remotion (React-based video framework).
## When to use
- User asks to update, regenerate, or modify the architecture video
- User asks to add or remove scenes from the video
- Codebase architecture has changed and the video needs to reflect it
- User wants to preview or render the video
## Before making changes
### 1. Read current architecture
Read these files to understand the current system architecture:
- `CLAUDE.md` — top-level project structure, module specs, key traits, principles
- `crates/ironclaw_engine/CLAUDE.md` — engine v2 primitives, execution loop, CodeAct
- `src/agent/CLAUDE.md` — agent loop architecture
- `src/llm/CLAUDE.md` — LLM provider architecture
- `src/db/CLAUDE.md` — database dual-backend architecture
- `src/tools/README.md` — tool system architecture
- `src/workspace/README.md` — workspace/memory architecture
### 2. Read current video scenes
Read `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.
### 3. Identify gaps
Compare the architecture documentation with what the video covers. Look for:
- New modules or traits added since the video was last updated
- Renamed or restructured components
- New data flows or state machines
- Removed or deprecated features
## Video project structure
```
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`
## Current scene inventory (12 scenes, ~82s at 30fps)
| # | 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 |
## Remotion patterns used in this project
All animations MUST be driven by `useCurrentFrame()` — never CSS transitions or Tailwind animation classes.
### Animation pattern
```tsx
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),
});
```
### Staggered list pattern
For items that appear one by one:
```tsx
{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>;
})}
```
### Scene transitions
Scenes are composed using `TransitionSeries` with alternating `fade()` and `slide({ direction: "from-right" })` transitions, each 15 frames (0.5s):
```tsx
<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>
```
### Code blocks
Use the `CodeBlock` component from `../components/Code` for syntax-highlighted code:
```tsx
import { CodeBlock } from "../components/Code";
<CodeBlock code={`pub trait Channel: Send + Sync {
async fn start(&self) -> Result<MessageStream>;
}`} fontSize={13} />
```
### Theme
Import colors and fonts from `../theme`:
```tsx
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)
```
## Adding a new scene
1. Create `src/scenes/MyNewScene.tsx` following existing patterns
2. Export the component
3. Import in `IronClawArchitecture.tsx`
4. Add to the `SCENES` array with duration and transition type
5. `TOTAL_DURATION` auto-computes from the array
6. Verify with: `npx remotion still IronClawArchitecture --scale=0.25 --frame=<N>`
### Scene template
```tsx
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>
);
};
```
## Verification
After making changes:
1. **Type check:** `cd docs/architecture-video && npx tsc --noEmit`
2. **Spot check frames:** `npx remotion still IronClawArchitecture --scale=0.25 --frame=<N>`
- At 30fps, frame N corresponds to time N/30 seconds
- Check at least one frame per modified scene
3. **Full render:** `./scripts/render-architecture-video.sh [output-path]`
4. **Preview in browser:** `cd docs/architecture-video && npm run dev`
## Design guidelines
- Dark theme (slate-900 background) — matches typical developer tooling
- Each scene has a colored heading keyword using a trait-appropriate color
- File:line references in muted monospace below headings
- Data flows use staggered animation (0.3-0.5s delays between items)
- State machines use SVG with animated dash-offset for arrows
- Code blocks use the `CodeBlock` component with syntax highlighting
- Keep scene duration proportional to content density (7-10s typical)
- Total video should stay under 120s for attention retention

7
docs/architecture-video/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
node_modules
dist
.DS_Store
.env
# Ignore the output video from Git but not videos you import into src/.
out

View File

@@ -0,0 +1,5 @@
{
"useTabs": false,
"bracketSpacing": true,
"tabWidth": 2
}

View File

@@ -0,0 +1,58 @@
# IronClaw Architecture Overview Video
A Remotion-based animated video that walks new contributors through IronClaw's
internals — the five primitives, execution loop, CodeAct, thread state machine,
skills pipeline, tool dispatcher, channels, extensibility traits, and the LLM
provider decorator chain.
See the project-level render script and Claude skill for end-to-end use:
- `scripts/render-architecture-video.sh` — one-command MP4 render
- `.claude/skills/architecture-video/SKILL.md` — how to update scenes when
architecture changes
## Commands
Install dependencies (first time only):
```console
npm ci
```
Preview in browser (Remotion Studio with hot reload):
```console
npm run dev
```
Render to MP4 from this directory:
```console
npx remotion render IronClawArchitecture out.mp4
```
Or from the repository root:
```console
./scripts/render-architecture-video.sh output.mp4
```
Type-check and lint:
```console
npm run lint
```
## Structure
- `src/IronClawArchitecture.tsx` — scene sequencing, durations, transitions
- `src/scenes/*.tsx` — one file per scene (12 total)
- `src/components/Code.tsx` — shared syntax-highlighted code block
- `src/theme.ts` — shared colors and fonts
- `src/Root.tsx` — Remotion composition registration
## License
This video project is part of IronClaw and dual-licensed MIT OR Apache-2.0.
Remotion itself has a [custom license](https://github.com/remotion-dev/remotion/blob/main/LICENSE.md);
use is covered under the open-source free tier for this project.

View File

@@ -0,0 +1,3 @@
import { config } from "@remotion/eslint-config-flat";
export default config;

4610
docs/architecture-video/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
{
"name": "ironclaw-architecture-video",
"version": "1.0.0",
"description": "My Remotion video",
"repository": {},
"license": "MIT OR Apache-2.0",
"private": true,
"dependencies": {
"@remotion/cli": "4.0.447",
"@remotion/tailwind-v4": "4.0.447",
"@remotion/transitions": "4.0.447",
"react": "19.2.3",
"react-dom": "19.2.3",
"remotion": "4.0.447",
"tailwindcss": "4.0.0"
},
"devDependencies": {
"@remotion/eslint-config-flat": "4.0.447",
"@types/react": "19.2.7",
"@types/web": "0.0.166",
"eslint": "9.19.0",
"prettier": "3.8.1",
"typescript": "5.7.3"
},
"scripts": {
"dev": "remotion studio",
"build": "remotion bundle",
"upgrade": "remotion upgrade",
"lint": "eslint src && tsc"
},
"sideEffects": [
"*.css"
]
}

View File

@@ -0,0 +1,4 @@
import { Config } from "@remotion/cli/config";
Config.setVideoImageFormat("jpeg");
Config.setOverwriteOutput(true);

View File

@@ -0,0 +1,69 @@
import React from "react";
import { TransitionSeries, linearTiming } from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
import { TitleScene } from "./scenes/TitleScene";
import { PrimitivesScene } from "./scenes/PrimitivesScene";
import { ExecutionLoopScene } from "./scenes/ExecutionLoopScene";
import { CodeActScene } from "./scenes/CodeActScene";
import { ThreadStateScene } from "./scenes/ThreadStateScene";
import { SkillsPipelineScene } from "./scenes/SkillsPipelineScene";
import { ToolDispatchScene } from "./scenes/ToolDispatchScene";
import { ChannelsRoutingScene } from "./scenes/ChannelsRoutingScene";
import { ChannelImplsScene } from "./scenes/ChannelImplsScene";
import { TraitsScene } from "./scenes/TraitsScene";
import { LlmDecoratorScene } from "./scenes/LlmDecoratorScene";
import { OutroScene } from "./scenes/OutroScene";
const s = (seconds: number) => Math.round(seconds * 30);
const SCENES = [
{ comp: TitleScene, dur: s(4), transition: fade },
{ comp: PrimitivesScene, dur: s(8), transition: slide },
{ comp: ExecutionLoopScene, dur: s(8), transition: fade },
{ comp: CodeActScene, dur: s(10), transition: slide },
{ comp: ThreadStateScene, dur: s(7), transition: fade },
{ comp: SkillsPipelineScene, dur: s(8), transition: slide },
{ comp: ToolDispatchScene, dur: s(9), transition: fade },
{ comp: ChannelsRoutingScene, dur: s(7), transition: slide },
{ comp: ChannelImplsScene, dur: s(7), transition: fade },
{ comp: TraitsScene, dur: s(8), transition: slide },
{ comp: LlmDecoratorScene, dur: s(7), transition: fade },
{ comp: OutroScene, dur: s(5) },
];
const TRANSITION_DUR = 15;
export const TOTAL_DURATION =
SCENES.reduce((acc, sc) => acc + sc.dur, 0) -
SCENES.filter((sc) => sc.transition).length * TRANSITION_DUR;
export const IronClawArchitecture: React.FC = () => {
return (
<TransitionSeries>
{SCENES.map((sc, i) => {
const Comp = sc.comp;
const isLast = i === SCENES.length - 1;
const presentation = sc.transition
? sc.transition === slide
? slide({ direction: "from-right" })
: fade()
: null;
return (
<React.Fragment key={i}>
<TransitionSeries.Sequence durationInFrames={sc.dur}>
<Comp />
</TransitionSeries.Sequence>
{!isLast && presentation && (
<TransitionSeries.Transition
presentation={presentation}
timing={linearTiming({ durationInFrames: TRANSITION_DUR })}
/>
)}
</React.Fragment>
);
})}
</TransitionSeries>
);
};

View File

@@ -0,0 +1,21 @@
import "./index.css";
import { Composition } from "remotion";
import {
IronClawArchitecture,
TOTAL_DURATION,
} from "./IronClawArchitecture";
export const RemotionRoot: React.FC = () => {
return (
<>
<Composition
id="IronClawArchitecture"
component={IronClawArchitecture}
durationInFrames={TOTAL_DURATION}
fps={30}
width={1280}
height={720}
/>
</>
);
};

View File

@@ -0,0 +1,116 @@
import React, { useMemo } from "react";
import { COLORS, FONTS } from "../theme";
type Token = { text: string; color?: string };
// Very simple tokenizer - colors keywords, strings, comments, types
export const highlight = (code: string): Token[][] => {
const keywords = new Set([
"pub", "fn", "async", "await", "let", "mut", "struct", "enum", "impl",
"trait", "for", "match", "if", "else", "return", "use", "mod", "self",
"Self", "dyn", "Box", "Vec", "Option", "Result", "as", "in", "while",
"loop", "break", "continue", "const", "static", "type", "where",
"def", "class", "import", "from", "None", "True", "False", "await",
"try", "except", "with", "yield", "lambda", "global", "nonlocal",
]);
const types = new Set([
"Thread", "Step", "Capability", "MemoryDoc", "Project", "ThreadId",
"StepId", "String", "u32", "u64", "usize", "bool", "i32", "f64",
"LlmResponse", "ActionCall", "ActionResult", "ThreadEvent", "Uuid",
"ExecutionLoop", "ThreadManager", "CapabilityRegistry", "LeaseManager",
"PolicyEngine", "Store", "IncomingMessage", "OutgoingResponse",
"MessageStream", "Channel", "Tool", "LlmProvider", "Database",
"DispatchSource", "ToolDispatcher", "SafetyLayer", "ActionRecord",
"ExecutionTier", "ThreadState", "ThreadConfig",
]);
return code.split("\n").map((line) => {
const tokens: Token[] = [];
let i = 0;
while (i < line.length) {
// Comments
if (line.slice(i).startsWith("//") || line.slice(i).startsWith("#")) {
tokens.push({ text: line.slice(i), color: COLORS.textMuted });
break;
}
// Strings
if (line[i] === '"' || line[i] === "'") {
const quote = line[i];
let end = i + 1;
while (end < line.length && line[end] !== quote) end++;
tokens.push({
text: line.slice(i, end + 1),
color: COLORS.success,
});
i = end + 1;
continue;
}
// Words
if (/[a-zA-Z_]/.test(line[i])) {
let end = i;
while (end < line.length && /[a-zA-Z0-9_]/.test(line[end])) end++;
const word = line.slice(i, end);
let color: string | undefined;
if (keywords.has(word)) color = COLORS.purple;
else if (types.has(word)) color = COLORS.cyan;
else if (line[end] === "(") color = COLORS.accentLight;
tokens.push({ text: word, color });
i = end;
continue;
}
// Numbers
if (/[0-9]/.test(line[i])) {
let end = i;
while (end < line.length && /[0-9.]/.test(line[end])) end++;
tokens.push({ text: line.slice(i, end), color: COLORS.accent });
i = end;
continue;
}
// Other
tokens.push({ text: line[i] });
i++;
}
return tokens;
});
};
export const CodeBlock: React.FC<{
code: string;
fontSize?: number;
opacity?: number;
style?: React.CSSProperties;
}> = ({ code, fontSize = 15, opacity = 1, style = {} }) => {
// Memoize tokenization — Remotion re-renders every frame and `code` is static.
const lines = useMemo(() => highlight(code), [code]);
return (
<div
style={{
fontFamily: FONTS.mono,
fontSize,
lineHeight: 1.55,
backgroundColor: "#0b1120",
border: `1px solid ${COLORS.border}`,
borderRadius: 10,
padding: "16px 20px",
color: COLORS.text,
whiteSpace: "pre",
opacity,
...style,
}}
>
{lines.map((tokens, li) => (
<div key={li}>
{tokens.length === 0 ? (
<span>&nbsp;</span>
) : (
tokens.map((t, ti) => (
<span key={ti} style={{ color: t.color || COLORS.text }}>
{t.text}
</span>
))
)}
</div>
))}
</div>
);
};

View File

@@ -0,0 +1 @@
@import "tailwindcss";

View File

@@ -0,0 +1,4 @@
import { registerRoot } from "remotion";
import { RemotionRoot } from "./Root";
registerRoot(RemotionRoot);

View File

@@ -0,0 +1,187 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const CHANNELS = [
{
icon: "⌨",
name: "REPL",
file: "src/channels/repl.rs",
input: "stdin via rustyline",
output: "stdout + termimad markdown",
color: COLORS.primary,
},
{
icon: "🌐",
name: "HTTP",
file: "src/channels/http.rs",
input: "POST + HMAC-SHA256 validation",
output: "oneshot response channel",
color: COLORS.cyan,
},
{
icon: "💻",
name: "Web",
file: "src/channels/web/mod.rs",
input: "SSE/WebSocket + bearer auth",
output: "SseManager::broadcast_for_user()",
color: COLORS.accent,
},
{
icon: "📱",
name: "Signal",
file: "src/channels/signal.rs",
input: "signal-cli SSE /api/v1/events",
output: "JSON-RPC to /api/v1/rpc",
color: COLORS.success,
},
{
icon: "📺",
name: "TUI",
file: "src/channels/cli/ (ratatui)",
input: "crossterm key + mouse events",
output: "direct buffer render",
color: COLORS.purple,
},
{
icon: "🧩",
name: "WASM",
file: "src/channels/wasm/wrapper.rs",
input: "dynamic module + host_bridge",
output: "host bridge callbacks",
color: COLORS.pink,
},
];
export const ChannelImplsScene: 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.cyan }}>Channel</span> implementations
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 30,
fontFamily: FONTS.mono,
}}
>
each implements the same 8-method trait &bull; plugged via
ChannelManager::register()
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: 16,
flex: 1,
}}
>
{CHANNELS.map((c, i) => {
const delay = 0.4 + i * 0.3;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const y = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[30, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={c.name}
style={{
opacity,
transform: `translateY(${y}px)`,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderTop: `4px solid ${c.color}`,
borderRadius: 12,
padding: "18px 22px",
display: "flex",
flexDirection: "column",
gap: 10,
}}
>
<div
style={{
display: "flex",
alignItems: "center",
gap: 12,
}}
>
<div style={{ fontSize: 28 }}>{c.icon}</div>
<div
style={{
fontSize: 22,
fontWeight: 800,
color: c.color,
}}
>
{c.name}
</div>
</div>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
{c.file}
</div>
<div style={{ fontSize: 12, marginTop: 4 }}>
<div style={{ color: COLORS.success, marginBottom: 4 }}>
<span style={{ color: COLORS.textMuted }}>in:</span>{" "}
{c.input}
</div>
<div style={{ color: COLORS.accent }}>
<span style={{ color: COLORS.textMuted }}>out:</span>{" "}
{c.output}
</div>
</div>
</div>
);
})}
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,187 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
import { CodeBlock } from "../components/Code";
const TRAIT_CODE = `// Simplified — see src/channels/channel.rs
pub trait Channel: Send + Sync {
fn name(&self) -> &str;
async fn start(&self) -> Result<MessageStream, ChannelError>;
async fn respond(&self, msg: &IncomingMessage,
resp: OutgoingResponse) -> Result<()>;
async fn send_status(&self, s: StatusUpdate,
meta: &Value) -> Result<()>;
async fn broadcast(&self, user_id: &str,
resp: OutgoingResponse) -> Result<()>;
async fn health_check(&self) -> Result<()>;
fn conversation_context(&self, meta: &Value)
-> HashMap<String, String>;
async fn shutdown(&self) -> Result<()>;
}`;
const MERGE_CODE = `// ChannelManager::start_all()
let streams: Vec<MessageStream> = channels
.iter()
.map(|c| c.start())
.collect().await?;
// Merge N channels into 1 stream
stream::select_all(streams)`;
export const ChannelsRoutingScene: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const headingOpacity = interpolate(frame, [0, 0.4 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const leftOpacity = interpolate(frame, [0.5 * fps, 1.2 * fps], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const leftX = interpolate(frame, [0.5 * fps, 1.2 * fps], [-30, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const rightOpacity = interpolate(frame, [1.5 * fps, 2.2 * fps], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const rightX = interpolate(frame, [1.5 * fps, 2.2 * fps], [30, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const routingOpacity = interpolate(
frame,
[2.8 * fps, 3.5 * fps],
[0, 1],
{ extrapolateLeft: "clamp", 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.cyan }}>Channels</span> &mdash; trait +
stream merging
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 20,
fontFamily: FONTS.mono,
}}
>
src/channels/channel.rs &bull; src/channels/manager.rs
</div>
<div
style={{
position: "absolute",
left: 60,
top: 150,
width: 640,
opacity: leftOpacity,
transform: `translateX(${leftX}px)`,
}}
>
<div
style={{
fontSize: 12,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 6,
textTransform: "uppercase",
letterSpacing: 2,
}}
>
Channel trait (8 methods)
</div>
<CodeBlock code={TRAIT_CODE} fontSize={13} />
</div>
<div
style={{
position: "absolute",
right: 60,
top: 150,
width: 470,
opacity: rightOpacity,
transform: `translateX(${rightX}px)`,
}}
>
<div
style={{
fontSize: 12,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 6,
textTransform: "uppercase",
letterSpacing: 2,
}}
>
stream::select_all merges N1
</div>
<CodeBlock code={MERGE_CODE} fontSize={13} />
<div
style={{
marginTop: 20,
opacity: routingOpacity,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderLeft: `4px solid ${COLORS.accent}`,
borderRadius: 8,
padding: "14px 18px",
}}
>
<div
style={{
fontSize: 14,
fontWeight: 700,
color: COLORS.accent,
marginBottom: 8,
}}
>
routing_target_from_metadata()
</div>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
lineHeight: 1.7,
}}
>
signal_target chat_id channel_id target
</div>
</div>
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,341 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
Sequence,
} from "remotion";
import { COLORS, FONTS } from "../theme";
import { CodeBlock } from "../components/Code";
const PYTHON_CODE = `# Monty VM (NOT CPython) - injected context:
# context, goal, step_number, user_timezone
search = await web_search(query=goal)
summary = llm_query(
prompt="Summarize findings",
context=search
)
if needs_approval(summary):
mission_create(
name="follow_up",
cadence="0 9 * * *",
)
FINAL(summary)`;
const HOST_FNS = [
"__execute_action__(name, params)",
"__list_skills__()",
"__llm_query__(prompt, context)",
"__memory_search__(query)",
"__policy_check__(action)",
];
export const CodeActScene: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const headingOpacity = interpolate(frame, [0, 0.4 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const codeOpacity = interpolate(
frame,
[0.5 * fps, 1.2 * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const codeX = interpolate(frame, [0.5 * fps, 1.2 * fps], [-30, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const arrowProgress = interpolate(
frame,
[2.5 * fps, 3.2 * fps],
[0, 1],
{ extrapolateLeft: "clamp", 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.accent }}>CodeAct</span> &mdash; LLM
writes Python, Monty executes
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 24,
fontFamily: FONTS.mono,
}}
>
crates/ironclaw_engine/prompts/codeact_preamble.md &bull;
crates/ironclaw_engine/src/executor/orchestrator.rs
</div>
{/* Left: Python code */}
<div
style={{
position: "absolute",
left: 60,
top: 160,
width: 560,
opacity: codeOpacity,
transform: `translateX(${codeX}px)`,
}}
>
<div
style={{
fontSize: 14,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 8,
textTransform: "uppercase",
letterSpacing: 2,
}}
>
LLM output
</div>
<CodeBlock code={PYTHON_CODE} fontSize={14} />
</div>
{/* Arrow */}
<svg
width="120"
height="60"
style={{
position: "absolute",
left: 620,
top: 380,
opacity: arrowProgress,
}}
>
<line
x1={0}
y1={30}
x2={100}
y2={30}
stroke={COLORS.accent}
strokeWidth={3}
strokeDasharray={100}
strokeDashoffset={100 * (1 - arrowProgress)}
/>
<polygon
points="100,22 115,30 100,38"
fill={COLORS.accent}
opacity={arrowProgress > 0.8 ? 1 : 0}
/>
</svg>
{/* Right: Host function dispatch */}
<Sequence from={Math.round(2.8 * fps)} layout="none">
<HostFnPanel />
</Sequence>
{/* Bottom: suspension flow */}
<Sequence from={Math.round(5.5 * fps)} layout="none">
<SuspendFlow />
</Sequence>
</AbsoluteFill>
);
};
const HostFnPanel: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const opacity = interpolate(frame, [0, 0.5 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const x = interpolate(frame, [0, 0.5 * fps], [30, 0], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
return (
<div
style={{
position: "absolute",
left: 760,
top: 160,
width: 440,
opacity,
transform: `translateX(${x}px)`,
}}
>
<div
style={{
fontSize: 14,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 8,
textTransform: "uppercase",
letterSpacing: 2,
}}
>
Rust host functions
</div>
<div
style={{
backgroundColor: "#0b1120",
border: `1px solid ${COLORS.border}`,
borderRadius: 10,
padding: 20,
}}
>
{HOST_FNS.map((fn, i) => {
const delay = 0.2 + i * 0.2;
const itemOpacity = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
return (
<div
key={fn}
style={{
opacity: itemOpacity,
fontSize: 13,
color: COLORS.cyan,
fontFamily: FONTS.mono,
padding: "6px 0",
borderBottom:
i < HOST_FNS.length - 1
? `1px solid ${COLORS.border}`
: "none",
}}
>
<span style={{ color: COLORS.purple }}>fn</span> {fn}
</div>
);
})}
</div>
</div>
);
};
const SuspendFlow: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const boxes = [
{ label: "Python suspends", color: COLORS.accent },
{ label: "Lease check", color: COLORS.danger },
{ label: "Policy check", color: COLORS.danger },
{ label: "ToolDispatcher", color: COLORS.primary },
{ label: "Result → Python", color: COLORS.success },
];
return (
<div
style={{
position: "absolute",
left: 60,
right: 60,
bottom: 60,
}}
>
<div
style={{
fontSize: 14,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 10,
textTransform: "uppercase",
letterSpacing: 2,
}}
>
Suspend execute resume
</div>
<div
style={{
display: "flex",
alignItems: "center",
gap: 6,
}}
>
{boxes.map((b, i) => {
const delay = 0.3 + i * 0.35;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const scale = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0.85, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={b.label}
style={{
display: "flex",
alignItems: "center",
gap: 6,
}}
>
<div
style={{
opacity,
transform: `scale(${scale})`,
backgroundColor: COLORS.bgLight,
border: `2px solid ${b.color}`,
borderRadius: 8,
padding: "10px 14px",
fontSize: 13,
fontWeight: 700,
color: b.color,
fontFamily: FONTS.mono,
whiteSpace: "nowrap",
}}
>
{b.label}
</div>
{i < boxes.length - 1 && (
<div
style={{
opacity: opacity * 0.7,
fontSize: 20,
color: COLORS.textMuted,
}}
>
</div>
)}
</div>
);
})}
</div>
</div>
);
};

View File

@@ -0,0 +1,185 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const STEPS = [
{ n: 1, label: "Load checkpoint", detail: "resume from prior run" },
{ n: 2, label: "Transition → Running", detail: "ThreadState state machine" },
{ n: 3, label: "Pre-fetch memory docs", detail: "shared context injection" },
{ n: 4, label: "Inject CodeAct prompt", detail: "preamble + actions from leases" },
{ n: 5, label: "Load Python orchestrator", detail: "versioned, self-modify opt-in" },
{ n: 6, label: "execute_orchestrator()", detail: "Monty VM runs user code" },
{ n: 7, label: "Persist state + events", detail: "never deleted, full audit" },
];
export const ExecutionLoopScene: 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.cyan }}>ExecutionLoop::run()</span>
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 30,
fontFamily: FONTS.mono,
}}
>
crates/ironclaw_engine/src/executor/loop_engine.rs:188
</div>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 14,
}}
>
{STEPS.map((s, i) => {
const delay = 0.4 + i * 0.5;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const scale = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0.92, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
// Connector line between steps
const lineProgress =
i < STEPS.length - 1
? interpolate(
frame,
[(delay + 0.3) * fps, (delay + 0.55) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
)
: 0;
return (
<div
key={s.n}
style={{
position: "relative",
opacity,
transform: `scale(${scale})`,
transformOrigin: "left center",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
gap: 20,
}}
>
<div
style={{
width: 44,
height: 44,
borderRadius: "50%",
backgroundColor: COLORS.cyan,
color: COLORS.bg,
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: 18,
fontWeight: 800,
flexShrink: 0,
fontFamily: FONTS.mono,
}}
>
{s.n}
</div>
<div
style={{
flex: 1,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderRadius: 8,
padding: "10px 20px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<div
style={{
fontSize: 18,
fontWeight: 700,
color: COLORS.text,
fontFamily: FONTS.mono,
}}
>
{s.label}
</div>
<div
style={{
fontSize: 13,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
{s.detail}
</div>
</div>
</div>
{i < STEPS.length - 1 && (
<div
style={{
position: "absolute",
left: 22,
top: 44,
width: 2,
height: 14,
backgroundColor: COLORS.cyan,
opacity: lineProgress,
transformOrigin: "top",
transform: `scaleY(${lineProgress})`,
}}
/>
)}
</div>
);
})}
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,199 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const LAYERS = [
{
name: "SmartRouting",
desc: "pick provider by cost/latency/capability",
color: COLORS.primary,
},
{
name: "CircuitBreaker",
desc: "fail fast on downstream outage",
color: COLORS.danger,
},
{
name: "Retry",
desc: "exponential backoff + jitter",
color: COLORS.accent,
},
{
name: "Failover",
desc: "secondary provider on primary failure",
color: COLORS.purple,
},
{
name: "Cached",
desc: "prompt-hash cache for deterministic calls",
color: COLORS.cyan,
},
{
name: "TokenRefreshing",
desc: "OAuth token rotation",
color: COLORS.success,
},
{
name: "Base Provider",
desc: "Anthropic / OpenAI / Bedrock / NearAi / Ollama",
color: COLORS.pink,
base: true,
},
];
export const LlmDecoratorScene: 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 }}>LlmProvider</span> &mdash;
decorator chain
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 30,
fontFamily: FONTS.mono,
}}
>
src/llm/provider.rs &bull; each decorator wraps the next, same trait
</div>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 0,
maxWidth: 900,
margin: "0 auto",
width: "100%",
}}
>
{LAYERS.map((layer, i) => {
const delay = 0.3 + i * 0.35;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const scale = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0.9, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
const indent = layer.base ? 0 : i * 8;
return (
<div
key={layer.name}
style={{
opacity,
transform: `scale(${scale})`,
marginLeft: indent,
marginRight: indent,
backgroundColor: layer.base
? `${layer.color}20`
: COLORS.bgLight,
border: `2px solid ${layer.color}`,
borderRadius: 10,
padding: "12px 22px",
display: "flex",
alignItems: "center",
gap: 16,
marginBottom: 6,
}}
>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
minWidth: 24,
}}
>
{layer.base ? "■" : `${i + 1}.`}
</div>
<div
style={{
fontSize: 18,
fontWeight: 800,
color: layer.color,
fontFamily: FONTS.mono,
minWidth: 220,
}}
>
{layer.name}
</div>
<div
style={{
fontSize: 13,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
{layer.desc}
</div>
</div>
);
})}
</div>
{(() => {
const flowOpacity = interpolate(
frame,
[3.5 * fps, 4.0 * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
return (
<div
style={{
opacity: flowOpacity,
textAlign: "center",
marginTop: 16,
fontSize: 13,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
agent top of chain ... base provider HTTP call
</div>
);
})()}
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,195 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const STEPS = [
{ cmd: "git clone", desc: "Clone the repo" },
{ cmd: "cargo test", desc: "Run the test suite" },
{ cmd: "cargo run", desc: "Start the assistant" },
{ cmd: "Read CLAUDE.md", desc: "Module specs are your guide" },
];
export const OutroScene: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const titleOpacity = interpolate(frame, [0, 0.5 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const titleY = interpolate(frame, [0, 0.5 * fps], [30, 0], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const lineWidth = interpolate(frame, [0.6 * fps, 1.2 * fps], [0, 300], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const footerOpacity = interpolate(
frame,
[3.0 * fps, 3.5 * fps],
[0, 1],
{ extrapolateRight: "clamp" },
);
return (
<AbsoluteFill
style={{
backgroundColor: COLORS.bg,
fontFamily: FONTS.sans,
justifyContent: "center",
alignItems: "center",
}}
>
{/* Grid background */}
<AbsoluteFill
style={{
opacity: 0.05,
backgroundImage: `linear-gradient(${COLORS.primary} 1px, transparent 1px), linear-gradient(90deg, ${COLORS.primary} 1px, transparent 1px)`,
backgroundSize: "60px 60px",
}}
/>
{/* Glow */}
<div
style={{
position: "absolute",
width: 500,
height: 500,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLORS.accent}15 0%, transparent 70%)`,
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
}}
/>
<div
style={{
opacity: titleOpacity,
transform: `translateY(${titleY}px)`,
fontSize: 52,
fontWeight: 800,
color: COLORS.text,
marginBottom: 12,
textAlign: "center",
}}
>
Start <span style={{ color: COLORS.accent }}>Contributing</span>
</div>
<div
style={{
width: lineWidth,
height: 3,
backgroundColor: COLORS.accent,
borderRadius: 2,
marginBottom: 48,
}}
/>
{/* Getting started steps */}
<div
style={{
display: "flex",
flexDirection: "column",
gap: 16,
width: 600,
}}
>
{STEPS.map((step, i) => {
const delay = 1.0 + i * 0.35;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const x = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[20, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={step.cmd}
style={{
opacity,
transform: `translateX(${x}px)`,
display: "flex",
alignItems: "center",
gap: 20,
}}
>
<div
style={{
width: 36,
height: 36,
borderRadius: "50%",
backgroundColor: COLORS.accent,
color: COLORS.bg,
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: 18,
fontWeight: 800,
flexShrink: 0,
}}
>
{i + 1}
</div>
<div
style={{
fontSize: 20,
fontWeight: 700,
color: COLORS.primary,
fontFamily: FONTS.mono,
minWidth: 200,
}}
>
{step.cmd}
</div>
<div
style={{
fontSize: 16,
color: COLORS.textMuted,
}}
>
{step.desc}
</div>
</div>
);
})}
</div>
{/* Footer */}
<div
style={{
position: "absolute",
bottom: 60,
opacity: footerOpacity,
fontSize: 18,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
textAlign: "center",
}}
>
Built with Rust + Tokio &bull; All I/O is async &bull; cargo fmt
&amp;&amp; cargo clippy &amp;&amp; cargo test
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,178 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const PRIMITIVES = [
{
name: "Thread",
replaces: "Session + Job + Routine + Sub-agent",
desc: "Unit of work. Has state, config, messages, leases, events.",
color: COLORS.primary,
file: "crates/ironclaw_engine/src/types/thread.rs",
},
{
name: "Step",
replaces: "Turn + LLM Call + Tool Call",
desc: "Unit of execution. LLM call + subsequent action executions.",
color: COLORS.cyan,
file: "crates/ironclaw_engine/src/types/step.rs",
},
{
name: "Capability",
replaces: "Tool + Skill + Hook",
desc: "Unit of effect with leases and policies.",
color: COLORS.accent,
file: "crates/ironclaw_engine/src/capability/",
},
{
name: "MemoryDoc",
replaces: "Summary + Lesson + Skill + Note",
desc: "Durable knowledge. Injected into context on thread start.",
color: COLORS.success,
file: "crates/ironclaw_engine/src/types/memory.rs",
},
{
name: "Project",
replaces: "Workspace + Namespace",
desc: "Context scope. Owns memory, threads, missions.",
color: COLORS.purple,
file: "crates/ironclaw_engine/src/types/project.rs",
},
];
export const PrimitivesScene: 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: 8,
}}
>
<span style={{ color: COLORS.primary }}>Engine v2</span> &mdash; Five
Primitives
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 16,
color: COLORS.textMuted,
marginBottom: 36,
fontFamily: FONTS.mono,
}}
>
crates/ironclaw_engine/ &mdash; replaces ~10 v1 abstractions
</div>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 14,
}}
>
{PRIMITIVES.map((p, i) => {
const delay = 0.4 + i * 0.35;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.4) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const x = interpolate(
frame,
[delay * fps, (delay + 0.4) * fps],
[-40, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={p.name}
style={{
opacity,
transform: `translateX(${x}px)`,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderLeft: `5px solid ${p.color}`,
borderRadius: 10,
padding: "16px 24px",
display: "flex",
alignItems: "center",
gap: 24,
}}
>
<div
style={{
fontSize: 26,
fontWeight: 800,
color: p.color,
fontFamily: FONTS.mono,
minWidth: 180,
}}
>
{p.name}
</div>
<div style={{ flex: 1 }}>
<div
style={{
fontSize: 15,
color: COLORS.text,
marginBottom: 4,
}}
>
{p.desc}
</div>
<div
style={{
fontSize: 12,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
replaces: {p.replaces}
</div>
</div>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
maxWidth: 260,
textAlign: "right",
}}
>
{p.file}
</div>
</div>
);
})}
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,224 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const STAGES = [
{
n: 1,
name: "Gating",
color: COLORS.cyan,
desc: "Check requires: bins, env, config",
detail: "Skip skills whose prerequisites are missing",
example: "requires: { bins: [ffmpeg], env: [API_KEY] }",
},
{
n: 2,
name: "Scoring",
color: COLORS.primary,
desc: "Deterministic relevance score",
detail: "keywords (10/5, cap 30) + patterns (20, cap 40) + tags (3, cap 15)",
example: "exclude_keywords veto → score = 0",
},
{
n: 3,
name: "Budget",
color: COLORS.accent,
desc: "Fit within SKILLS_MAX_TOKENS",
detail: "Select top-scoring skills within prompt budget",
example: "num_tokens_from_string(frontmatter + body)",
},
{
n: 4,
name: "Attenuation",
color: COLORS.danger,
desc: "Minimum trust determines tool ceiling",
detail: "Trusted: all tools | Installed: read-only only",
example: "memory_search, memory_read, time, echo, json",
},
];
export const SkillsPipelineScene: 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.accentLight }}>Skills</span> &mdash;
selection pipeline
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 30,
fontFamily: FONTS.mono,
}}
>
src/skills/ &bull; SKILL.md + YAML frontmatter &bull; called from Python
via __list_skills__()
</div>
<div
style={{
display: "flex",
gap: 12,
flex: 1,
alignItems: "stretch",
}}
>
{STAGES.map((s, i) => {
const delay = 0.4 + i * 0.45;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.4) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const y = interpolate(
frame,
[delay * fps, (delay + 0.4) * fps],
[30, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
const arrowProgress =
i < STAGES.length - 1
? interpolate(
frame,
[(delay + 0.3) * fps, (delay + 0.55) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
)
: 0;
return (
<div
key={s.n}
style={{
flex: 1,
position: "relative",
display: "flex",
}}
>
<div
style={{
flex: 1,
opacity,
transform: `translateY(${y}px)`,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderTop: `4px solid ${s.color}`,
borderRadius: 12,
padding: "20px 22px",
display: "flex",
flexDirection: "column",
}}
>
<div
style={{
fontSize: 12,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginBottom: 4,
}}
>
STAGE {s.n}
</div>
<div
style={{
fontSize: 26,
fontWeight: 800,
color: s.color,
marginBottom: 12,
}}
>
{s.name}
</div>
<div
style={{
fontSize: 14,
color: COLORS.text,
marginBottom: 14,
fontWeight: 600,
}}
>
{s.desc}
</div>
<div
style={{
fontSize: 12,
color: COLORS.textMuted,
marginBottom: 18,
lineHeight: 1.5,
}}
>
{s.detail}
</div>
<div
style={{
marginTop: "auto",
fontSize: 11,
color: s.color,
fontFamily: FONTS.mono,
backgroundColor: "#0b1120",
padding: "8px 10px",
borderRadius: 6,
border: `1px solid ${COLORS.border}`,
}}
>
{s.example}
</div>
</div>
{i < STAGES.length - 1 && (
<div
style={{
position: "absolute",
right: -14,
top: "50%",
transform: `translateY(-50%) scaleX(${arrowProgress})`,
transformOrigin: "left",
fontSize: 28,
color: s.color,
fontWeight: 800,
opacity: arrowProgress,
zIndex: 10,
}}
>
</div>
)}
</div>
);
})}
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,202 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
type State = {
label: string;
x: number;
y: number;
color: string;
};
const STATES: State[] = [
{ label: "Created", x: 50, y: 230, color: COLORS.textMuted },
{ label: "Running", x: 270, y: 230, color: COLORS.primary },
{ label: "Waiting", x: 510, y: 110, color: COLORS.accent },
{ label: "Suspended", x: 510, y: 350, color: COLORS.pink },
{ label: "Completed", x: 780, y: 150, color: COLORS.success },
{ label: "Failed", x: 780, y: 330, color: COLORS.danger },
{ label: "Done", x: 1000, y: 230, color: COLORS.cyan },
];
type Edge = { from: number; to: number; label?: string };
const EDGES: Edge[] = [
{ from: 0, to: 1, label: "spawn" },
{ from: 1, to: 2, label: "await tool" },
{ from: 1, to: 3, label: "checkpoint" },
{ from: 2, to: 1, label: "result" },
{ from: 3, to: 1, label: "resume" },
{ from: 1, to: 4, label: "FINAL()" },
{ from: 1, to: 5, label: "error" },
{ from: 4, to: 6 },
{ from: 5, to: 6 },
];
const NODE_W = 150;
const NODE_H = 52;
export const ThreadStateScene: 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 }}>ThreadState</span> &mdash;
state machine
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 24,
fontFamily: FONTS.mono,
}}
>
crates/ironclaw_engine/src/types/thread.rs &bull; events persisted to
Store (never deleted)
</div>
<svg
width="1160"
height="500"
viewBox="0 0 1160 500"
style={{ position: "absolute", top: 130, left: 60 }}
>
<defs>
<marker
id="ts-arrow"
markerWidth="8"
markerHeight="6"
refX="8"
refY="3"
orient="auto"
>
<polygon points="0 0, 8 3, 0 6" fill={COLORS.border} />
</marker>
</defs>
{EDGES.map((edge, i) => {
const from = STATES[edge.from];
const to = STATES[edge.to];
const fromCx = from.x + NODE_W / 2;
const fromCy = from.y + NODE_H / 2;
const toCx = to.x + NODE_W / 2;
const toCy = to.y + NODE_H / 2;
const delay = 0.8 + i * 0.25;
const progress = interpolate(
frame,
[delay * fps, (delay + 0.4) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const len = Math.sqrt(
(toCx - fromCx) ** 2 + (toCy - fromCy) ** 2,
);
return (
<g key={i} opacity={progress}>
<line
x1={fromCx}
y1={fromCy}
x2={toCx}
y2={toCy}
stroke={COLORS.border}
strokeWidth={2}
strokeDasharray={len}
strokeDashoffset={len * (1 - progress)}
markerEnd="url(#ts-arrow)"
/>
{edge.label && (
<text
x={(fromCx + toCx) / 2}
y={(fromCy + toCy) / 2 - 6}
fill={COLORS.textMuted}
fontSize={11}
fontFamily={FONTS.mono}
textAnchor="middle"
opacity={progress > 0.6 ? (progress - 0.6) * 2.5 : 0}
>
{edge.label}
</text>
)}
</g>
);
})}
</svg>
{STATES.map((s, i) => {
const delay = 0.3 + i * 0.2;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const scale = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0.85, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={s.label}
style={{
position: "absolute",
left: 60 + s.x,
top: 130 + s.y,
width: NODE_W,
height: NODE_H,
opacity,
transform: `scale(${scale})`,
backgroundColor: COLORS.bgLight,
border: `2px solid ${s.color}`,
borderRadius: 10,
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: 16,
fontWeight: 700,
color: s.color,
fontFamily: FONTS.mono,
}}
>
{s.label}
</div>
);
})}
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,152 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
export const TitleScene: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const titleY = interpolate(frame, [0, 1 * fps], [60, 0], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const titleOpacity = interpolate(frame, [0, 0.6 * fps], [0, 1], {
extrapolateRight: "clamp",
});
const subtitleOpacity = interpolate(
frame,
[0.5 * fps, 1.2 * fps],
[0, 1],
{ extrapolateRight: "clamp" },
);
const subtitleY = interpolate(frame, [0.5 * fps, 1.2 * fps], [30, 0], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const lineWidth = interpolate(frame, [0.8 * fps, 1.6 * fps], [0, 400], {
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
});
const taglineOpacity = interpolate(
frame,
[1.4 * fps, 2.0 * fps],
[0, 1],
{ extrapolateRight: "clamp" },
);
// Animated grid background
const gridOpacity = interpolate(frame, [0, 1 * fps], [0, 0.08], {
extrapolateRight: "clamp",
});
return (
<AbsoluteFill
style={{
backgroundColor: COLORS.bg,
justifyContent: "center",
alignItems: "center",
fontFamily: FONTS.sans,
}}
>
{/* Grid background */}
<AbsoluteFill
style={{
opacity: gridOpacity,
backgroundImage: `linear-gradient(${COLORS.primary} 1px, transparent 1px), linear-gradient(90deg, ${COLORS.primary} 1px, transparent 1px)`,
backgroundSize: "60px 60px",
}}
/>
{/* Glow effect */}
<div
style={{
position: "absolute",
width: 600,
height: 600,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLORS.primary}20 0%, transparent 70%)`,
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
}}
/>
{/* Claw icon */}
<div
style={{
opacity: titleOpacity,
transform: `translateY(${titleY}px)`,
fontSize: 64,
marginBottom: 20,
}}
>
🦀
</div>
{/* Title */}
<div
style={{
opacity: titleOpacity,
transform: `translateY(${titleY}px)`,
fontSize: 80,
fontWeight: 800,
color: COLORS.text,
letterSpacing: -2,
}}
>
<span style={{ color: COLORS.primary }}>Iron</span>
<span style={{ color: COLORS.accent }}>Claw</span>
</div>
{/* Divider line */}
<div
style={{
width: lineWidth,
height: 3,
backgroundColor: COLORS.primary,
marginTop: 16,
marginBottom: 16,
borderRadius: 2,
}}
/>
{/* Subtitle */}
<div
style={{
opacity: subtitleOpacity,
transform: `translateY(${subtitleY}px)`,
fontSize: 32,
fontWeight: 600,
color: COLORS.textMuted,
letterSpacing: 6,
textTransform: "uppercase",
}}
>
Architecture Overview
</div>
{/* Tagline */}
<div
style={{
opacity: taglineOpacity,
fontSize: 20,
color: COLORS.textMuted,
marginTop: 40,
fontFamily: FONTS.mono,
}}
>
Secure Personal AI Assistant &mdash; A Contributor&apos;s Guide
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,232 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const STEPS = [
{
n: 1,
label: "Tool resolution",
code: "ToolRegistry::get_resolved(name)",
color: COLORS.cyan,
},
{
n: 2,
label: "Param normalization",
code: "prepare_tool_params()",
color: COLORS.cyan,
},
{
n: 3,
label: "Injection validation",
code: "SafetyLayer::validate_tool_params()",
color: COLORS.danger,
},
{
n: 4,
label: "Schema validation",
code: "jsonschema::validate(schema, params)",
color: COLORS.primary,
},
{
n: 5,
label: "Sensitive param redaction",
code: "redact_params() → [REDACTED]",
color: COLORS.danger,
},
{
n: 6,
label: "System job creation",
code: "store.create_system_job(user, src)",
color: COLORS.success,
},
{
n: 7,
label: "Execute with timeout",
code: "timeout(tool.execution_timeout(), ...)",
color: COLORS.accent,
},
{
n: 8,
label: "Output sanitization",
code: "SafetyLayer::sanitize_tool_output()",
color: COLORS.danger,
},
{
n: 9,
label: "Audit persistence",
code: "store.save_action(job_id, &action)",
color: COLORS.success,
},
];
export const ToolDispatchScene: 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.accent }}>ToolDispatcher::dispatch()</span>
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 22,
fontFamily: FONTS.mono,
}}
>
src/tools/dispatch.rs:116 &bull; every action (channel / routine /
system) flows through this
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: 12,
flex: 1,
}}
>
{STEPS.map((s, i) => {
const delay = 0.3 + i * 0.3;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const scale = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0.9, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={s.n}
style={{
opacity,
transform: `scale(${scale})`,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderLeft: `4px solid ${s.color}`,
borderRadius: 10,
padding: "14px 18px",
display: "flex",
flexDirection: "column",
gap: 6,
}}
>
<div
style={{
display: "flex",
alignItems: "center",
gap: 10,
}}
>
<div
style={{
width: 26,
height: 26,
borderRadius: "50%",
backgroundColor: s.color,
color: COLORS.bg,
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: 13,
fontWeight: 800,
fontFamily: FONTS.mono,
flexShrink: 0,
}}
>
{s.n}
</div>
<div
style={{
fontSize: 16,
fontWeight: 700,
color: COLORS.text,
}}
>
{s.label}
</div>
</div>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
marginLeft: 36,
}}
>
{s.code}
</div>
</div>
);
})}
</div>
{/* Key insight callout */}
{(() => {
const calloutOpacity = interpolate(
frame,
[3.5 * fps, 4.2 * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
return (
<div
style={{
opacity: calloutOpacity,
marginTop: 16,
fontSize: 13,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
backgroundColor: `${COLORS.accent}10`,
border: `1px solid ${COLORS.accent}40`,
borderRadius: 8,
padding: "10px 16px",
}}
>
<span style={{ color: COLORS.accent, fontWeight: 700 }}>
Key:{" "}
</span>
Tools receive raw params, audit row gets redacted params +
sanitized output
</div>
);
})()}
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,194 @@
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
Easing,
} from "remotion";
import { COLORS, FONTS } from "../theme";
const TRAITS = [
{
name: "Database",
file: "src/db/mod.rs",
impls: ["PgBackend", "LibSqlBackend"],
},
{
name: "Tool",
file: "src/tools/tool.rs",
impls: ["60+ builtins", "McpToolWrapper", "WasmToolWrapper"],
},
{
name: "LlmProvider",
file: "src/llm/provider.rs",
impls: ["Anthropic", "OpenAI", "Bedrock", "NearAi", "+ 11 decorators"],
},
{
name: "EmbeddingProvider",
file: "src/workspace/embeddings.rs",
impls: ["OpenAi", "NearAi", "Bedrock", "Ollama", "Cached"],
},
{
name: "NetworkPolicyDecider",
file: "src/sandbox/proxy/policy.rs",
impls: ["Default", "AllowAll", "DenyAll"],
},
{
name: "Hook",
file: "src/hooks/hook.rs",
impls: ["AuditLog", "Rule", "OutboundWebhook", "SessionStart"],
},
{
name: "Observer",
file: "src/observability/traits.rs",
impls: ["Noop", "Log", "Multi"],
},
{
name: "Tunnel",
file: "src/tunnel/mod.rs",
impls: ["None", "Cloudflare", "Ngrok", "Tailscale", "Custom"],
},
];
export const TraitsScene: 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.purple }}>Extensibility</span> &mdash;
traits + implementers
</div>
<div
style={{
opacity: headingOpacity,
fontSize: 14,
color: COLORS.textMuted,
marginBottom: 24,
fontFamily: FONTS.mono,
}}
>
impl YourTrait for YourType &mdash; plug in without touching core
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 12,
flex: 1,
}}
>
{TRAITS.map((t, i) => {
const delay = 0.4 + i * 0.22;
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const x = interpolate(
frame,
[delay * fps, (delay + 0.35) * fps],
[i % 2 === 0 ? -30 : 30, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.16, 1, 0.3, 1),
},
);
return (
<div
key={t.name}
style={{
opacity,
transform: `translateX(${x}px)`,
backgroundColor: COLORS.bgLight,
border: `1px solid ${COLORS.border}`,
borderLeft: `4px solid ${COLORS.purple}`,
borderRadius: 10,
padding: "14px 20px",
display: "flex",
flexDirection: "column",
gap: 6,
}}
>
<div
style={{
display: "flex",
alignItems: "baseline",
justifyContent: "space-between",
gap: 12,
}}
>
<div
style={{
fontSize: 20,
fontWeight: 800,
color: COLORS.purple,
fontFamily: FONTS.mono,
}}
>
{t.name}
</div>
<div
style={{
fontSize: 11,
color: COLORS.textMuted,
fontFamily: FONTS.mono,
}}
>
{t.file}
</div>
</div>
<div
style={{
fontSize: 12,
fontFamily: FONTS.mono,
display: "flex",
flexWrap: "wrap",
gap: 6,
}}
>
{t.impls.map((impl) => (
<span
key={impl}
style={{
backgroundColor: "#0b1120",
border: `1px solid ${COLORS.border}`,
borderRadius: 4,
padding: "2px 8px",
color: COLORS.cyan,
}}
>
{impl}
</span>
))}
</div>
</div>
);
})}
</div>
</AbsoluteFill>
);
};

View File

@@ -0,0 +1,21 @@
export const COLORS = {
bg: "#0f172a", // slate-900
bgLight: "#1e293b", // slate-800
primary: "#3b82f6", // blue-500
primaryLight: "#60a5fa", // blue-400
accent: "#f59e0b", // amber-500
accentLight: "#fbbf24", // amber-400
success: "#10b981", // emerald-500
danger: "#ef4444", // red-500
text: "#f8fafc", // slate-50
textMuted: "#94a3b8", // slate-400
border: "#334155", // slate-700
purple: "#8b5cf6", // violet-500
cyan: "#06b6d4", // cyan-500
pink: "#ec4899", // pink-500
};
export const FONTS = {
mono: "monospace",
sans: "system-ui, -apple-system, sans-serif",
};

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"jsx": "react-jsx",
"strict": true,
"noEmit": true,
"lib": ["dom", "dom.iterable", "esnext"],
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true
},
"exclude": ["remotion.config.ts"]
}

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
VIDEO_DIR="$PROJECT_ROOT/docs/architecture-video"
OUTPUT="${1:-$PROJECT_ROOT/ironclaw-architecture.mp4}"
case "$OUTPUT" in
/*) ;;
*) OUTPUT="$PROJECT_ROOT/$OUTPUT" ;;
esac
if ! command -v node &>/dev/null; then
echo "Error: node is required. Install Node.js >= 18." >&2
exit 1
fi
if ! command -v npx &>/dev/null; then
echo "Error: npx is required (comes with npm)." >&2
exit 1
fi
if ! command -v npm &>/dev/null; then
echo "Error: npm is required to install dependencies." >&2
exit 1
fi
if [ ! -d "$VIDEO_DIR/node_modules" ]; then
echo "Installing dependencies..."
if [ -f "$VIDEO_DIR/package-lock.json" ]; then
(cd "$VIDEO_DIR" && npm ci --no-fund --no-audit)
else
(cd "$VIDEO_DIR" && npm install --no-fund --no-audit)
fi
fi
echo "Rendering IronClaw architecture video..."
(cd "$VIDEO_DIR" && npx remotion render IronClawArchitecture -- "$OUTPUT")
echo ""
echo "Done: $OUTPUT"