import { AbsoluteFill, Audio, interpolate, Sequence, staticFile, useCurrentFrame, Video } from "remotion";
import { type ClaudeEvent, ClaudeTerminal } from "./ClaudeTerminal";
import { Terminal, type TerminalEvent } from "./Terminal";
import { WebPage } from "./WebPage";
export const PROMO_FPS = 30;
export const PROMO_WIDTH = 1920;
export const PROMO_HEIGHT = 1080;
// ─── Scene durations (frames at 30fps) ───
const SCENE_WEB_EMPTY = 75; // 2.5s — Machines page → cursor → click
const SCENE_CHOOSE = 105; // 3.5s — Choose type → click Your Computer
const SCENE_SPLIT = 180; // 6s — Split: web waiting + terminal ak start
const SCENE_CLAUDE = 810; // 27s — ak claude → Claude Code UI
const TRANS = 0; // 直接切 DemoBoard
const SCENE_DEMO = 2379; // 79.3s — DemoBoard recording (matches demo.mov)
export const PROMO_DURATION = SCENE_WEB_EMPTY + SCENE_CHOOSE + SCENE_SPLIT + SCENE_CLAUDE + TRANS + SCENE_DEMO;
// ─── Colors ───
const C = {
bg: "#09090B",
surface: "#18181B",
border: "#27272A",
text: "#FAFAFA",
dim: "#71717A",
accent: "#22D3EE",
success: "#22C55E",
} as const;
// ─── Scene: ak start (split screen terminal) ───
const akStartEvents: TerminalEvent[] = [
{ type: "type", text: "npx vtit-agent-coding start --api-url https://vtit-agent-coding.viettelsoftware.com --api-key ak_live_xxxxxxxx", at: 5, duration: 40 },
{ type: "print", text: "Daemon started (PID 48291)", at: 55 },
{ type: "blank", at: 60 },
{ type: "print", text: "[info] Machine registered: m_macbook_pro", at: 70 },
{ type: "print", text: "[info] Machine online: macbook-pro (darwin arm64), runtimes: Claude Code", at: 85 },
{ type: "print", text: "[info] Daemon ready, polling for tasks...", at: 100 },
];
// ─── Scene: ak claude (regular terminal) ───
const akClaudeEvents: TerminalEvent[] = [
{ type: "type", text: "ak claude", at: 5, duration: 15 },
{ type: "print", text: "Creating leader identity for claude...", at: 30 },
{ type: "print", text: " Agent ID: a_claude_7f8a", at: 42 },
{ type: "print", text: " Fingerprint: 7f8a9b0c1d2e3f4g", at: 50 },
];
// ─── Scene: Claude Code UI (starts after ak claude transition at frame 120) ───
const P1 = 120; // /ak-plan (after crossfade completes)
const P2 = 480; // confirm + create
const claudeUIEvents: ClaudeEvent[] = [
// ── /ak-plan ──
{ type: "user", text: "/ak-plan v1.0 Build an API server with auth, CRUD, and webhook support", at: P1 + 15, duration: 40 },
{ type: "blank", at: P1 + 70 },
{ type: "thinking", text: "Analyzing project scope...", at: P1 + 80 },
{ type: "blank", at: P1 + 95 },
{ type: "tool", command: "ak get board", output: "No boards found.", at: P1 + 100 },
{ type: "tool", command: "ak get repo", output: "No repositories found.", at: P1 + 125 },
{ type: "tool", command: "ak get agent", output: "a_claude_7f8a [idle] claude — 0 tasks", at: P1 + 150 },
{ type: "blank", at: P1 + 175 },
{ type: "text", text: "Here's my proposed plan for api-server v1.0:", at: P1 + 185 },
{ type: "blank", at: P1 + 195 },
{ type: "text", text: " Board: api-server", at: P1 + 200 },
{ type: "text", text: " Repo: github.com/acme/api-server", at: P1 + 210 },
{ type: "text", text: " Tasks: 7 tasks across 3 phases", at: P1 + 220 },
{ type: "blank", at: P1 + 230 },
{ type: "text", text: " Phase 1 — Foundation (parallel):", at: P1 + 235 },
{ type: "text", text: " 1. Project scaffold + DB schema [high]", at: P1 + 245 },
{ type: "text", text: " 2. Auth middleware (JWT + sessions) [high]", at: P1 + 255 },
{ type: "blank", at: P1 + 265 },
{ type: "text", text: " Phase 2 — Core (depends on Phase 1):", at: P1 + 270 },
{ type: "text", text: " 3. CRUD endpoints for resources [high]", at: P1 + 280 },
{ type: "text", text: " 4. Input validation + error handling [medium]", at: P1 + 290 },
{ type: "text", text: " 5. Webhook dispatch + retry [medium]", at: P1 + 300 },
{ type: "blank", at: P1 + 310 },
{ type: "text", text: " Phase 3 — Polish:", at: P1 + 315 },
{ type: "text", text: " 6. Rate limiting + API keys [medium]", at: P1 + 325 },
{ type: "text", text: " 7. OpenAPI docs + health check [low]", at: P1 + 335 },
{ type: "blank", at: P1 + 345 },
{ type: "text", text: "Shall I proceed with this plan?", at: P1 + 350 },
// ── Confirm + create ──
{ type: "blank", at: P2 },
{ type: "user", text: "Looks good, go ahead", at: P2 + 10, duration: 25 },
{ type: "blank", at: P2 + 45 },
{ type: "thinking", text: "Creating board and tasks...", at: P2 + 55 },
{ type: "blank", at: P2 + 65 },
{ type: "tool", command: 'ak create board --name "api-server"', output: "Created board b_api01: api-server", at: P2 + 70 },
{
type: "tool",
command: "ak create repo --name api-server --url https://github.com/acme/api-server",
output: "Created repo r_api01: api-server",
at: P2 + 95,
},
{
type: "tool",
command: "ak apply -f agents/atlas.yaml",
output: "Created agent a_atlas01: Atlas (developer)",
at: P2 + 120,
},
{
type: "tool",
command: "ak apply -f agents/nova.yaml",
output: "Created agent a_nova02: Nova (developer)",
at: P2 + 140,
},
{ type: "blank", at: P2 + 160 },
{ type: "thinking", text: "Creating 7 tasks...", at: P2 + 165 },
{ type: "text", text: " ✓ T1: Project scaffold + DB schema → Atlas", at: P2 + 180 },
{ type: "text", text: " ✓ T2: Auth middleware (JWT + sessions) → Nova", at: P2 + 190 },
{ type: "text", text: " ✓ T3: CRUD endpoints for resources → Atlas", at: P2 + 200 },
{ type: "text", text: " ✓ T4: Input validation + error handling → Nova", at: P2 + 210 },
{ type: "text", text: " ✓ T5: Webhook dispatch + retry → Atlas", at: P2 + 220 },
{ type: "text", text: " ✓ T6: Rate limiting + API keys → Nova", at: P2 + 230 },
{ type: "text", text: " ✓ T7: OpenAPI docs + health check → Atlas", at: P2 + 240 },
{ type: "blank", at: P2 + 255 },
{ type: "text", text: "All set! 7 tasks created, 2 agents assigned. The daemon will start picking up tasks.", at: P2 + 265, color: C.success },
];
// ─── Layout components ───
function SplitScreen({ left, right, splitRatio = 0.5 }: { left: React.ReactNode; right: React.ReactNode; splitRatio?: number }) {
return (