Remotion Dev Skills

repository·main·Indexed 26 days ago

https://github.com/remotion-dev/skills

A collection of best practices and implementation guides for the Remotion ecosystem. Covers captioning using @remotion/captions and @remotion/install-whisper-cpp, project scaffolding with create-video, Remotion Studio interactivity, map animations with Mapbox, MapLibre, MapTiler, and CesiumJS, and workflows for fetching Remotion documentation in Markdown format.

Tokens
85.7K
Snippets
274
Records
404
Agent score
83%

What's inside @remotion/skills

  1. Alternative Rendering Platforms

    main

    Depending on your infrastructure requirements, you can use the following platforms for Remotion rendering:

    • Vercel: Ideal for applications deployed to the Vercel platform.
    • GitHub Actions: Can be used for rendering via GitHub Actions workflows.
    • Azure Container Apps: Suitable for rendering within Azure's containerized environment.
    • Cloudflare Containers: An option for rendering on Cloudflare's container infrastructure.
  2. Choose a map technique for Remotion animations

    main

    When creating map animations in Remotion, choose exactly one technique based on your requirements for styling, interactivity, and cost. Each technique is self-contained.

    Available techniques include:

    • Static map: Best for simple satellite image overlays using an <Img> tag.
    • Mapbox: Best for high-quality styles, 3D buildings (e.g., Eiffel Tower), and a round globe view when zoomed out. Requires a Mapbox API key.
    • MapLibre: Best for a fully free, open-source option that requires no API key. Does not support 3D buildings.
    • MapTiler: Best for drawing annotations on top of geographic features like borders, rivers, and labels.
    • CesiumJS: Best for terrain/mountain flythroughs and a "flight simulator" perspective.
  3. Use TransitionSeries for scene transitions and overlays

    main

    <TransitionSeries> is a container that arranges scenes and allows you to enhance the cut points between them using two methods:

    1. Transitions (<TransitionSeries.Transition>): Visual effects like crossfades, slides, or wipes. These cause the two adjacent scenes to play simultaneously during the transition, which shortens the total timeline duration.
    2. Overlays (<TransitionSeries.Overlay>): Renders a component (e.g., a light leak) on top of the cut point. Overlays do not shorten the timeline.

    Children of <TransitionSeries> are absolutely positioned.

    Constraint: An overlay cannot be placed immediately adjacent to a transition or another overlay.

  4. Choose a map animation technique for Remotion

    main

    The remotion-maps skill provides several distinct techniques for creating map animations in Remotion. You should choose exactly one technique based on your requirements for styling, cost, and features. Each technique is self-contained within its own directory.

    Available Techniques:

    • Static map: Best for simple animations where you use a pre-captured satellite image mounted in an <Img> tag and animate elements on top of it.
    • Mapbox: Provides high-quality styles by default, supports a round globe view when zoomed out, and includes 3D buildings (e.g., the Eiffel Tower). Requires a Mapbox API key.
    • MapLibre: A fully free option that requires no API key. It does not support 3D buildings.
    • MapTiler: Uses the MapTiler service. It allows for annotations to be drawn on top of geographic features like borders, rivers, and labels.
    • CesiumJS: Best for cinematic flythroughs through terrain and mountains, offering a "flight simulator" perspective.
  5. Get audio duration with Mediabunny

    main

    Use the mediabunny library to extract the duration of an audio file in seconds. This works in browser, Node.js, and Bun environments. To use a remote URL, instantiate an Input with a UrlSource. The computeDuration() method returns the duration as a number representing seconds.

    import { Input, ALL_FORMATS, UrlSource } from "mediabunny";
    
    export const getAudioDuration = async (src: string) => {
      const input = new Input({
        formats: ALL_FORMATS,
        source: new UrlSource(src, {
          getRetryDelay: () => null,
        }),
      });
    
      const durationInSeconds = await input.computeDuration();
      return durationInSeconds;
    };
    
    // Usage
    const duration = await getAudioDuration("https://remotion.media/audio.mp3");
    console.log(duration); // e.g. 180.5
  6. Calculate country `anchor` points using Pole of Inaccessibility

    main

    To place labels in the most interior part of a country, use the 'pole of inaccessibility' rather than a centroid (which can be pulled to edges).

    1. Clip to BBox: Clip the country polygon to a specific ANCHOR_BBOX (the story region) so large countries center in the relevant area.
    2. Grid Sampling: Perform a grid sample inside the polygon and select the point with the maximum distance to the boundary (the edge).
    3. Nudge: Apply a manual NUDGE (longitude/latitude offset) to fine-tune label placement.
    const pole = (poly) => {
      const bb = turf.bbox(poly), edge = turf.polygonToLine(poly), N = 46;
      let best = null, bestD = -1;
      for (let i = 0; i <= N; i++) for (let j = 0; j <= N; j++) {
        const p = turf.point([bb[0]+(bb[2]-bb[0])*i/N, bb[1]+(bb[3]-bb[1])*j/N]);
        if (!turf.booleanPointInPolygon(p, poly)) continue;
        const d = turf.pointToLineDistance(p, edge);
        if (d > bestD) { bestD = d; best = p.geometry.coordinates; }
      }
      return best;
    };
    
    // Example configuration for story regions and manual nudges
    const ANCHOR_BBOX = { china:[82,27,96,32], india:[76,14,99,31], bangladesh:[86,20,93,27] };
    const NUDGE = { china:[0,0.6], india:[-1.0,0], bangladesh:[0,-0.6] };
  7. Render transparent ProRes videos

    main

    Use ProRes when you need to import transparent videos into video editing software. You can achieve this via the CLI, by configuring global defaults in remotion.config.ts, or by setting composition-specific defaults using calculateMetadata.

    ### CLI
    ```bash
    npx remotion render --image-format=png --pixel-format=yuva444p10le --codec=prores --prores-profile=4444 MyComp out.mov

    Global Config (remotion.config.ts)

    import { Config } from "@remotion/cli/config";
    
    Config.setVideoImageFormat("png");
    Config.setPixelFormat("yuva444p10le");
    Config.setCodec("prores");
    Config.setProResProfile("4444");

    Composition Metadata

    import { CalculateMetadataFunction } from "remotion";
    
    const calculateMetadata: CalculateMetadataFunction<Props> = async ({ props }) => {
      return {
        defaultCodec: "prores",
        defaultVideoImageFormat: "png",
        defaultPixelFormat: "yuva444p10le",
        defaultProResProfile: "4444",
      };
    };
    
    <Composition
      id="my-video"
      component={MyVideo}
      durationInFrames={150}
      fps={30}
      width={1920}
      height={1080}
      calculateMetadata={calculateMetadata}
    />;
  8. Configure CesiumJS modes and credentials

    main

    CesiumJS flyovers in Remotion support two primary modes depending on the desired visual style. You must provide the corresponding API keys via environment variables.

    Available Modes

    • landscape: Uses MapTiler terrain-quantized-mesh-v2 and satellite-v2. Best for mountains, gorges, rivers, and rural routes.
    • city: Uses Google Photorealistic 3D Tiles. Best for cities, architecture, and landmarks. Note: Do not use footprint extrusions for city flyovers as they produce crude building blocks.

    Required Credentials

    • For landscape mode: Set REMOTION_MAPTILER_KEY using a key from MapTiler.
    • For city mode: Set REMOTION_GOOGLE_MAPS_API_KEY. You must create a billing-enabled Google Map Tiles API key, enable the Map Tiles API, and ensure application restrictions permit local headless Remotion requests.
  9. Play elements sequentially with `<Series>`

    main

    Use the <Series> component when elements should play one after another without overlap. Within a <Series>, use <Series.Sequence> to define the duration of each segment. Like standard sequences, these wrap children in an AbsoluteFill unless layout="none" is specified.

    import { Series } from "remotion";
    
    <Series>
      <Series.Sequence durationInFrames={45}>
        <Intro />
      </Series.Sequence>
      <Series.Sequence durationInFrames={60}>
        <MainContent />
      </Series.Sequence>
      <Series.Sequence durationInFrames={30}>
        <Outro />
      </Series.Sequence>
    </Series>;
  10. Animate properties using inline `interpolate()`

    main

    To make animations editable in the Studio, write interpolate() calls directly inside the style object.

    Requirements for Interactivity:

    • Inline Calls: The interpolate() call must be inside the markup, not assigned to a variable beforehand.
    • Hardcoded Values: The output range, easing, extrapolation, and output property must use hardcoded values.
    • Supported Variables: You can use frame and values destructured from useVideoConfig() (like fps, durationInFrames, width, and height).
    • Supported Math: You can use bare identifiers, multiplication with numbers (e.g., 2 * fps), or subtraction (e.g., durationInFrames - 1).
    • CSS Properties: Use scale, rotate, and translate instead of the transform property, as only the individual properties are interactively editable.
    const {fps, durationInFrames} = useVideoConfig();
    
    <Interactive.Div
      name="Product card"
      style={{
        color: 'white',
        fontSize: 80,
        scale: interpolate(frame, [0, fps], [0, 1], {
          easing: Easing.spring({damping: 200}),
          output: 'perceptual-scale',
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp'
        }),
        rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], {
          easing: Easing.spring({damping: 200}),
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp'
        }),
        translate: interpolate(frame, [durationInFrames - 30, durationInFrames], ['0px 0px', '0px 120px'], {
          easing: Easing.spring({damping: 200}),
          output: 'perceptual-scale',
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp'
        }),
      }}
    />