Communitygithub.com

chandreshpv/remotion-product-videos-claude-skill

Use this skill when creating Remotion promo videos. Covers canvas sizing, scene structure, mockup 3D entry, cursor animations, micro-animations, transitions, audio, and production best practices.

What is remotion-product-videos-claude-skill?

remotion-product-videos-claude-skill is a Claude Code agent skill that use this skill when creating Remotion promo videos. Covers canvas sizing, scene structure, mockup 3D entry, cursor animations, micro-animations, transitions, audio, and production best practices.

Works with✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/chandreshpv/remotion-product-videos-claude-skill/tree/main

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Remotion Visual Production Skill

Built from real production experience creating the SureCart 4.2 launch video. Author: Chandresh Vaghanani


Before You Start — 2 Questions (Non-Negotiable)

Ask these 2 questions before writing any code. Keep it casual — one message, two questions. Do not skip them even if the user says "just go" or "start now." These 10 seconds prevent hours of rework.

Before I start — two quick things:
1. Light or dark background? (or share your website/screenshot and I'll pull it from there)
2. Do you have a product screenshot or mockup? (totally optional — I can build without one)

That's it. No more questions unless the user volunteers more.

What to do with the answers:

  • If they share a mockup/screenshot — extract background color, accent color, font style, UI copy. Use it.
  • If they share a website URL — fetch it, extract the same. Do not guess.
  • If they answer light/dark only — proceed with the No-Info Fallback Defaults below.
  • If they skip both questions — proceed with the No-Info Fallback Defaults below. Do not ask again.

Other assets (logo, music, extra colors) — accept if offered, but never block on them.


No-Info Fallback Defaults

When brand info is unavailable, the AI's instinct is to shrink fonts and add padding. That instinct is wrong for video. Apply these instead:

These kick in automatically when no mockup, screenshot, or website is provided. They ensure a professional result even with zero brand info.

Layout

  • justifyContent: "center" + alignItems: "center" on every scene's AbsoluteFill — no exceptions
  • marginTop: -50 to pull content slightly above true center
  • Mockup/card width: 1200px (use the upper end — fill the frame)
  • Container padding: max 40px — never more
  • Content must occupy at least 75% of the 1080px height. If it doesn't, increase font sizes or reduce gaps.

Font sizes (fallback — upper end of range)

ElementFallback size
Main headline140px
Sub-headline56px
Body / description36px
Label / pill22px
Card content text28px

Colors (fallback palette — safe and professional)

  • Background: #0a0a0f (near-black, neutral)
  • Accent: #6366f1 (indigo — readable, modern, not product-specific)
  • Text: #ffffff
  • Muted text: rgba(255,255,255,0.55)
  • Card bg: rgba(255,255,255,0.06)

These are STARTING POINTS only. The moment the user shares brand colors, replace them entirely.

What NOT to do without brand info

  • Do NOT use neon/cyber colors — that's a personal aesthetic, not a brand match
  • Do NOT use paddingTop: 120 and call it "centered" — it's top-aligned with dead space
  • Do NOT pick fontSize: 32 for a headline because it "looks clean" — it's illegible on video

Rule #1 — Canvas is NOT a Website

This is the single most common mistake in AI-generated Remotion videos.

Remotion canvas is 1920×1080px. Design to fill it — not like a webpage.

⚠️ These are MINIMUMS. Writing fontSize: 18 for body text is a BUG, not a style choice. Anything below the minimum column means the text is unreadable on a 1080p screen. Treat these numbers like type errors — they must be fixed before moving on.

ElementMINIMUM (hard floor)Recommended Range
Main headline80px100–160px
Sub-headline40px48–72px
Body / description28px32–40px
Label / pill / badge18px20–24px
Card content text22px24–32px

Rules:

  • Content must feel like it fills the screen
  • Mockup cards: width: 1100–1200px, centered
  • Container padding: max 48px — NOT 80–120px like a webpage
  • If text feels "too big for comfort" — it's probably right for video

Rule #2 — All Animations MUST Use useCurrentFrame()

// CORRECT
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 20], [0, 1], {
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});

// FORBIDDEN — will NOT render correctly
// CSS: transition: opacity 1s ease
// Tailwind: animate-fade-in
// CSS @keyframes

Always include extrapolateLeft: "clamp" and extrapolateRight: "clamp" on every interpolate() call unless you explicitly need unbounded values. Forgetting this causes values to bleed outside their range and creates subtle bugs.


Rule #3 — Determinism

// FORBIDDEN — different value on every render pass
const x = Math.random() * 100;

// CORRECT — same value every time, every frame
import { random } from "remotion";
const x = random("particle-x-1") * 100; // string seed = deterministic

Rule #4 — Assets

import { staticFile } from "remotion";
import { Img } from "remotion";        // NOT native <img>
import { Audio } from "@remotion/media";

// Always use staticFile() for anything in public/ folder
<Audio src={staticFile("bg-music.mp3")} />
<Img src={staticFile("logo.png")} />   // <Img> ensures asset loads before frame renders

// Remote URLs don't need staticFile() but require CORS

Rule #5 — Smooth Preview Playback

Add premountFor={30} on <Sequence> components so heavy components preload 30 frames before their time:

<Sequence from={90} durationInFrames={120} premountFor={30}>
  <HeavyScene />
</Sequence>

Easing Recipes

import { Easing } from "remotion";

// Crisp UI entrance (strong ease-out, no overshoot) — most enter animations
Easing.bezier(0.16, 1, 0.3, 1)

// Slow editorial fade (balanced ease-in-out) — mood transitions
Easing.bezier(0.45, 0, 0.55, 1)

// Playful overshoot — bouncy/fun elements
Easing.bezier(0.34, 1.56, 0.64, 1)

// Spring — no bounce (mockup entries, cards, UI)
spring({ frame, fps, config: { damping: 200 } })

// Spring — snappy with slight bounce (punchy elements)
spring({ frame, fps, config: { damping: 20, stiffness: 200 } })

// Spring — bouncy/playful
spring({ frame, fps, config: { damping: 8 } })

Pre-Layout Gates — Run BEFORE Writing Any Scene Layout

These are not suggestions. Run all three gates before writing the first <div> of any scene. If any gate fails, change the layout — never patch with fixed dimensions or extra content.


Gate 1 — Canvas Fill (both axes, mandatory)

Width axis:
  dead_side = (1920 − content_width) / 2
  MUST be ≤ 300px. If > 300px → content is too narrow. Widen it or change layout.

Height axis:
  fill_h = content_height / 1080
  MUST be ≥ 0.80. If < 0.80 → content is too short. Change the layout shape.

⚠️ If height fails, do NOT fix it by setting a fixed height on cards or containers. A fixed height creates an empty void inside the card — the dead space moves inside the element instead of being eliminated. The only real fix is changing the layout shape (Gate 2).

Real failure example — 3 short feature cards:

Versioncontent_widthdead_sidecontent_heightfill_hVerdict
v1: 3-col cards (365px)1151px384px416px38%❌ both axes fail
v2: forced height: 720px1542px189px864px80%✅ width, ❌ visual (empty void in card)
v3: horizontal rows (1400px)1400px260px916px85%✅ both axes pass

Gate 2 — Layout Selection Decision Table

Content volume determines layout shape. Choose layout from this table BEFORE writing code.

ItemsContent per itemCorrect layoutWhy
3–5 itemsicon + name + 1 lineHorizontal rows (1400px wide)Short content stacks vertically → fills height naturally
3 itemsicon + name + 2–3 lines3-column cards (min 1100px wide)Enough content to fill card height without void
2 itemssubstantialSide-by-side large cards or split-screen
1 itemanythingFull-screen hero

If the natural layout for your content leaves either axis below threshold after Gate 1 — that layout is wrong. Pick a different row in this table.

Never choose layout by aesthetics or default instinct. Content fit first. Aesthetics second.


Gate 3 — Content Density Limit

Per item maximum: icon + name + 1 short line. Hard stop. No bullets. No sub-sections. No paragraphs. No second description lines.

A viewer has ~5 seconds per scene. They read 1 line. They do not read 4 bullets.

If content feels thin and you want to add more to fill space — that is Gate 2 telling you the layout shape is wrong, not that content is missing.

Fill empty space with SIZE (bigger fonts, bigger icons, larger gaps between items) — never with more content.


Universal Scene Rules

  1. Vertical alignment — justifyContent: "center" + marginTop: -40 to -60 (slightly above true center = modern, premium feel. NOT top-aligned with padding.)

    ❌ WRONG — top-aligned, leaves empty space at bottom:

    <AbsoluteFill style={{ display: "flex", flexDirection: "column", paddingTop: 110 }}>
      <h1>Headline</h1>
      <p>Subtext</p>
      {/* large empty void at bottom */}
    </AbsoluteFill>
    

    ✅ RIGHT — vertically centered, slightly above midpoint:

    <AbsoluteFill style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", marginTop: -50 }}>
      <h1>Headline</h1>
      <p>Subtext</p>
      {/* content fills the frame — no dead space */}
    </AbsoluteFill>
    
  2. Canvas fill — run Pre-Layout Gates before writing this scene. Gate 1 checks both width (dead_side ≤ 300px) and height (fill_h ≥ 0.80) together. Gate 2 selects the layout shape from the decision table. Gate 3 caps content per item. All three gates live in the Pre-Layout Gates section above — they supersede the old width-only check that was here.

  3. Headline z-index — always zIndex: 20 on headline container so mockup never overlaps text

  4. Headline overflow — always whiteSpace: "nowrap" on headline text (prevents wrap behind mockup)

  5. No overflow: hidden on AbsoluteFill — clips cursor and SVG elements. Remove it or place cursor outside.

  6. 15 frame hold — every scene must have at least 15 frames of fully-visible hold at the END before transition fires. Never start a transition while an animation is still playing in the outgoing scene.

  7. Font — use one consistent font throughout. Recommended: Plus Jakarta Sans via @remotion/google-fonts. Max available weight: 800 (writing fontWeight: 900 renders as 800).

  8. Color — 2–3 brand colors max. One dark background, one primary accent, white/muted white for text. Consistent across all scenes.

Typography Hierarchy

// Supertitle / Label pill
{ fontSize: 20, letterSpacing: "4px", textTransform: "uppercase", fontWeight: 600 }

// Main headline
{ fontSize: 112, fontWeight: 800 }  // range: 100–160px

// Sub-text / description
{ fontSize: 36, opacity: 0.7 }  // range: 32–40px

// Trust line / small badges
{ fontSize: 26, opacity: 0.5 }  // range: 24–28px

Font Setup

import { loadFont } from "@remotion/google-fonts/PlusJakartaSans";

// Call at top level — must load before render
const { fontFamily } = loadFont("normal", {
  weights: ["400", "600", "800"],
  subsets: ["latin"],
});

For other fonts: install via @remotion/google-fonts/FontName or drop .woff2 in public/ and use loadFont from @remotion/fonts.


Scene Structure Template

Every scene follows this fixed layer order (bottom → top):

<AbsoluteFill style={{ background: brandBg }}

Related Skills