RemotionUI

Strikethrough Replace

Strikes out one phrase and puts another in its place, on a three-beat correction timeline.

PrimitiveAdvanced

strikethrough-replace30fps · 960×540
Install
$ npx remotion-ui@latest add strikethrough-replace

Cancels from and puts to in its place: the correction gesture. The whole component is the timing relationship between three beats, and they run in order rather than as one cross-fade.

First the stroke travels the full width of from over strikeDurationInFrames, on an ease-in-out, because a hand accelerates off the first letter and decelerates onto the last. It is drawn once, at full length, so the old phrase is visibly cancelled before anything moves. Then, after holdInFrames, the old phrase lifts by travel and fades on an ease-in. The stroke leaves inside that layer rather than being switched off: a rule that vanishes on its own frame reads as a glitch, while one that travels out with the text it cancelled reads as a single object. Last, replaceDelayInFrames after the stroke lands, the new phrase rises into the same baseline over replaceDurationInFrames.

The defaults open the arrival as the departure passes half: the narrow window where the line is neither empty nor doubled. Opacity leads the move in both directions, gone at 62% of the lift and complete at 55% of the rise, so by the time the new phrase is readable the old one has gone, and while both are faint they are travelling in opposite directions. That matters in both directions: shorten replaceDelayInFrames far enough and you get two half-tone phrases stacked on one line, which is the single state in which neither is readable; push it past holdInFrames + departDurationInFrames and the line goes briefly empty, which reads as a dropout rather than a beat.

Both phrases sit in the same grid cell, so the box is as wide as the longer of the two for the whole shot and a centred line never reflows on the swap.

The stroke is placed from the baseline, in the font's own x-height: strikeHeight is in ex units and defaults to 0.5, which is centred through the lowercase mass. It is an inline box aligned by vertical-align rather than a rule positioned inside the line box, and that is the whole point: top: 50% or an em offset from the top of the em box is thrown off by half-leading the moment lineHeight changes, and is only ever right for the one face it was eyeballed on. Measured at 62px and 28px, and at line heights from 1.0 to 2.2, the stroke's centre lands within 4% of an x-height of the glyph mass centre, at 0.30–0.33em above the baseline.

strikeWeight is the thickness in em, so it tracks the type size, and the stroke overshoots each end of the phrase slightly: a pen does not stop on the glyph. The layer turns about its centre so tilt costs the same deviation at both ends, and the sweep is scaled inside that rotation rather than outside it, since scaling a rotated box stretches it along the frame's axis instead of its own.

The stroke is aligned from the baseline in ex units, so it stays centred through the lowercase mass at any fontSize or lineHeight, and it departs inside the old phrase's layer rather than switching off. Both phrases share one grid cell, so the box holds the width of the longer one and a centred line never reflows on the swap.

Agent notes

Install first, then import the copied source component locally. AI guide →

Import
@/remotion/primitives/strikethrough-replace
  • Use when: frame-level motion primitives and reusable animation wrappers.
  • Customize: from, to, delayInFrames, strikeDurationInFrames, plus copied source for timing, layout, colors, and typography.
  • Rule: do not import this component from the remotion-ui npm package; it is copied into your project.

Usage

Example
import { StrikethroughReplace } from "@/remotion/primitives/strikethrough-replace"; <StrikethroughReplace from="Motion you rent" to="Motion you own" delayInFrames={10} />

API Reference

PropTypeDescription
from*stringPhrase that gets struck out.
to*stringPhrase that takes its place.
delayInFramesnumberFrames before the stroke starts travelling.
strikeDurationInFramesnumberFrames the stroke takes to cross the full width of `from`.
holdInFramesnumberBeat held on the struck-out phrase after the stroke lands, before it leaves.
departDurationInFramesnumberFrames the old phrase takes to lift away. Its opacity is gone at 62% of it.
replaceDelayInFramesnumberFrames after the stroke lands before the new phrase starts arriving. Past `holdInFrames + departDurationInFrames` the line goes briefly empty; well below it the two phrases cross-fade.
replaceDurationInFramesnumberFrames the new phrase takes to rise into place.
travelnumberVertical handoff distance in em: the old lifts by it, the new rises from it.
strikeWeightnumberStroke thickness in em, so it tracks the type size.
strikeHeightnumberStroke height above the baseline in `ex`, units of the font's own x-height. 0.5 is centred through the lowercase mass.
tiltnumberStroke angle in degrees off level: a hand does not rule it flat.
colorstringText colour.
strikeColorstringStroke colour.
replaceColorstringInk of the replacement. Defaults to `color`.
fontSizenumberText size in pixels.
fontWeightnumberText weight.
fontFamilystringFont family for both phrases.
textAlign"left" | "center" | "right"Alignment of both phrases inside the shared box.
styleCSSPropertiesStyles merged onto the wrapper span.

On this page