mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-02 23:56:24 +08:00
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:
245
.claude/skills/architecture-video/SKILL.md
Normal file
245
.claude/skills/architecture-video/SKILL.md
Normal 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
7
docs/architecture-video/.gitignore
vendored
Normal 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
|
||||
5
docs/architecture-video/.prettierrc
Normal file
5
docs/architecture-video/.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"bracketSpacing": true,
|
||||
"tabWidth": 2
|
||||
}
|
||||
58
docs/architecture-video/README.md
Normal file
58
docs/architecture-video/README.md
Normal 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.
|
||||
3
docs/architecture-video/eslint.config.mjs
Normal file
3
docs/architecture-video/eslint.config.mjs
Normal 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
4610
docs/architecture-video/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
docs/architecture-video/package.json
Normal file
34
docs/architecture-video/package.json
Normal 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"
|
||||
]
|
||||
}
|
||||
4
docs/architecture-video/remotion.config.ts
Normal file
4
docs/architecture-video/remotion.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Config } from "@remotion/cli/config";
|
||||
|
||||
Config.setVideoImageFormat("jpeg");
|
||||
Config.setOverwriteOutput(true);
|
||||
69
docs/architecture-video/src/IronClawArchitecture.tsx
Normal file
69
docs/architecture-video/src/IronClawArchitecture.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
21
docs/architecture-video/src/Root.tsx
Normal file
21
docs/architecture-video/src/Root.tsx
Normal 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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
116
docs/architecture-video/src/components/Code.tsx
Normal file
116
docs/architecture-video/src/components/Code.tsx
Normal 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> </span>
|
||||
) : (
|
||||
tokens.map((t, ti) => (
|
||||
<span key={ti} style={{ color: t.color || COLORS.text }}>
|
||||
{t.text}
|
||||
</span>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
1
docs/architecture-video/src/index.css
Normal file
1
docs/architecture-video/src/index.css
Normal file
@@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
4
docs/architecture-video/src/index.ts
Normal file
4
docs/architecture-video/src/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { registerRoot } from "remotion";
|
||||
import { RemotionRoot } from "./Root";
|
||||
|
||||
registerRoot(RemotionRoot);
|
||||
187
docs/architecture-video/src/scenes/ChannelImplsScene.tsx
Normal file
187
docs/architecture-video/src/scenes/ChannelImplsScene.tsx
Normal 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 • 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>
|
||||
);
|
||||
};
|
||||
187
docs/architecture-video/src/scenes/ChannelsRoutingScene.tsx
Normal file
187
docs/architecture-video/src/scenes/ChannelsRoutingScene.tsx
Normal 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> — trait +
|
||||
stream merging
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 14,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 20,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
src/channels/channel.rs • 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 N→1
|
||||
</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>
|
||||
);
|
||||
};
|
||||
341
docs/architecture-video/src/scenes/CodeActScene.tsx
Normal file
341
docs/architecture-video/src/scenes/CodeActScene.tsx
Normal 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> — 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 •
|
||||
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>
|
||||
);
|
||||
};
|
||||
185
docs/architecture-video/src/scenes/ExecutionLoopScene.tsx
Normal file
185
docs/architecture-video/src/scenes/ExecutionLoopScene.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
199
docs/architecture-video/src/scenes/LlmDecoratorScene.tsx
Normal file
199
docs/architecture-video/src/scenes/LlmDecoratorScene.tsx
Normal 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> —
|
||||
decorator chain
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 14,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 30,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
src/llm/provider.rs • 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>
|
||||
);
|
||||
};
|
||||
195
docs/architecture-video/src/scenes/OutroScene.tsx
Normal file
195
docs/architecture-video/src/scenes/OutroScene.tsx
Normal 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 • All I/O is async • cargo fmt
|
||||
&& cargo clippy && cargo test
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
178
docs/architecture-video/src/scenes/PrimitivesScene.tsx
Normal file
178
docs/architecture-video/src/scenes/PrimitivesScene.tsx
Normal 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> — Five
|
||||
Primitives
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 16,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 36,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
crates/ironclaw_engine/ — 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>
|
||||
);
|
||||
};
|
||||
224
docs/architecture-video/src/scenes/SkillsPipelineScene.tsx
Normal file
224
docs/architecture-video/src/scenes/SkillsPipelineScene.tsx
Normal 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> —
|
||||
selection pipeline
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 14,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 30,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
src/skills/ • SKILL.md + YAML frontmatter • 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>
|
||||
);
|
||||
};
|
||||
202
docs/architecture-video/src/scenes/ThreadStateScene.tsx
Normal file
202
docs/architecture-video/src/scenes/ThreadStateScene.tsx
Normal 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> —
|
||||
state machine
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 14,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 24,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
crates/ironclaw_engine/src/types/thread.rs • 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>
|
||||
);
|
||||
};
|
||||
152
docs/architecture-video/src/scenes/TitleScene.tsx
Normal file
152
docs/architecture-video/src/scenes/TitleScene.tsx
Normal 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 — A Contributor's Guide
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
232
docs/architecture-video/src/scenes/ToolDispatchScene.tsx
Normal file
232
docs/architecture-video/src/scenes/ToolDispatchScene.tsx
Normal 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 • 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>
|
||||
);
|
||||
};
|
||||
194
docs/architecture-video/src/scenes/TraitsScene.tsx
Normal file
194
docs/architecture-video/src/scenes/TraitsScene.tsx
Normal 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> —
|
||||
traits + implementers
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
opacity: headingOpacity,
|
||||
fontSize: 14,
|
||||
color: COLORS.textMuted,
|
||||
marginBottom: 24,
|
||||
fontFamily: FONTS.mono,
|
||||
}}
|
||||
>
|
||||
impl YourTrait for YourType — 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>
|
||||
);
|
||||
};
|
||||
21
docs/architecture-video/src/theme.ts
Normal file
21
docs/architecture-video/src/theme.ts
Normal 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",
|
||||
};
|
||||
15
docs/architecture-video/tsconfig.json
Normal file
15
docs/architecture-video/tsconfig.json
Normal 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"]
|
||||
}
|
||||
41
scripts/render-architecture-video.sh
Executable file
41
scripts/render-architecture-video.sh
Executable 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"
|
||||
Reference in New Issue
Block a user