Gooey Morph
Bars fly in Tetris-style, land as a row, and melt into a word through a gooey blur-and-threshold morph
$ pnpm dlx shadcn@latest add @remocn/gooey-morphUsage
// src/Root.tsx
import { Composition } from "remotion";
import { GooeyMorph } from "@/components/remocn/gooey-morph";
const GooeyMorphScene = () => (
<GooeyMorph word="HELLO" fontFamily="'Bodoni Moda', Georgia, serif" />
);
export const RemotionRoot = () => (
<Composition
id="GooeyMorph"
component={GooeyMorphScene}
durationInFrames={120}
fps={30}
width={1920}
height={1080}
/>
);The melt works by blurring the alpha channel and pushing it through a near-vertical threshold: where two shapes sit close, their blurred edges add up, cross the threshold, and paint a solid neck between them. Everything that should fuse lives inside the component's single filtered group — nearby elements outside it never join the goo.
Props21
| Prop | Type | Default |
|---|---|---|
| word | string"HELLO" The word the bars melt into | |
| fill | string"#ffffff" Fill color of the bars and the word | |
| fontFamily | string"sans-serif" Font family of the word — heavy display faces melt best | |
| fontSize | number237 Font size in comp pixels | |
| tracking | number0 Letter spacing of the word | |
| wordCenterX / wordBaselineY | number961.4 / 601.3 Horizontal center and baseline of the word in comp pixels | |
| width / height | number1920 / 1080 Coordinate space of the composition | |
| barWidth / barHeight | number213 / 181 Size of each bar in comp pixels | |
| barStartPositions | [number, number][]4 scattered points Where each bar starts, as `[x, y]` centers | |
| barRestPositions | [number, number][]4 points in a row Where each bar lands before the melt | |
| barEntryFrames | number[][8, 0, 4, 13] Per-bar entry frames — deliberately non-monotonic so the build reads as Tetris, not a wave | |
| barTravelFrames | number30 Length of one bar's L-shaped move: horizontal into the column, then vertical into the row | |
| morphStartFrame / morphPeakFrame / morphEndFrame | number50 / 63 / 76 The melt window. Blur and displacement are zero outside it | |
| blurRadius | number6 Peak goo blur radius | |
| blurIterations | number6 Box blur passes folded into the equivalent Gaussian sigma | |
| alphaInputBlack / alphaInputWhite | number0.4588 / 0.5098 Alpha threshold range — the narrower, the harder the goo edge | |
| displaceAmount | number20 Peak turbulent displacement of the goo edge, in pixels | |
| displaceSize | number19 Feature size of the displacement noise | |
| displaceComplexity | number1 Noise octaves | |
| displaceEvolutionPerSecond | number50 How fast the noise field pans, per second | |
| className | string— Optional className passed to the wrapper | |
- wordstring
The word the bars melt into
Default
"HELLO" - fillstring
Fill color of the bars and the word
Default
"#ffffff" - fontFamilystring
Font family of the word — heavy display faces melt best
Default
"sans-serif" - fontSizenumber
Font size in comp pixels
Default
237 - trackingnumber
Letter spacing of the word
Default
0 - wordCenterX / wordBaselineYnumber
Horizontal center and baseline of the word in comp pixels
Default
961.4 / 601.3 - width / heightnumber
Coordinate space of the composition
Default
1920 / 1080 - barWidth / barHeightnumber
Size of each bar in comp pixels
Default
213 / 181 - barStartPositions[number, number][]
Where each bar starts, as `[x, y]` centers
Default
4 scattered points - barRestPositions[number, number][]
Where each bar lands before the melt
Default
4 points in a row - barEntryFramesnumber[]
Per-bar entry frames — deliberately non-monotonic so the build reads as Tetris, not a wave
Default
[8, 0, 4, 13] - barTravelFramesnumber
Length of one bar's L-shaped move: horizontal into the column, then vertical into the row
Default
30 - morphStartFrame / morphPeakFrame / morphEndFramenumber
The melt window. Blur and displacement are zero outside it
Default
50 / 63 / 76 - blurRadiusnumber
Peak goo blur radius
Default
6 - blurIterationsnumber
Box blur passes folded into the equivalent Gaussian sigma
Default
6 - alphaInputBlack / alphaInputWhitenumber
Alpha threshold range — the narrower, the harder the goo edge
Default
0.4588 / 0.5098 - displaceAmountnumber
Peak turbulent displacement of the goo edge, in pixels
Default
20 - displaceSizenumber
Feature size of the displacement noise
Default
19 - displaceComplexitynumber
Noise octaves
Default
1 - displaceEvolutionPerSecondnumber
How fast the noise field pans, per second
Default
50 - classNamestring
Optional className passed to the wrapper
Inspired by 5 Clean Text Animations by Mapal.