# Lens Zoom
URL: https://remocn.dev/docs/transitions/lens-zoom

A hard cut disguised as a lens punch-in — barrel distortion, zoom blur, chromatic split and camera shake around the splice

- Install: `npx shadcn@latest add @remocn/lens-zoom`
- Vibe: premium
- Natural length: 28f @ 30fps

## Installation

```bash
npx shadcn@latest add @remocn/lens-zoom
```

## Usage

`lensZoom()` is a Remotion transition presentation. The transition is a hard
cut, not a dissolve: the outgoing half owns progress 0–0.5 and the incoming
half owns 0.5–1, so the splice lands exactly halfway through the transition.
Use `LENS_ZOOM_DURATION_IN_FRAMES` (28) with `linearTiming` for the tutorial's
pacing — two equal 14-frame ramps either side of the cut.

```tsx
import { TransitionSeries, linearTiming } from "@remotion/transitions";
import {
  lensZoom,
  LENS_ZOOM_DURATION_IN_FRAMES,
} from "@/components/remocn/lens-zoom";

export const MyVideo = () => (
  <TransitionSeries>
    <TransitionSeries.Sequence durationInFrames={70}>
      <SceneA />
    </TransitionSeries.Sequence>
    <TransitionSeries.Transition
      timing={linearTiming({ durationInFrames: LENS_ZOOM_DURATION_IN_FRAMES })}
      presentation={lensZoom()}
    />
    <TransitionSeries.Sequence durationInFrames={70}>
      <SceneB />
    </TransitionSeries.Sequence>
  </TransitionSeries>
);
```

Performance scales with `blurSamples × (lensSteps + 1)` painted copies of each
scene per frame, tripled when the three channel scales differ. Setting
`redScale`, `greenScale` and `blueScale` equal skips the chromatic split
entirely — the single biggest thing to turn off while dialling the transition
in.

## Props

`lensZoom(props)` accepts:

| Prop | Type | Default | Description |
|---|---|---|---|
| `inScaleFrom / inScaleTo` | `number` | `100 / 150` | Scale ramp of the outgoing half, in percent |
| `inFovFrom / inFovTo` | `number` | `0 / 160` | Lens distortion FOV ramp of the outgoing half, in degrees |
| `inBlurFrom / inBlurTo` | `number` | `0 / 60` | Zoom blur amount ramp of the outgoing half |
| `inRotationFrom / inRotationTo` | `number` | `0 / -15` | Rotation ramp of the outgoing half, in degrees |
| `outScaleFrom / outScaleTo` | `number` | `135 / 100` | Scale ramp of the incoming half — starts below the outgoing peak so the energy steps down at the cut |
| `outFovFrom / outFovTo` | `number` | `135 / 0` | Lens distortion FOV ramp of the incoming half |
| `outBlurFrom / outBlurTo` | `number` | `45 / 0` | Zoom blur amount ramp of the incoming half |
| `outRotationFrom / outRotationTo` | `number` | `345 / 360` | Rotation ramp of the incoming half — unwinds the outgoing twist |
| `anticipateScale` | `number` | `100` | Scale the outgoing scene squeezes down to before the punch — the wind-up before the jump. The lens, blur and rotation ramps hold until the squeeze ends. Disabled by default (scaling the full frame below 100 reveals the backdrop behind it) — prefer squeezing the subject inside the scene; set below `inScaleFrom` to enable the frame squeeze |
| `anticipatePortion` | `number` | `0.35` | Portion of the outgoing half spent on the squeeze. 0 disables it |
| `lensSteps` | `number` | `9` | Concentric rings approximating the barrel warp. Nearly free — the rings are disjoint |
| `blurSamples` | `number` | `7` | Scaled copies approximating the zoom blur. The expensive knob — higher is smoother |
| `blurScaleGain` | `number` | `1` | Scale span one unit of blur amount buys |
| `blurFade` | `number` | `1.5` | Higher keeps the sharp copy dominant over the smear |
| `shakeAmount` | `number` | `50` | Peak of the shake envelope around the cut. 0 disables the shake |
| `shakeFrequency` | `number` | `1.4` | Shake noise frequency |
| `shakeCyclesPerUnit` | `number` | `8` | Noise cycles per second one unit of frequency is worth |
| `shakeTranslatePx` | `number` | `73` | Peak shake translation in pixels |
| `shakeRotateDeg` | `number` | `1.1` | Peak shake rotation in degrees |
| `redScale / greenScale / blueScale` | `number` | `1.01 / 1.0 / 0.99` | Per-channel scales for the chromatic aberration. Set all three equal to skip the split |
| `letterboxAspect` | `number` | `0` | Cinematic bars aspect ratio (e.g. 2.39). 0 disables them |
| `width / height` | `number` | `composition size` | Stage size in pixels |
| `distortionCenterX / distortionCenterY` | `number` | `stage center` | Center of the lens distortion, blur and shake |

Inspired by [After Effects: Lens Zoom Transition Tutorial](https://www.youtube.com/watch?v=ePz-YEPXl6Y) by Creative Dojo.

## Use when
- A high-energy beat drop or reveal needs a cinematic camera move — the cut hides inside the peak of the distortion.
- You want the full optics package (lens warp, fading zoom blur, RGB fringing, shake) in one drop-in presentation.
- The two scenes are visually rich footage-like content that can sell a physical camera whip.

## Don't use when
- You just need a clean depth punch-in without the optics — use `zoom-blur`, the cheap variant of this move.
- You want static lens optics on a single scene rather than a transition — use `camera-lens`.
- The scenes are heavy React subtrees — every frame paints `blurSamples × (lensSteps + 1)` copies of the scene (×3 with the chromatic split); keep scenes light or turn the counts down.
- The pacing is calm or the brand is minimal — this is an aggressive, showy move.