Anti-patterns

The dozen mistakes that recur when a video is generated, each with the fix beside it

Common mistakes when generating remocn videos. Each is something a model tends to get wrong.

Clipping a component by under-budgeting its Sequence

Every component has a natural length. Budget the Sequence around it — under-budgeting cuts the animation off mid-motion, over-budgeting leaves dead air.

// ❌ blur-out-up needs ~90f, gets cut at 30
<Sequence durationInFrames={30}><BlurOutUp text="Launch" /></Sequence>
// ✅
<Sequence durationInFrames={90}><BlurOutUp text="Launch" /></Sequence>

Natural lengths for every component are listed in /llms-components.txt.

Mounting a transition as a component

Transitions are presentations for @remotion/transitions — pass them to TransitionSeries.Transition, never mount them directly.

// ❌
<WhipPan />
<SceneB />
// ✅
<TransitionSeries>
  <TransitionSeries.Sequence durationInFrames={70}><SceneA /></TransitionSeries.Sequence>
  <TransitionSeries.Transition
    timing={linearTiming({ durationInFrames: 26 })}
    presentation={whipPan()}
  />
  <TransitionSeries.Sequence durationInFrames={70}><SceneB /></TransitionSeries.Sequence>
</TransitionSeries>

Animation-tier props on a UI primitive

Primitives (remocn-ui) are state-based and have no speed. Drive them with state.

// ❌
<Dialog speed={2} />
// ✅
<Dialog state="open" />

Wrong canvas size

The standard composition is 1280×720 @ 30fps. Components are laid out for it. Don't invent 1920×1080 and wonder why things are off-center.

Animating layout properties

Animate transform (and individual translate / scale), never top / left / width / height — layout animation reflows every frame and breaks split layouts.

// ❌ left: interpolate(frame, [0,30], [0,200])
// ✅ transform: `translateX(${interpolate(frame,[0,30],[0,200])}px)`

Non-deterministic code

Renders are multi-pass — Math.random(), setInterval / setTimeout and Date.now() all produce flicker or diverging frames.

// ❌ const x = Math.random();
// ✅ import { random } from "@remotion/random"; const x = random(`seed-${frame}`);

Mishandling registryDependencies

Dependencies install automatically — don't tell the user to add them manually, and don't inline-copy a dependency's code. Also don't import deeper than one path segment (@/components/remocn/<name>); the tsconfig glob doesn't resolve <name>/helpers.

Loading fonts mid-render

Load fonts once before render via @remotion/google-fonts (loadFont()), not inside a component body per frame. Unloaded fonts flash a fallback in the export.

Hardcoding a background on a component

remocn components render transparent — they don't own a background. Set the scene background with backdrop or your own container, not by hardcoding a fill into the component.

Slop styling on your own additions

ALL-CAPS plus wide tracking plus gradient text plus glow shadows on text you add. See Design defaults.

Everything enters on one frame

Stagger sibling entrances by 3–6 frames. Landing a whole group simultaneously reads robotic. See Motion principles → follow-through and overlapping action.

Promoting the wrong layer under a slow zoom

Text under drift trembles — glyph rasters snap to whole device pixels while the zoom keeps them in sub-pixel motion. The fix is one willChange: "transform" layer per text container. Never promote per-word or per-character spans (many small text layers shimmer even at rest) and never Drift itself (borders become resampled texture, so 1px lines pulse between sharp and blurry as the scale creeps).

// ❌ <Drift><div style={{ willChange: "transform" }}>{scene}</div></Drift> — borders pulse
// ❌ chars.map((c) => <span style={{ willChange: "transform" }}>{c}</span>) — shimmer at rest
// ✅ bordered card unpromoted; inner text block gets willChange: "transform"