Glitch Cut

Tear a hard cut into displaced slices with channel split and corrupted blocks

Installation
$ pnpm dlx shadcn@latest add @remocn/glitch-cut

Usage

glitchCut() is a Remotion transition presentation. Pass it to a TransitionSeries.Transition between two sequences. The frame breaks into horizontal slices that slide apart, the colour channels separate, and blocks of the frame corrupt into the wrong scene — then each slice hands over to the incoming scene on its own beat around the midpoint, so the cut itself is torn rather than flat. Both ends of the transition settle to untouched pixels, so nothing bleeds into the scenes on either side.

It is built for short timings. linearTiming({ durationInFrames: 12 }) is the recommended default; past roughly 20 frames the tearing stops reading as an artifact and starts reading as an effect.

tsx
import { TransitionSeries, linearTiming } from "@remotion/transitions";
import { glitchCut } from "@/components/remocn/glitch-cut";
 
export const MyVideo = () => (
  <TransitionSeries>
    <TransitionSeries.Sequence durationInFrames={45}>
      <SceneA />
    </TransitionSeries.Sequence>
    <TransitionSeries.Transition
      timing={linearTiming({ durationInFrames: 12 })}
      presentation={glitchCut()}
    />
    <TransitionSeries.Sequence durationInFrames={45}>
      <SceneB />
    </TransitionSeries.Sequence>
  </TransitionSeries>
);

Installing it also installs lib/remocn/canvas-presentation.tsx, the shared scaffolding behind every canvas transition. It owns the support check, the WebGL2 scene shader that receives both sides of the cut as textures, and the routing that swaps in the CSS fallback where the browser has no html-in-canvas.

Determinism

Every pixel is a pure function of the transition's progress. The slice displacement, the block corruption and the per-slice handover all come from a hash seeded on the slice index and on a 22-step clock derived from progress — no wall-clock time, no state carried between frames. The same frame renders identically on every machine and in every chunk, so parallel and server-side renders come out seam-free.

Fallback

Where html-in-canvas is unavailable the presentation renders a CSS approximation instead: the frame is clipped into bands that shift horizontally on the same seeded clock, each band tinted alternately red and cyan to stand in for the channel split, and each band hands over to the incoming scene at its own staggered cut point. It reads as the same edit — a torn hard cut — without touching pixels. slices still drives how many bands there are; blockNoise has no effect there.

Props

glitchCut(props) accepts:

PropTypeDefault
intensity
number1

Overall displacement. Scales how far slices and corrupted blocks slide sideways. 0 leaves the geometry intact and keeps only the channel split.

slices
number24

How many horizontal slices the frame is cut into. Low counts read as chunky tape damage, high counts as fine scanline tearing.

rgbSplit
number1

Chromatic separation of the red and blue channels at the peak of the glitch. 0 keeps the colour clean.

blockNoise
number0.6

How much of the frame corrupts into displaced blocks that leak the other scene. 0 keeps the tearing purely horizontal.

  • intensitynumber

    Overall displacement. Scales how far slices and corrupted blocks slide sideways. 0 leaves the geometry intact and keeps only the channel split.

    Default1

  • slicesnumber

    How many horizontal slices the frame is cut into. Low counts read as chunky tape damage, high counts as fine scanline tearing.

    Default24

  • rgbSplitnumber

    Chromatic separation of the red and blue channels at the peak of the glitch. 0 keeps the colour clean.

    Default1

  • blockNoisenumber

    How much of the frame corrupts into displaced blocks that leak the other scene. 0 keeps the tearing purely horizontal.

    Default0.6