Variable Font Morph
Sweep a variable font's weight and width axes across a line, one character at a time. Install with npx remotion-ui@latest add variable-font-morph.
PrimitivePrimitivesAdvanced
$ npx remotion-ui@latest add variable-font-morphA weight wave travelling through a headline.
import { VariableFontMorph } from "@/remotion/primitives/variable-font-morph";
<VariableFontMorph
text="Weight in motion"
weight={[200, 900]}
width={[85, 115]}
oscillate
periodInFrames={46}
/>One position, every axis
The axis position is a single 0–1 value per character, spent on every requested
axis at once. A real variable face moves wght and wdth together; driving
them from separate clocks makes the type look broken rather than variable.
weight, width and slant are the registered axes. Anything else goes
through axes by four-letter tag:
<VariableFontMorph text="Optical" axes={{ opsz: [14, 96] }} />Oscillate, or arrive
By default the axes ramp from from to to with the entrance and stay there.
oscillate keeps them travelling between the two ends forever, offset per
character by phaseStep so the wave moves along the line.
The static-font fallback
font-variation-settings does nothing on a face without those axes, so the
wght and wdth values are also written to font-weight and font-stretch.
A family shipping discrete weights therefore steps between them instead of
gliding — visibly coarser, but never frozen. Pass a variable fontFamily to
get the real thing.
One 0–1 position drives every axis at once. On a static face the values fall back to `font-weight`/`font-stretch`, which steps rather than glides.
Agent notes
Install first, then import the copied source component locally. AI guide →
@/remotion/primitives/variable-font-morph- Use when: frame-level motion primitives and reusable animation wrappers.
- Customize: text, weight, width, slant, plus copied source for timing, layout, colors, and typography.
- Rule: do not import this component from the
remotion-uinpm package; it is copied into your project.
Usage
import { VariableFontMorph } from "@/remotion/primitives/variable-font-morph";
<VariableFontMorph text="Weight in motion" weight={[200, 900]} oscillate />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | - | The line whose axes are swept. |
| weight | [number, number] | [200, 800] | `wght` axis. Also mirrored onto `font-weight`. |
| width | [number, number] | - | `wdth` axis in percent. Also mirrored onto `font-stretch`. |
| slant | [number, number] | - | `slnt` axis in degrees. Negative leans right, per the spec. |
| axes | Record<string, [number, number]> | - | Any further axes by four-letter tag, e.g. `{ opsz: [14, 96] }`. |
| oscillate | boolean | false | Keep travelling between the two ends instead of landing on `to`. |
| periodInFrames | number | 60 | Frames for one there-and-back when oscillating. |
| phaseStep | number | 0.55 | Radians of offset per character along the wave. |
| staggerInFrames | number | 2 | Frames between one character starting and the next. |
| durationInFrames | number | 20 | Length of one character's ramp. |
| delayInFrames | number | 0 | Frames before the first character starts. |
| fontFamily | string | - | Pass a variable face here — the fallback only steps between static weights. |