diff --git a/packages/video/.gitignore b/packages/video/.gitignore new file mode 100644 index 0000000..a9a5b50 --- /dev/null +++ b/packages/video/.gitignore @@ -0,0 +1,8 @@ +# Rendered video outputs +out/ +*.mp4 +*.webm +*.mov + +# Remotion cache +.remotion/ diff --git a/packages/video/package.json b/packages/video/package.json index 49e111e..d414dfe 100644 --- a/packages/video/package.json +++ b/packages/video/package.json @@ -5,7 +5,8 @@ "description": "Marketing videos for TPMJS", "scripts": { "dev": "remotion studio", - "render": "remotion render MarketingVideo out/marketing-video.mp4", + "render": "remotion render TPMJSExplainer out/explainer-video.mp4", + "render:features": "remotion render TPMJSFeatures out/features-video.mp4", "upgrade": "remotion upgrade" }, "dependencies": { diff --git a/packages/video/src/FeaturesVideo.tsx b/packages/video/src/FeaturesVideo.tsx new file mode 100644 index 0000000..5d9e938 --- /dev/null +++ b/packages/video/src/FeaturesVideo.tsx @@ -0,0 +1,55 @@ +import { AbsoluteFill, Sequence, useVideoConfig } from 'remotion'; +import { colors } from './design-tokens'; + +// Scene imports +import { FeaturesOpeningScene } from './scenes/features/FeaturesOpeningScene'; +import { ToolRegistryScene } from './scenes/features/ToolRegistryScene'; +import { OmegaAgentScene } from './scenes/features/OmegaAgentScene'; +import { CollectionsFeatureScene } from './scenes/features/CollectionsFeatureScene'; +import { CustomAgentsScene } from './scenes/features/CustomAgentsScene'; +import { MCPProtocolScene } from './scenes/features/MCPProtocolScene'; +import { SecureExecutionScene } from './scenes/features/SecureExecutionScene'; +import { TestScenariosScene } from './scenes/features/TestScenariosScene'; +import { LivingSkillsScene } from './scenes/features/LivingSkillsScene'; +import { DeveloperSDKScene } from './scenes/features/DeveloperSDKScene'; +import { FeaturesClosingScene } from './scenes/features/FeaturesClosingScene'; + +/** + * TPMJS Features Showcase Video + * Total: 2700 frames @ 30fps = 90 seconds + * + * A punchy showcase of all 9 platform features + */ +export const FeaturesVideo = () => { + const { fps } = useVideoConfig(); + + // Scene timing (in seconds) + const scenes = [ + { component: FeaturesOpeningScene, start: 0, duration: 6 }, + { component: ToolRegistryScene, start: 6, duration: 9 }, + { component: OmegaAgentScene, start: 15, duration: 9 }, + { component: CollectionsFeatureScene, start: 24, duration: 8 }, + { component: CustomAgentsScene, start: 32, duration: 8 }, + { component: MCPProtocolScene, start: 40, duration: 9 }, + { component: SecureExecutionScene, start: 49, duration: 8 }, + { component: TestScenariosScene, start: 57, duration: 8 }, + { component: LivingSkillsScene, start: 65, duration: 8 }, + { component: DeveloperSDKScene, start: 73, duration: 9 }, + { component: FeaturesClosingScene, start: 82, duration: 8 }, + ]; + + return ( + + {scenes.map(({ component: Component, start, duration }, index) => ( + + + + ))} + + ); +}; diff --git a/packages/video/src/Root.tsx b/packages/video/src/Root.tsx index 2f1b3df..a7b661d 100644 --- a/packages/video/src/Root.tsx +++ b/packages/video/src/Root.tsx @@ -1,15 +1,26 @@ import { Composition } from 'remotion'; import { ExplainerVideo } from './ExplainerVideo'; +import { FeaturesVideo } from './FeaturesVideo'; export const RemotionRoot = () => { return ( - + <> + + + ); }; diff --git a/packages/video/src/scenes/features/CollectionsFeatureScene.tsx b/packages/video/src/scenes/features/CollectionsFeatureScene.tsx new file mode 100644 index 0000000..33ab429 --- /dev/null +++ b/packages/video/src/scenes/features/CollectionsFeatureScene.tsx @@ -0,0 +1,271 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 3: Collections (0:24 - 0:32) + * Curate tool sets for specific use cases + */ + +const CollectionCard = ({ + name, + toolCount, + category, + delay, + isActive = false, +}: { + name: string; + toolCount: number; + category: string; + delay: number; + isActive?: boolean; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + return ( +
+
+
+ {name} +
+
+ {category} +
+
+
+
+ {Array.from({ length: Math.min(toolCount, 5) }).map((_, i) => ( +
+ ))} + {toolCount > 5 && ( + + +{toolCount - 5} + + )} +
+ + {toolCount} tools + +
+
+ ); +}; + +export const CollectionsFeatureScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const collections = [ + { name: 'data-science-kit', toolCount: 12, category: 'analytics' }, + { name: 'content-creation', toolCount: 8, category: 'marketing' }, + { name: 'devops-automation', toolCount: 15, category: 'infra' }, + ]; + + return ( + + {/* Feature badge */} +
+
+ 📁 +
+
+
+ Feature 03 +
+
+ Collections +
+
+
+ shareable +
+
+ + {/* Main content */} +
+ {/* Left - Description */} +
+
+ Curate tool sets +
+ for specific{' '} + use cases +
+
+ Add test scenarios to validate behavior. +
+ Generate living documentation automatically. +
+
+ + {/* Right - Collection cards */} +
+ {collections.map((collection, i) => ( + + ))} +
+
+
+ ); +}; diff --git a/packages/video/src/scenes/features/CustomAgentsScene.tsx b/packages/video/src/scenes/features/CustomAgentsScene.tsx new file mode 100644 index 0000000..0188e15 --- /dev/null +++ b/packages/video/src/scenes/features/CustomAgentsScene.tsx @@ -0,0 +1,268 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 4: Custom Agents (0:32 - 0:40) + * Build AI agents with your choice of LLM + */ + +const AgentCard = ({ + name, + model, + tools, + status, + delay, +}: { + name: string; + model: string; + tools: number; + status: 'public' | 'private'; + delay: number; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + return ( +
+
+
+ {name[0].toUpperCase()} +
+
+
+ {name} +
+
+ {model} +
+
+
+ +
+ + {tools} tools configured + +
+ {status} +
+
+
+ ); +}; + +export const CustomAgentsScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const agents = [ + { name: 'Research Bot', model: 'claude-opus-4', tools: 8, status: 'public' as const }, + { name: 'Code Review', model: 'gpt-4o', tools: 5, status: 'private' as const }, + { name: 'Data Analyst', model: 'claude-sonnet-4', tools: 12, status: 'public' as const }, + ]; + + return ( + + {/* Feature badge */} +
+
+ 👤 +
+
+
+ Feature 04 +
+
+ Custom Agents +
+
+
+ unlimited +
+
+ + {/* Tagline */} +
+
+ Your LLM. Your prompts. +
+ Your tools. +
+
+ + {/* Agent cards */} +
+ {agents.map((agent, i) => ( + + ))} +
+ + {/* Bottom text */} +
+ + Share publicly or keep private — your choice + +
+
+ ); +}; diff --git a/packages/video/src/scenes/features/DeveloperSDKScene.tsx b/packages/video/src/scenes/features/DeveloperSDKScene.tsx new file mode 100644 index 0000000..0aa2cbd --- /dev/null +++ b/packages/video/src/scenes/features/DeveloperSDKScene.tsx @@ -0,0 +1,321 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 9: Developer SDK (1:13 - 1:22) + * Publish tools with one keyword, TypeScript support + */ + +const CodeLine = ({ + content, + indent = 0, + delay, + highlight = false, +}: { + content: string; + indent?: number; + delay: number; + highlight?: boolean; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + return ( +
+ {content} +
+ ); +}; + +export const DeveloperSDKScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const codeLines = [ + { content: '// package.json', indent: 0, highlight: false }, + { content: '{', indent: 0, highlight: false }, + { content: '"name": "my-awesome-tool",', indent: 1, highlight: false }, + { content: '"keywords": ["tpmjs"],', indent: 1, highlight: true }, + { content: '"tpmjs": {', indent: 1, highlight: true }, + { content: '"tools": ["./src/tools.ts"]', indent: 2, highlight: true }, + { content: '}', indent: 1, highlight: false }, + { content: '}', indent: 0, highlight: false }, + ]; + + const features = [ + 'TypeScript support', + 'Vercel AI SDK integration', + 'Auto schema extraction', + 'Zero config publish', + ]; + + return ( + + {/* Feature badge */} +
+
+ {''} +
+
+
+ Feature 09 +
+
+ Developer SDK +
+
+
+ npm +
+
+ + {/* Main content */} +
+ {/* Left - Code block */} +
+
+
+
+
+
+
+ {codeLines.map((line, i) => ( + + ))} +
+ + {/* npm publish command */} +
+ $ + + npm publish + + + → auto-discovered in minutes + +
+
+ + {/* Right - Features */} +
+
+ One keyword. +
+ Instant discovery. +
+ +
+ {features.map((feature, i) => { + const featureProgress = spring({ + frame: frame - fps * 2 - i * 8, + fps, + config: springConfigs.snappy, + }); + + return ( +
+
+ ✓ +
+ + {feature} + +
+ ); + })} +
+
+
+ + ); +}; diff --git a/packages/video/src/scenes/features/FeaturesClosingScene.tsx b/packages/video/src/scenes/features/FeaturesClosingScene.tsx new file mode 100644 index 0000000..010c2b9 --- /dev/null +++ b/packages/video/src/scenes/features/FeaturesClosingScene.tsx @@ -0,0 +1,208 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, + Easing, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Features Closing Scene (1:22 - 1:30) + * Call to action with tpmjs.com + */ +export const FeaturesClosingScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + // All features revealed + const gridProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + // URL animation + const urlProgress = spring({ + frame: frame - fps * 1.5, + fps, + config: springConfigs.bouncy, + }); + + // CTA animation + const ctaProgress = spring({ + frame: frame - fps * 3, + fps, + config: springConfigs.snappy, + }); + + const features = [ + 'Tool Registry', + 'Omega Agent', + 'Collections', + 'Custom Agents', + 'MCP Protocol', + 'Secure Execution', + 'Test Scenarios', + 'Living Skills', + 'Developer SDK', + ]; + + // Pulsing glow + const glowIntensity = Math.sin(frame * 0.08) * 0.3 + 0.7; + + return ( + + {/* Radial gradient background */} +
+ + {/* Features grid (small) */} +
+ {features.map((feature, i) => ( +
+ {feature} +
+ ))} +
+ + {/* Main CTA */} +
+
+ Start building with AI tools +
+ + {/* URL box */} +
+
+ tpmjs.com +
+
+ + {/* Action buttons */} +
+
+ Try Omega Agent +
+
+ Read the Docs +
+
+
+ + {/* Bottom tagline */} +
+ + The Package Manager for AI Tools + +
+ + ); +}; diff --git a/packages/video/src/scenes/features/FeaturesOpeningScene.tsx b/packages/video/src/scenes/features/FeaturesOpeningScene.tsx new file mode 100644 index 0000000..233fcf1 --- /dev/null +++ b/packages/video/src/scenes/features/FeaturesOpeningScene.tsx @@ -0,0 +1,160 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, + Easing, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Features Opening Scene (0:00 - 0:06) + * Bold intro with TPMJS branding and tagline + */ +export const FeaturesOpeningScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + // Logo animation + const logoScale = spring({ + frame, + fps, + config: springConfigs.bouncy, + }); + + const logoRotate = interpolate(frame, [0, fps * 0.5], [-10, 0], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + easing: Easing.out(Easing.back(2)), + }); + + // Tagline animation + const taglineProgress = spring({ + frame: frame - fps * 1, + fps, + config: springConfigs.smooth, + }); + + // Feature count animation + const countProgress = spring({ + frame: frame - fps * 2, + fps, + config: springConfigs.snappy, + }); + + const featureCount = Math.floor( + interpolate(frame, [fps * 2, fps * 3.5], [0, 9], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + }) + ); + + // Copper line sweep + const lineWidth = interpolate(frame, [fps * 3, fps * 5], [0, 100], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + easing: Easing.out(Easing.cubic), + }); + + return ( + + {/* Gradient overlay */} +
+ + {/* Main content */} +
+ {/* Logo/Brand */} +
+ tpmjs +
+ + {/* Tagline */} +
+ The Package Manager for AI Tools +
+ + {/* Feature count */} +
+ + {featureCount} + + + Core Features + +
+
+ + {/* Bottom copper line */} +
+ + ); +}; diff --git a/packages/video/src/scenes/features/LivingSkillsScene.tsx b/packages/video/src/scenes/features/LivingSkillsScene.tsx new file mode 100644 index 0000000..bb82d3c --- /dev/null +++ b/packages/video/src/scenes/features/LivingSkillsScene.tsx @@ -0,0 +1,311 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 8: Living Skills (1:05 - 1:13) + * Documentation that evolves from real usage + */ + +const SkillNode = ({ + label, + x, + y, + delay, + size = 'md', +}: { + label: string; + x: number; + y: number; + delay: number; + size?: 'sm' | 'md' | 'lg'; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.bouncy, + }); + + const sizes = { + sm: { w: 100, h: 40, font: typography.fontSize.xs }, + md: { w: 140, h: 50, font: typography.fontSize.sm }, + lg: { w: 180, h: 60, font: typography.fontSize.base }, + }; + + const s = sizes[size]; + + return ( +
+ + {label} + +
+ ); +}; + +export const LivingSkillsScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + // Skill nodes with positions + const skills = [ + { label: 'API Design', x: 800, y: 300, size: 'lg' as const, delay: fps * 1 }, + { label: 'Error Handling', x: 600, y: 200, size: 'md' as const, delay: fps * 1.5 }, + { label: 'Rate Limits', x: 1000, y: 200, size: 'md' as const, delay: fps * 1.8 }, + { label: 'Caching', x: 550, y: 400, size: 'sm' as const, delay: fps * 2.2 }, + { label: 'Auth', x: 700, y: 450, size: 'sm' as const, delay: fps * 2.5 }, + { label: 'Webhooks', x: 950, y: 420, size: 'sm' as const, delay: fps * 2.8 }, + { label: 'Pagination', x: 1100, y: 350, size: 'sm' as const, delay: fps * 3 }, + ]; + + // Connection lines progress + const linesProgress = interpolate(frame, [fps * 3, fps * 5], [0, 1], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + }); + + return ( + + {/* Feature badge */} +
+
+ 💬 +
+
+
+ Feature 08 +
+
+ Living Skills +
+
+
+ NEW +
+
+ + {/* Left description */} +
+
+ Documentation that{' '} + evolves +
+
+ Skills emerge from question patterns +
+ and proven behaviors in real usage. +
+
+ + {/* Skill graph */} + + {/* Connection lines */} + + + + + + + + + + + {/* Skill nodes */} + {skills.map((skill) => ( + + ))} + + {/* Bottom quote */} +
+ + "Skills, proven in the wild — not declared on paper" + +
+
+ ); +}; diff --git a/packages/video/src/scenes/features/MCPProtocolScene.tsx b/packages/video/src/scenes/features/MCPProtocolScene.tsx new file mode 100644 index 0000000..53b2b05 --- /dev/null +++ b/packages/video/src/scenes/features/MCPProtocolScene.tsx @@ -0,0 +1,298 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 5: MCP Protocol (0:40 - 0:49) + * Works with Claude Desktop, Cursor, Windsurf, and any MCP client + */ + +const ClientLogo = ({ + name, + delay, + connected, +}: { + name: string; + delay: number; + connected: boolean; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.bouncy, + }); + + const connectionProgress = spring({ + frame: frame - delay - fps * 0.5, + fps, + config: springConfigs.snappy, + }); + + return ( +
+
+ {name[0]} +
+
+ {name} +
+ {connected && ( +
+ connected +
+ )} +
+ ); +}; + +export const MCPProtocolScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const urlProgress = spring({ + frame: frame - fps * 2, + fps, + config: springConfigs.snappy, + }); + + const clients = [ + { name: 'Claude', connected: true }, + { name: 'Cursor', connected: true }, + { name: 'Windsurf', connected: true }, + { name: 'Any MCP', connected: false }, + ]; + + // Connection line animation + const lineProgress = interpolate(frame, [fps * 3, fps * 5], [0, 1], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + }); + + return ( + + {/* Feature badge */} +
+
+ 🔗 +
+
+
+ Feature 05 +
+
+ MCP Protocol +
+
+
+ universal +
+
+ + {/* Center URL box */} +
+
+
+ MCP Server URL +
+
+ tpmjs.com/mcp +
+
+ +
+ One URL. Instant access to all tools. +
+
+ + {/* Client logos */} +
+ {clients.map((client, i) => ( + + ))} +
+ + {/* Connection lines */} + + {clients.slice(0, 3).map((_, i) => { + const startX = 480 + i * 320; + const startY = 820; + const endX = 960; + const endY = 520; + + const path = `M ${startX} ${startY} Q ${startX} ${(startY + endY) / 2} ${endX} ${endY}`; + const pathLength = 400; // Approximate + + return ( + + ); + })} + +
+ ); +}; diff --git a/packages/video/src/scenes/features/OmegaAgentScene.tsx b/packages/video/src/scenes/features/OmegaAgentScene.tsx new file mode 100644 index 0000000..95edafc --- /dev/null +++ b/packages/video/src/scenes/features/OmegaAgentScene.tsx @@ -0,0 +1,265 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 2: Omega Agent (0:15 - 0:24) + * AI that dynamically discovers and executes tools + */ + +const Message = ({ + role, + content, + delay, +}: { + role: 'user' | 'assistant'; + content: string; + delay: number; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + const isUser = role === 'user'; + + return ( +
+
+ {content} +
+
+ ); +}; + +const ToolPill = ({ name, delay }: { name: string; delay: number }) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.bouncy, + }); + + return ( +
+
+ + {name} + +
+ ); +}; + +export const OmegaAgentScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const selectedTools = ['web-scraper', 'sentiment', 'chart-gen']; + + return ( + + {/* Feature badge */} +
+
+ 🧩 +
+
+
+ Feature 02 +
+
+ Omega Agent +
+
+
+ LIVE +
+
+ + {/* Chat interface */} +
+ + + {/* Tool selection */} + {frame > fps * 1.5 && ( +
+
+ Auto-selected tools: +
+
+ {selectedTools.map((tool, i) => ( + + ))} +
+
+ )} + + +
+ + {/* Bottom highlight */} +
+ + No configuration needed.{' '} + Just ask. + +
+
+ ); +}; diff --git a/packages/video/src/scenes/features/SecureExecutionScene.tsx b/packages/video/src/scenes/features/SecureExecutionScene.tsx new file mode 100644 index 0000000..dabadfe --- /dev/null +++ b/packages/video/src/scenes/features/SecureExecutionScene.tsx @@ -0,0 +1,261 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 6: Secure Execution (0:49 - 0:57) + * Isolated sandboxes, rate limiting, encrypted credentials + */ + +const SecurityLayer = ({ + label, + icon, + delay, + index, +}: { + label: string; + icon: string; + delay: number; + index: number; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + const width = 300 - index * 40; + + return ( +
+ {icon} + + {label} + +
+ ); +}; + +export const SecureExecutionScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const shieldPulse = Math.sin(frame * 0.1) * 0.1 + 1; + + const layers = [ + { label: 'isolated sandbox', icon: '📦' }, + { label: 'rate limiting', icon: '⏱️' }, + { label: 'timeout handling', icon: '⚡' }, + { label: 'encrypted at rest', icon: '🔐' }, + ]; + + return ( + + {/* Feature badge */} +
+
+ 🔑 +
+
+
+ Feature 06 +
+
+ Secure Execution +
+
+
+ sandboxed +
+
+ + {/* Main content */} +
+ {/* Left - Shield visualization */} +
+
+ {/* Shield shape using CSS */} +
+
+ 🛡️ +
+
+
+
+ + {/* Right - Security layers */} +
+ {layers.map((layer, i) => ( + + ))} +
+
+ + {/* Bottom text */} +
+ + Every tool runs in{' '} + complete isolation + +
+
+ ); +}; diff --git a/packages/video/src/scenes/features/TestScenariosScene.tsx b/packages/video/src/scenes/features/TestScenariosScene.tsx new file mode 100644 index 0000000..73cf518 --- /dev/null +++ b/packages/video/src/scenes/features/TestScenariosScene.tsx @@ -0,0 +1,284 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 7: Test Scenarios (0:57 - 1:05) + * AI-generated test scenarios, pass rates, execution times + */ + +const TestResult = ({ + name, + status, + time, + delay, +}: { + name: string; + status: 'pass' | 'fail' | 'running'; + time?: string; + delay: number; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + const statusColors = { + pass: colors.status.success, + fail: colors.status.error, + running: colors.status.warning, + }; + + const statusIcons = { + pass: '✓', + fail: '✕', + running: '○', + }; + + return ( +
+ + {statusIcons[status]} + + + {name} + + {time && ( + + {time} + + )} +
+ ); +}; + +export const TestScenariosScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + // Animated progress bar + const passRate = Math.min( + 94, + interpolate(frame, [fps * 2, fps * 4], [0, 94], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + }) + ); + + const tests = [ + { name: 'search_basic_query', status: 'pass' as const, time: '124ms' }, + { name: 'search_with_filters', status: 'pass' as const, time: '89ms' }, + { name: 'handle_empty_results', status: 'pass' as const, time: '45ms' }, + { name: 'validate_api_key', status: 'fail' as const, time: '2.1s' }, + { name: 'rate_limit_handling', status: 'pass' as const, time: '312ms' }, + ]; + + return ( + + {/* Feature badge */} +
+
+ ✓ +
+
+
+ Feature 07 +
+
+ Test Scenarios +
+
+
+ automated +
+
+ + {/* Main content */} +
+ {/* Left - Pass rate */} +
+
+ Pass Rate +
+
+ {Math.floor(passRate)}% +
+ + {/* Progress bar */} +
+
+
+ +
+ AI-generated tests validate +
+ tool behavior automatically +
+
+ + {/* Right - Test results */} +
+
+ Recent Tests +
+ {tests.map((test, i) => ( + + ))} +
+
+ + ); +}; diff --git a/packages/video/src/scenes/features/ToolRegistryScene.tsx b/packages/video/src/scenes/features/ToolRegistryScene.tsx new file mode 100644 index 0000000..b86e769 --- /dev/null +++ b/packages/video/src/scenes/features/ToolRegistryScene.tsx @@ -0,0 +1,286 @@ +import { + AbsoluteFill, + interpolate, + spring, + useCurrentFrame, + useVideoConfig, +} from 'remotion'; +import { colors, typography, springConfigs } from '../../design-tokens'; + +/** + * Feature 1: Tool Registry (0:06 - 0:15) + * Browse 1M+ AI tools from npm + */ + +const ToolCard = ({ + name, + downloads, + score, + delay, +}: { + name: string; + downloads: string; + score: number; + delay: number; +}) => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const progress = spring({ + frame: frame - delay, + fps, + config: springConfigs.snappy, + }); + + return ( +
+
+
+ {name} +
+
+ {downloads} downloads/mo +
+
+
+
+
+
+ + {score}% + +
+
+ ); +}; + +export const ToolRegistryScene = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const headerProgress = spring({ + frame, + fps, + config: springConfigs.smooth, + }); + + const counterValue = Math.floor( + interpolate(frame, [fps * 0.5, fps * 3], [0, 1847293], { + extrapolateLeft: 'clamp', + extrapolateRight: 'clamp', + }) + ); + + const tools = [ + { name: '@anthropic/claude-sdk', downloads: '2.1M', score: 98 }, + { name: 'firecrawl-aisdk', downloads: '847K', score: 95 }, + { name: 'openai-tool-kit', downloads: '1.2M', score: 92 }, + { name: 'langchain-tools', downloads: '654K', score: 89 }, + ]; + + return ( + + {/* Feature badge */} +
+
+ 🔍 +
+
+
+ Feature 01 +
+
+ Tool Registry +
+
+
+ + {/* Main content */} +
+ {/* Left - Stats */} +
+
+ {counterValue.toLocaleString()}+ +
+
+ AI tools auto-discovered from npm +
+ + {/* Badges */} +
+ {['auto-sync', 'quality scores', 'health monitoring'].map((badge) => ( +
+ {badge} +
+ ))} +
+
+ + {/* Right - Tool list */} +
+ {tools.map((tool, i) => ( + + ))} +
+
+ + {/* Bottom tagline */} +
+ + Updated within minutes of npm publication + +
+
+ ); +};