Animated scenes are authored as frame-driven Remotion compositions and exposed through the frame-by-frame inspector and exporters at /videos/<id>. No video files are shipped to the site.
Why frame-driven, not CSS keyframes: only useCurrentFrame()-based animation is frame-addressable (inspect any frame) and deterministically renderable (export). Seamless loops are guaranteed by mapping exactly one motion cycle onto durationInFrames (last frame wraps to frame 0 with no jump). The old CSS-keyframe visualizations could do neither.
Layout (single source of truth per scene):
remotion/scenes/<Scene>.data.ts— plain data (props type, defaults, asset paths relative to public/, no leading slash). NO remotion/React import → safe in server components.remotion/scenes/<Scene>.tsx— the composition (importsremotion; wrap asset paths instaticFile()so they resolve in both the browser Player and the render server).remotion/scenes.meta.ts— pure metadata array (id/title/dims/fps/durationInFrames/embedMaxWidth/defaultProps). Server-safe.remotion/registry.tsx— id → component (client/bundle only).remotion/Root.tsx+remotion/index.ts— registers Compositions for Studio/CLI/export.- Text scenes (fonts): load fonts inside the composition via
@remotion/google-fonts/<Font>loadFont()(Inter + GeistMono) and inline theme colors as hex constants in the.data.ts. The site'snext/font+ CSS vars do NOT exist in the render bundle, so never rely on them. app/videos/[id]+components/VideoInspector.tsx— Player + scrubber + arrow-key frame stepping + MP4 and 5:2 final-frame banner exports.app/api/render/route.ts—@remotion/bundler+@remotion/renderer, publicDir=Nextpublic/, yuv420p h264 for video and PNG for banners. Marked inserverExternalPackagesin next.config.
Gotchas learned: (1) a server-safe meta module must NOT transitively import any file that imports remotion (createContext SSR guard) — that's why data is split from the composition. (2) Use staticFile() for assets; bare /avatars/x.png 404s in the render server. (3) Remotion license reminder silenced via acknowledgeRemotionLicense — verify the free-license terms still apply if this ever becomes a company/commercial use.
Scripts: npm run studio (richest timeline for craft), npm run render. Verified: avatar-orbit exports 1080x1080 / 30fps / 720f / 24s, seamless (frame 0 ≈ frame 719). Related: nextjs-is-modified if it exists.