Chromatic Wave

A soft wave travels down through the type; where it crosses, the letters ripple and split into RGB fringes, then settle back to white

Installation
$ pnpm dlx shadcn@latest add @remocn/chromatic-wave

Usage

tsx
// src/Root.tsx
import { Composition } from "remotion";
import { ChromaticWave } from "@/components/remocn/chromatic-wave";
 
const ChromaticWaveScene = () => (
  <ChromaticWave headline="MUSIC" kicker="APPLES" />
);
 
export const RemotionRoot = () => (
  <Composition
    id="ChromaticWave"
    component={ChromaticWaveScene}
    durationInFrames={100}
    fps={30}
    width={1920}
    height={1080}
  />
);

Three copies of the type are displaced by the same traveling wave at three different depths — one per color channel — and summed back together with screen blending. Where the copies still coincide the sum is white; where the depths pull them apart, red, green and blue fringes appear. The component paints its own background (default black) because the reassembly is only exact over black.

Props20

PropTypeDefault
headline
string"MUSIC"

The large center line

kicker
string"APPLES"

The small tracked line, repeated above and below the headline

headlineFontFamily / kickerFontFamily
stringHelvetica stack

Fonts of the two lines

headlineFontSize / kickerFontSize
number174 / 52

Font sizes in comp pixels

kickerTracking
number32

Letter spacing of the kicker lines

headlineBaselineY / kickerBaselines
number / [number, number]601 / [444, 670]

Baselines of the three lines in comp pixels

textCenterX
number960

Horizontal center of the type

fill
string"#ffffff"

Color of the type before the split

background
string"#000000"

Painted stage background. Keep it dark — the channel reassembly is only exact over black

width / height
number1920 / 1080

Coordinate space of the composition

bandHeight / bandCopies / bandPitch
number147.1 / 7 / 750

Geometry of the traveling distortion bands

mapStartY / mapEndY / mapTravelFrames
number31 / 1560 / 150

The bands' travel. Deliberately linear — an ease reads as the ripple hesitating inside the word

waveHeight / waveWidth / waveSpeed
number28 / 272 / 1

The sine ripple on each band's edges

turbulentAmount / turbulentSize
number130 / 163

Turbulent displacement breaking the wave's regular rhythm

evolutionPerSecond
number50

How fast the turbulence field pans

mapBlurRadius / mapBlurIterations
number13 / 6

Blur on the displacement map — without it the map's edges tear the output

glassDisplacement / maxDisplacementPx
number100 / 39

Displacement strength, and the pixel span it maps to

glassPasses
number3

How many depth passes — also how many channels split

channelOrder
("red" | "green" | "blue")[]["blue", "green", "red"]

Which channel rides which depth, shallowest first

className
string—

Optional className passed to the wrapper

  • headlinestring

    The large center line

    Default"MUSIC"

  • kickerstring

    The small tracked line, repeated above and below the headline

    Default"APPLES"

  • headlineFontFamily / kickerFontFamilystring

    Fonts of the two lines

    DefaultHelvetica stack

  • headlineFontSize / kickerFontSizenumber

    Font sizes in comp pixels

    Default174 / 52

  • kickerTrackingnumber

    Letter spacing of the kicker lines

    Default32

  • headlineBaselineY / kickerBaselinesnumber / [number, number]

    Baselines of the three lines in comp pixels

    Default601 / [444, 670]

  • textCenterXnumber

    Horizontal center of the type

    Default960

  • fillstring

    Color of the type before the split

    Default"#ffffff"

  • backgroundstring

    Painted stage background. Keep it dark — the channel reassembly is only exact over black

    Default"#000000"

  • width / heightnumber

    Coordinate space of the composition

    Default1920 / 1080

  • bandHeight / bandCopies / bandPitchnumber

    Geometry of the traveling distortion bands

    Default147.1 / 7 / 750

  • mapStartY / mapEndY / mapTravelFramesnumber

    The bands' travel. Deliberately linear — an ease reads as the ripple hesitating inside the word

    Default31 / 1560 / 150

  • waveHeight / waveWidth / waveSpeednumber

    The sine ripple on each band's edges

    Default28 / 272 / 1

  • turbulentAmount / turbulentSizenumber

    Turbulent displacement breaking the wave's regular rhythm

    Default130 / 163

  • evolutionPerSecondnumber

    How fast the turbulence field pans

    Default50

  • mapBlurRadius / mapBlurIterationsnumber

    Blur on the displacement map — without it the map's edges tear the output

    Default13 / 6

  • glassDisplacement / maxDisplacementPxnumber

    Displacement strength, and the pixel span it maps to

    Default100 / 39

  • glassPassesnumber

    How many depth passes — also how many channels split

    Default3

  • channelOrder("red" | "green" | "blue")[]

    Which channel rides which depth, shallowest first

    Default["blue", "green", "red"]

  • classNamestring

    Optional className passed to the wrapper

Inspired by 5 Clean Text Animations by Mapal.