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-waveUsage
// 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.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
headline | string | "MUSIC" | The large center line |
kicker | string | "APPLES" | The small tracked line, repeated above and below the headline |
headlineFontFamily / kickerFontFamily | string | Helvetica stack | Fonts of the two lines |
headlineFontSize / kickerFontSize | number | 174 / 52 | Font sizes in comp pixels |
kickerTracking | number | 32 | Letter spacing of the kicker lines |
headlineBaselineY / kickerBaselines | number / [number, number] | 601 / [444, 670] | Baselines of the three lines in comp pixels |
textCenterX | number | 960 | 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 | number | 1920 / 1080 | Coordinate space of the composition |
bandHeight / bandCopies / bandPitch | number | 147.1 / 7 / 750 | Geometry of the traveling distortion bands |
mapStartY / mapEndY / mapTravelFrames | number | 31 / 1560 / 150 | The bands' travel. Deliberately linear — an ease reads as the ripple hesitating inside the word |
waveHeight / waveWidth / waveSpeed | number | 28 / 272 / 1 | The sine ripple on each band's edges |
turbulentAmount / turbulentSize | number | 130 / 163 | Turbulent displacement breaking the wave's regular rhythm |
evolutionPerSecond | number | 50 | How fast the turbulence field pans |
mapBlurRadius / mapBlurIterations | number | 13 / 6 | Blur on the displacement map — without it the map's edges tear the output |
glassDisplacement / maxDisplacementPx | number | 100 / 39 | Displacement strength, and the pixel span it maps to |
glassPasses | number | 3 | 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 |
Inspired by 5 Clean Text Animations by Mapal.