Files
Daniil 6e82165566
compute / deploy (push) Has been cancelled
chore: agentic upgrade
2026-05-17 02:12:18 +03:00

8.3 KiB

name, description
name description
remotion-best-practices Use when writing, reviewing, or refactoring Remotion code in this repository, including compositions, dynamic metadata, @remotion/media video/audio, CLI or renderer rendering, Docker/Chromium settings, queue progress/cancellation, or render performance.

Remotion Best Practices

Overview

Apply current Remotion guidance to this Bun rendering service without losing the project-specific details that make renders reliable: dynamic metadata, S3 input URLs, BullMQ progress, Docker Chromium, and cleanup of generated artifacts.

Workflow

  1. Fetch current Remotion docs first with Context7. This repo pins Remotion packages at 4.0.435, so compare docs version badges against that version before using newer API options.
  2. Identify the layer being changed:
    • Composition UI: src/components/Composition.tsx, src/components/Captions.tsx
    • Composition registration and metadata: src/components/Root.tsx, src/hooks/useVideoMeta.ts
    • Render orchestration: server/services/render_video.ts, server/services/render_queue.ts
    • Runtime config: remotion.config.ts, Dockerfile, .env.example, server/config.ts
  3. Keep render behavior deterministic. A frame should be a pure function of props, frame number, and explicitly loaded assets.
  4. Verify with bun run lint and a focused smoke test: Remotion Studio, bun run render with valid props, or the API/queue path when server behavior changed.

Project Map

  • Runtime: Bun, React 19, Remotion 4.0.435.
  • Entry point: src/index.ts registers RemotionRoot.
  • Main composition: CaptionedVideo in src/components/Root.tsx.
  • Metadata: getVideoMeta() uses calculateMetadata plus @remotion/media-parser parseMedia() to set duration, dimensions, and fps from the input video.
  • Media rendering: CaptionsComposition uses @remotion/media Video, with captions overlaid in AbsoluteFill.
  • Server rendering: renderCaptionedVideo() writes props JSON into out/, runs ./node_modules/.bin/remotion render src/index.ts ... --props, parses CLI progress output, and deletes the props file in finally.
  • Queue wrapper: BullMQ controls job concurrency through MAX_CONCURRENT_RENDERS, uploads finished files to S3, sends webhooks, and stores cancellation flags in Redis.
  • Docker: Chromium and FFmpeg are installed in the image; Remotion browser download is skipped; sandboxing is disabled through env.

Composition Rules

  • Animate with useCurrentFrame(), useVideoConfig(), interpolate(), spring(), and Sequence. Do not use CSS animations, CSS transitions, timers, or wall-clock time for render-critical motion.
  • Keep props JSON-serializable. When adding composition input fields, update src/types/captions_composition.d.ts, src/components/Root.tsx defaultProps, and the server-side props object together.
  • Avoid fetches or expensive async work inside frame-rendering components. Prefer server preprocessing or calculateMetadata() for data that changes duration, dimensions, fps, or props.
  • Use delayRender() only for assets that must block a frame, such as dynamic CSS/font loading. In new code prefer useDelayRender() where practical, and always clear or cancel every handle on success and failure.
  • Use AbsoluteFill for full-frame layers and Sequence for frame-based timing. Convert seconds with the active fps, not a hardcoded 30 unless the composition contract really is fixed at 30 fps.

Metadata

  • Keep dynamic duration and dimensions in calculateMetadata, not component useEffect(). In Remotion v4, useEffect() can run again for render workers and multiply API calls.
  • For this repo, preserve the existing parseMedia() path unless deliberately upgrading. Current Remotion docs are moving media metadata toward Mediabunny, so check docs before adding new metadata helpers.
  • Use Math.ceil(durationInSeconds * fps) and keep the existing minimum of one frame so zero-length or partially unreadable metadata cannot produce invalid compositions.
  • If metadata fetching starts using fetch(), pass Remotion's abortSignal so cancelled metadata calculations stop promptly.
  • When migrating from the CLI to @remotion/renderer, pass the same inputProps to both selectComposition() and renderMedia() so calculateMetadata() and the actual render resolve the same composition.

Media And Assets

  • Local reusable assets belong in public/ and should be referenced with staticFile(). The public/ folder must stay beside the project package.json.
  • Remote video URLs from S3/MinIO are valid, but they must be accessible from the Chromium process inside Docker. Prefer presigned URLs with enough TTL for queue wait time plus render time.
  • This repo currently uses @remotion/media Video. It is frame-perfect and fast, but respect version badges: options introduced after 4.0.435 require a package upgrade before use.
  • Do not use objectFit on @remotion/media Video while the project remains on 4.0.435; the docs mark it as 4.0.442. Use sizing wrappers or upgrade Remotion intentionally.
  • Do not use credentials on @remotion/media Video while on 4.0.435; the docs mark it as 4.0.437. Prefer signed public URLs for protected videos in this version.
  • Keep Config.setVideoImageFormat("jpeg") for regular opaque videos. Switch to png only when transparency or color-accuracy requirements justify the slower render and larger intermediate frames.
  • For unsupported media, HLS, looping, alpha channels, pitch shifts, or frame-manipulation callbacks, re-check the current docs for @remotion/media Video, OffthreadVideo, and their fallback behavior before changing code.

Render Service Rules

  • The current CLI path means remotion.config.ts applies. If switching to Node/Bun APIs, move needed options into bundle(), selectComposition(), or renderMedia() because Remotion config is not automatically applied there.
  • Keep the two concurrency knobs separate:
    • BullMQ MAX_CONCURRENT_RENDERS controls simultaneous videos.
    • Remotion render concurrency controls frame workers inside one video. Tune both against Docker CPU and memory limits; a 4 GB / 2 CPU container can run out of memory quickly with multiple video jobs.
  • Prefer renderer callbacks (onStart, onProgress, onBrowserLog, onDownload) if moving to @remotion/renderer. Keep CLI progress parsing tolerant because CLI log text can change.
  • If moving to @remotion/renderer, use makeCancelSignal() instead of only killing a process. Keep Redis cancellation and upload abort behavior aligned.
  • Preserve bounded stdout/stderr capture. Render failures should include enough tail output for debugging without logging full user media paths or huge logs.
  • Keep generated files under out/, remove props JSON in finally, and remove rendered files after upload. Never commit render outputs or real .env values.
  • In Docker, keep Chromium, FFmpeg, emoji fonts, and Linux browser libraries in sync with Remotion requirements. If browser detection changes, configure an explicit browser executable or Remotion renderer option instead of relying on accidental host state.

Validation

  • Always run bun run lint after TypeScript or Remotion changes.
  • For composition/caption layout changes, run Remotion Studio or a short render using valid props with an accessible videoSrc.
  • For API, queue, cancellation, or upload changes, run bun run server and smoke the affected /api/render flow, including callback/progress behavior when touched.
  • For Docker/browser/render-performance changes, smoke through docker compose up --build remotion when feasible because local host Chrome behavior is not enough evidence.

Source Anchors