diff --git a/docs/superpowers/specs/2026-05-08-remotion-promo-videos-design.md b/docs/superpowers/specs/2026-05-08-remotion-promo-videos-design.md new file mode 100644 index 00000000..c0001bf4 --- /dev/null +++ b/docs/superpowers/specs/2026-05-08-remotion-promo-videos-design.md @@ -0,0 +1,736 @@ +# Remotion Promotional Videos -- Design Spec + +## Overview + +Three standalone promotional videos for SnapOtter built with Remotion. Each video serves a different purpose and platform, with a shared design system for brand consistency. + +| # | Video | Purpose | Theme | Resolution | Duration | +|---|-------|---------|-------|------------|----------| +| 1 | X Launch Video | Twitter/X announcement | Dark | 1080x1080 | ~35s | +| 2 | Product Demo | Website/sales walkthrough | Light | 1920x1080 | ~75s | +| 3 | Promo Teaser | Social media awareness | Dark | 1080x1080 + 1080x1920 | ~20s | + +All videos use music + text captions (no voiceover). Music is placeholder-ready (Remotion audio infrastructure wired up, user swaps in a real track later). + +--- + +## Technical Architecture + +### Workspace Setup + +New monorepo workspace: `apps/videos/` + +``` +apps/videos/ + package.json (@snapotter/videos) + tsconfig.json + remotion.config.ts + tailwind.config.js (v3 format for Remotion Webpack compat) + src/ + index.ts (entry point) + Root.tsx (Composition registry -- all 3 + aspect ratio variants) + design-system/ + colors.ts (dark + light palettes from SnapOtter brand) + fonts.ts (Inter, Nunito, JetBrains Mono registration) + animations.ts (spring presets, easing curves, timing constants) + components/ + AppWindow.tsx (macOS-style window chrome with traffic lights) + Terminal.tsx (terminal with typing animation + syntax highlighting) + AnimatedText.tsx (word-by-word / character reveal with clip-mask) + ToolGrid.tsx (animated grid of tool cards by category) + BeforeAfter.tsx (split comparison with scan-line wipe) + LogoReveal.tsx (SnapOtter logo with particle convergence) + GitHubCTA.tsx (star on GitHub end card) + RotatingTaglines.tsx (cycling phrases from landing page) + FeaturePill.tsx (animated feature badge) + NumberPunch.tsx (large number with impact animation) + GrainOverlay.tsx (animated Perlin noise film grain) + ProgressBar.tsx (animated processing progress) + GradientMesh.tsx (ambient amber/orange blob background) + compositions/ + x-launch/ + XLaunchVideo.tsx + scenes/ + HookScene.tsx + TerminalInstallScene.tsx + ToolGridRevealScene.tsx + AiShowcaseScene.tsx + PrivacyBeatScene.tsx + FeatureBurstScene.tsx + GitHubCTAScene.tsx + product-demo/ + ProductDemo.tsx + scenes/ + DashboardScene.tsx + SingleToolScene.tsx + BatchProcessingScene.tsx + PipelineBuilderScene.tsx + AiToolsScene.tsx + ImageEditorScene.tsx + ApiDocsScene.tsx + EndCardScene.tsx + promo-teaser/ + PromoTeaser.tsx + PromoTeaserVertical.tsx (1080x1920 variant) + scenes/ + AmbientOpenScene.tsx + NumberPunchScene.tsx + TaglineCascadeScene.tsx + LogoRevealScene.tsx + CTAScene.tsx + lib/ + tools.ts (all 49 tool names + categories, mirrored from shared) + audio.ts (audio placeholder config with fade-in/fade-out) + public/ + otter-logo.svg + audio/ + placeholder.mp3 (silent placeholder, same duration as longest video) + scripts/ + render-all.mjs (batch render all compositions to MP4) +``` + +### Dependencies + +```json +{ + "dependencies": { + "remotion": "^4.0.0", + "@remotion/cli": "^4.0.0", + "@remotion/renderer": "^4.0.0", + "@remotion/bundler": "^4.0.0", + "@remotion/tailwind": "^4.0.0", + "@remotion/noise": "^4.0.0", + "@remotion/motion-blur": "^4.0.0", + "@remotion/paths": "^4.0.0", + "@remotion/google-fonts": "^4.0.0", + "@remotion/shapes": "^4.0.0", + "react": "^18.3.0", + "react-dom": "^18.3.0" + } +} +``` + +Note: Remotion v4 requires React 18, not React 19. This workspace pins React 18 independently (pnpm handles this with workspace overrides). `@remotion/tailwind` uses Webpack and requires Tailwind CSS v3 config format. + +### Config + +**`remotion.config.ts`:** +```ts +import { Config } from "@remotion/cli/config"; +import { enableTailwind } from "@remotion/tailwind"; + +Config.setVideoImageFormat("jpeg"); +Config.setOverwriteOutput(true); +Config.overrideWebpackConfig((config) => enableTailwind(config)); +``` + +**`tailwind.config.js`** (v3 format): +```js +module.exports = { + content: ["./src/**/*.{ts,tsx}"], + theme: { + extend: { + fontFamily: { + heading: ["Nunito", "sans-serif"], + body: ["Inter", "sans-serif"], + mono: ["JetBrains Mono", "monospace"], + }, + colors: { + accent: "#f59e0b", + safe: "#22c55e", + danger: "#ef4444", + }, + }, + }, +}; +``` + +### Root Composition Registry + +```tsx +// Root.tsx +import { Composition } from "remotion"; +import { XLaunchVideo } from "./compositions/x-launch/XLaunchVideo"; +import { ProductDemo } from "./compositions/product-demo/ProductDemo"; +import { PromoTeaser } from "./compositions/promo-teaser/PromoTeaser"; +import { PromoTeaserVertical } from "./compositions/promo-teaser/PromoTeaserVertical"; + +export const RemotionRoot = () => ( + <> + + + + + +); +``` + +### Audio Setup + +All videos use a placeholder audio track. The infrastructure is wired so the user drops in a real track later. + +```ts +// lib/audio.ts +import { Audio, interpolate, useCurrentFrame } from "remotion"; +import { staticFile } from "remotion"; + +export const BackgroundMusic: React.FC<{ + src?: string; + volume?: number; + fadeInFrames?: number; + fadeOutFrames?: number; + totalFrames: number; +}> = ({ + src = staticFile("audio/placeholder.mp3"), + volume = 0.4, + fadeInFrames = 30, + fadeOutFrames = 60, + totalFrames, +}) => { + const frame = useCurrentFrame(); + const vol = interpolate( + frame, + [0, fadeInFrames, totalFrames - fadeOutFrames, totalFrames], + [0, volume, volume, 0], + { extrapolateLeft: "clamp", extrapolateRight: "clamp" } + ); + return