FasterMotion
API ReferenceText

TextEffects

Advanced scroll-driven text effects including warp, morph, scramble, glitch, 3D flip, and rainbow animations

TextEffects provides ready-to-use advanced typography effects optimized for scroll-driven animations. All effects work with split text elements (from TextSplitter) and progress values (0-1).

Basic Usage

import { TextSplitter, TextEffects } from 'faster-motion';

// 1. Split text into characters
// IMPORTANT: Use className: 'ft' so TextEffects can find .ft-char elements
const result = TextSplitter.split('#title', {
  type: 'chars',
  className: 'ft'  // Required for TextEffects
});

// 2. Apply effect with scroll progress (0-1)
window.addEventListener('scroll', () => {
  const progress = Math.min(1, window.scrollY / 500);

  TextEffects.warp(result.parent, progress, {
    type: 'sine',
    amplitude: 20
  });
});

Important: When using TextEffects with TextSplitter, you must pass className: 'ft' to TextSplitter. This creates elements with .ft-char class that TextEffects methods look for.

Try it: Warp Effect

const result = TextSplitter.split('#title', { type: 'chars', className: 'ft' });
TextEffects.warp(result.parent, progress, { type: 'sine', amplitude: 20 });

TextEffects.warp()

Warp text along a curve based on progress value.

Syntax

TextEffects.warp(
  element: HTMLElement,
  progress: number,
  options?: {
    amplitude?: number;
    frequency?: number;
    type?: 'sine' | 'wave' | 'arc' | 'spiral';
  }
): void

Parameters

  • element - HTMLElement - Parent element containing .ft-split-char children
  • progress - number - Animation progress (0-1)
  • options - object (optional) - Configuration options
    • amplitude - Wave height in pixels (default: 20)
    • frequency - Number of waves (default: 1)
    • type - Warp type: 'sine', 'wave', 'arc', 'spiral' (default: 'sine')

Warp Types

TypeDescription
sineSmooth sine wave oscillation
waveScrolling wave that moves with progress
arcArc/rainbow curve shape
spiralSpiral outward from center

Example

// Sine wave
TextEffects.warp(element, progress, {
  type: 'sine',
  amplitude: 20,
  frequency: 1
});

// Arc curve
TextEffects.warp(element, progress, {
  type: 'arc',
  amplitude: 50
});

// Spiral
TextEffects.warp(element, progress, {
  type: 'spiral',
  amplitude: 30,
  frequency: 2
});

Try it: All Warp Types

// Try: 'sine', 'wave', 'arc', 'spiral'
TextEffects.warp(element, progress, { type: 'sine', amplitude: 25 });

TextEffects.morph()

Morph text from one transform state to another with staggered timing.

Syntax

TextEffects.morph(
  element: HTMLElement,
  progress: number,
  from: TextTransform,
  to: TextTransform
): void

Parameters

  • element - HTMLElement - Parent element with .ft-split-char children
  • progress - number - Animation progress (0-1)
  • from - TextTransform - Starting transform state
  • to - TextTransform - Ending transform state

Example

TextEffects.morph(element, progress,
  // From state
  {
    x: -100,
    y: 50,
    scale: 0,
    rotation: -90,
    opacity: 0,
    color: '#ff0000'
  },
  // To state
  {
    x: 0,
    y: 0,
    scale: 1,
    rotation: 0,
    opacity: 1,
    color: '#00ff00'
  }
);

Try it: Morph Effect

TextEffects.morph(element, progress,
  { y: 50, scale: 0, rotation: -90, opacity: 0 },
  { y: 0, scale: 1, rotation: 0, opacity: 1 }
);

TextEffects.typeVariable()

Create a variable-speed typing effect where characters appear at different speeds.

Syntax

TextEffects.typeVariable(
  element: HTMLElement,
  progress: number,
  options?: {
    minSpeed?: number;
    maxSpeed?: number;
    acceleration?: 'linear' | 'ease' | 'bounce';
  }
): void

Parameters

  • element - HTMLElement - Parent element with .ft-split-char children
  • progress - number - Animation progress (0-1)
  • options - object (optional)
    • minSpeed - Minimum speed multiplier (default: 0.5)
    • maxSpeed - Maximum speed multiplier (default: 2)
    • acceleration - Speed curve type (default: 'ease')

Acceleration Types

TypeDescription
linearConstant speed increase
easeSpeeds up then slows down
bounceBouncy speed variations

Example

// Eased typing (speeds up, then slows down)
TextEffects.typeVariable(element, progress, {
  minSpeed: 0.3,
  maxSpeed: 3,
  acceleration: 'ease'
});

// Bouncy typing
TextEffects.typeVariable(element, progress, {
  acceleration: 'bounce'
});

Try it: TypeVariable Effect

TextEffects.typeVariable(element, progress, {
  minSpeed: 0.3,
  maxSpeed: 2.5,
  acceleration: 'ease'
});

TextEffects.scramble()

Scramble text reveal effect - characters show as random symbols before revealing.

Syntax

TextEffects.scramble(
  element: HTMLElement,
  progress: number,
  options?: {
    characters?: string;
    speed?: number;
  }
): void

Parameters

  • element - HTMLElement - Text element (works on unsplit text too)
  • progress - number - Animation progress (0-1)
  • options - object (optional)
    • characters - Characters to use for scrambling (default: alphanumeric + symbols)
    • speed - Scramble speed (default: 10)

Example

// Default scramble
TextEffects.scramble(element, progress);

// Binary scramble (Matrix-style)
TextEffects.scramble(element, progress, {
  characters: '01',
  speed: 20
});

// Letters only
TextEffects.scramble(element, progress, {
  characters: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
});

Try it: Scramble Effect

TextEffects.scramble(element, progress, {
  characters: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
  speed: 15
});

TextEffects.glitch()

Create a digital glitch distortion effect with chromatic aberration.

Syntax

TextEffects.glitch(
  element: HTMLElement,
  progress: number,
  intensity?: number
): void

Parameters

  • element - HTMLElement - Text element
  • progress - number - Animation progress (0-1, kept for API consistency)
  • intensity - number (optional) - Glitch intensity from 0-1 (default: 1)

Effect Details

The glitch effect applies:

  • Random offset and skew transforms
  • RGB chromatic aberration (red/cyan text shadows)
  • Auto-resets after 50-150ms

Example

// Call repeatedly for glitch effect
setInterval(() => {
  TextEffects.glitch(element, 0, 0.8);  // 80% intensity
}, 100);

// High intensity
TextEffects.glitch(element, 0, 1);

// Subtle glitch
TextEffects.glitch(element, 0, 0.2);

Try it: Glitch Effect

// Glitch with 80% intensity
TextEffects.glitch(element, 0, 0.8);

TextEffects.flip3D()

3D flip animation with perspective transforms.

Syntax

TextEffects.flip3D(
  element: HTMLElement,
  progress: number,
  axis?: 'x' | 'y' | 'both'
): void

Parameters

  • element - HTMLElement - Parent element with .ft-split-char children
  • progress - number - Animation progress (0-1)
  • axis - 'x' | 'y' | 'both' (optional) - Flip axis (default: 'y')

Axis Options

AxisDescription
xVertical flip (rotateX)
yHorizontal flip (rotateY)
bothFlip on both axes

Example

// Horizontal flip (card-flip style)
TextEffects.flip3D(element, progress, 'y');

// Vertical flip
TextEffects.flip3D(element, progress, 'x');

// Both axes
TextEffects.flip3D(element, progress, 'both');

Try it: 3D Flip Effect

TextEffects.flip3D(element, progress, 'y');

TextEffects.rainbow()

Animated rainbow color effect cycling through the hue spectrum.

Syntax

TextEffects.rainbow(
  element: HTMLElement,
  progress: number,
  speed?: number
): void

Parameters

  • element - HTMLElement - Parent element with .ft-split-char children
  • progress - number - Animation progress (0-1)
  • speed - number (optional) - Animation speed multiplier (default: 1)

Example

// Standard rainbow
TextEffects.rainbow(element, progress);

// Fast rainbow (2x speed)
TextEffects.rainbow(element, progress, 2);

// Slow rainbow (0.5x speed)
TextEffects.rainbow(element, progress, 0.5);

Try it: Rainbow Effect

TextEffects.rainbow(element, progress, 1.5);

TextEffects.alongPath()

Move text characters along an SVG path.

Syntax

TextEffects.alongPath(
  element: HTMLElement,
  progress: number,
  pathData: string
): void

Parameters

  • element - HTMLElement - Parent element with .ft-split-char children
  • progress - number - Animation progress (0-1)
  • pathData - string - SVG path data (d attribute)

Example

// Simple curve
const pathData = 'M0,50 Q100,0 200,50';
TextEffects.alongPath(element, progress, pathData);

// Complex path
const complexPath = 'M10,90 Q90,90 90,45 Q90,10 50,10 Q10,10 10,40';
TextEffects.alongPath(element, progress, complexPath);

Try it: Path Effect

const pathData = 'M0,100 Q150,0 300,100';
TextEffects.alongPath(element, progress, pathData);

TextTransform Interface

All transform properties supported by morph() and internal methods:

interface TextTransform {
  // Position & Scale
  x?: number;
  y?: number;
  z?: number;
  scale?: number;
  scaleX?: number;
  scaleY?: number;

  // Rotation (degrees)
  rotation?: number;
  rotationX?: number;
  rotationY?: number;
  rotationZ?: number;

  // Skew (degrees)
  skewX?: number;
  skewY?: number;

  // Typography
  letterSpacing?: number;
  wordSpacing?: number;
  lineHeight?: number;
  fontSize?: number;
  fontWeight?: number;

  // Colors
  color?: string;
  backgroundColor?: string;
  borderColor?: string;

  // Effects
  opacity?: number;
  blur?: number;
  brightness?: number;
  contrast?: number;
  grayscale?: number;
  hueRotate?: number;
  saturate?: number;
  sepia?: number;

  // Text effects
  strokeWidth?: number;
  strokeColor?: string;
  shadowX?: number;
  shadowY?: number;
  shadowBlur?: number;
  shadowColor?: string;

  // Perspective
  perspective?: number;
  perspectiveOrigin?: string;
  transformOrigin?: string;
}

Scroll Integration

TextEffects are designed to work with scroll progress. Here's how to integrate with scroll:

Using Window Scroll

const result = TextSplitter.split('#title', { type: 'chars' });

window.addEventListener('scroll', () => {
  const progress = Math.min(1, window.scrollY / 500);
  TextEffects.warp(result.parent, progress, { type: 'wave' });
});

Using requestAnimationFrame

const result = TextSplitter.split('#title', { type: 'chars' });

function animate() {
  const progress = Math.min(1, window.scrollY / 500);
  TextEffects.rainbow(result.parent, progress, 1.5);
  requestAnimationFrame(animate);
}
animate();

Combining Effects

const result = TextSplitter.split('#title', { type: 'chars' });

window.addEventListener('scroll', () => {
  const progress = Math.min(1, window.scrollY / 500);

  // Apply multiple effects
  TextEffects.morph(result.parent, progress,
    { scale: 0, rotation: -90 },
    { scale: 1, rotation: 0 }
  );
  TextEffects.rainbow(result.parent, progress, 0.5);
});

Performance Tips

Use RAF for Smooth Updates

window.addEventListener('scroll', () => {
  requestAnimationFrame(() => {
    TextEffects.warp(element, progress, { type: 'sine' });
  });
});

Cache Path Data

// Good: Define path outside handler
const pathData = 'M10,80 Q95,10 180,80';

window.addEventListener('scroll', () => {
  TextEffects.alongPath(element, progress, pathData);
});

// Bad: Don't recreate path each frame
window.addEventListener('scroll', () => {
  const pathData = generatePath();  // Expensive!
  TextEffects.alongPath(element, progress, pathData);
});

Limit Effect Combinations

// Good: 1-2 effects
TextEffects.morph(element, progress, from, to);
TextEffects.rainbow(element, progress);

// Bad: Too many effects
TextEffects.warp(element, progress);
TextEffects.morph(element, progress, from, to);
TextEffects.flip3D(element, progress);
TextEffects.rainbow(element, progress);  // Overkill!

Examples

See Also

On this page