Skip to content20cuts
Menu

FocusPull

Blur and dim a background layer to direct attention to a foreground result.

MarkdownView source

Installation

Run once from your product repo. The installer includes FocusPull, its source, and the agent skill.

Terminal
npx -y https://20cuts.com/releases/v0.3.0/20cuts-create-0.3.0.tgz video/20cuts

Already installed? Import it in your video project. Full setup guide

Import
import { FocusPull } from "./system/motion";

Usage

The starter already includes FocusPullExample in Remotion Studio. To edit a copy, save the Code tab as src/FocusPullExample.tsx and register it below.

Register in Remotion

Use the complete example from the Code tab. For a separate entry point, replace src/index.tsx with this registration, then run npm run studio.

src/index.tsx
import { Composition, registerRoot } from "remotion";
import { FocusPullExample } from "./FocusPullExample";

registerRoot(() => (
  <Composition
    id="FocusPullExample"
    component={FocusPullExample}
    width={1280}
    height={720}
    fps={30}
    durationInFrames={180}
  />
));

Props

PropTypeDefault
children

React content to display.

ReactNodeRequired
at

Start time in seconds within the current Remotion Sequence.

number0
duration

Animation duration in seconds.

number0.7
direction

Out adds blur and dimming; in removes them.

"out" | "in""out"
blur

Maximum blur radius in pixels.

number6
dim

Opacity at full defocus, from 0 to 1.

number0.45
style

Styles applied to the component wrapper.

CSSProperties
  • Place foreground content outside this wrapper to keep it sharp.
MotionTiming
MotionTiming type
Source
export type MotionTiming = {at?: number; duration?: number};
PropTypeDefault
at

Start time in seconds within the current Remotion Sequence.

number
duration

Animation duration in seconds.

number

Source

Read the component files
motion/direction.tsx
Source
import React, {type CSSProperties, type ReactNode} from "react";
import {useCurrentFrame, useVideoConfig} from "remotion";
import {cameraTransform, focusStyle, inOut, phase, type CameraPose, type MotionTiming} from "./core.js";

export type FocusPullProps = MotionTiming & {children: ReactNode; direction?: "out" | "in"; blur?: number; dim?: number; style?: CSSProperties};
export function FocusPull({children, at = 0, duration = 0.7, direction = "out", blur = 6, dim = 0.45, style}: FocusPullProps) {
  const p = inOut(phase(useCurrentFrame(), useVideoConfig().fps, at, duration));
  if (direction !== "out" && direction !== "in") throw new TypeError("direction must be out or in.");
  return <div style={{...style, ...focusStyle(direction === "out" ? p : 1 - p, blur, dim)}}>{children}</div>;
}

export type CameraRigProps = MotionTiming & {children: ReactNode; from: CameraPose; to: CameraPose; style?: CSSProperties};
/** The point in each pose is the world coordinate to place at the viewport center. */
export function CameraRig({children, from, to, at = 0, duration = 1.2, style}: CameraRigProps) {
  const frame = useCurrentFrame(), {fps, width, height} = useVideoConfig();
  const p = inOut(phase(frame, fps, at, duration));
  return <div style={{position: "absolute", inset: 0, ...style, transform: cameraTransform(from, to, p, width, height), transformOrigin: "0 0"}}>{children}</div>;
}