Text that moves like air

Gust animates changing React text one character at a time. Shared prefixes stay put while old glyphs lift out and new ones settle in, and the width eases to fit. It runs on the Web Animations API, with no animation library.

Install

npm i @maniktherana/gust

Usage

Your component owns the value and decides when it changes. Gust animates from the previous string to the next one.

import { useEffect, useState } from "react";
import { Gust } from "@maniktherana/gust";
import "@maniktherana/gust/styles.css";

const messages = ["Queued", "Building", "Live"];

export function Status() {
  const [index, setIndex] = useState(0);

  useEffect(() => {
    const timer = window.setInterval(() => {
      setIndex((current) => (current + 1) % messages.length);
    }, 2000);

    return () => window.clearInterval(timer);
  }, []);

  return <Gust value={messages[index] ?? ""} />;
}

Import the stylesheet once. It holds Gust's structural layout and nothing else.

Props

The defaults suit display text. Each panel runs the real component, and its graph is drawn from the same keyframes Gust plays.

Basics

What to show and how it looks.

value

string

The text to show. Your component decides what the text is and when it changes; Gust animates each change. Leading and trailing spaces are trimmed.

Default required

const [label, setLabel] = useState("Save");

<Gust value={label} />
Save

className

string

Classes for the root span. Gust takes its font, size and color from here or from the surrounding text. Other span attributes, such as id, style and aria-*, pass through too.

Default —

<Gust value={count} />
1,111

Timing

Every changed character runs its own animation, and leaving characters animate at the same time as arriving ones.

duration

number

How long each arriving character takes to settle, in milliseconds.

Default 440

<Gust
  value={label}
  duration={440}
/>
Calm
Duration

exitDuration

number

How long each leaving character takes to disappear, in milliseconds.

Default 400

<Gust
  value={label}
  exitDuration={400}
/>
Fade
Exit duration

stagger

number

Extra delay before each next character starts, in milliseconds. The dots pulse with the arriving characters.

Default 20

<Gust
  value={label}
  stagger={20}
/>
When each character starts
Calm
Stagger

Direction

Which way characters travel.

enterAngle, exitAngle

number

Travel angles in screen degrees: 0 is right, 90 is down and −90 is up. Arriving characters travel along enterAngle, so they come from the opposite side. Drag anywhere on the ring to aim the nearest arrow.

Default -90

<Gust
  value={label}
  enterAngle={-90}
  exitAngle={-90}
/>
Directions
Breeze
Enter-90°
Exit-90°

down

boolean

Sends both directions down. Set it from your data, such as down={price < previous}, so falling values fall. Explicit angles take precedence.

Default false

<Gust value={price} />
$24.80

Entrance

Arriving characters start away from their spot, pass it, and settle. Distances use 100 = 1em, so they scale with the text.

entranceHeight

number

How far from its resting spot a character starts. The dot is where it starts.

Default 90

<Gust
  value={label}
  entranceHeight={90}
/>
Position while arriving
Rise
Height

entranceOvershoot

number

How far a character overshoots its spot before settling. The dot is the top of the overshoot; 0 removes it.

Default 12

<Gust
  value={label}
  entranceOvershoot={12}
/>
Position while arriving
Rise
Overshoot

entranceScale

number

A character's scale during its arrival, from 0 to 2.

Default 1.1

<Gust
  value={label}
  entranceScale={1.1}
/>
Size while arriving
Rise
Peak scale

entranceBlur

number

Blur when a character starts arriving, in pixels. It sharpens as it settles. The default is 0.

Default 0

<Gust
  value={label}
  entranceBlur={0}
/>
Blur while arriving
Rise
Blur

Exit

Leaving characters travel, shrink, blur and fade together. Most of the movement happens right away.

exitHeight

number

How far a leaving character travels before it disappears. 100 equals 1em.

Default 90

<Gust
  value={label}
  exitHeight={90}
/>
Position while leaving
Fade
Travel

exitScale

number

How large a leaving character is when it disappears, from 0 to 1.5.

Default 0.4

<Gust
  value={label}
  exitScale={0.4}
/>
Size while leaving
Fade
End scale

exitBlur

number

How blurred a leaving character is when it disappears, in pixels. Blur does not grow with font size: 4px suits display text, about 1px suits 12–14px text.

Default 4

<Gust
  value={label}
  exitBlur={4}
/>
Blur while leaving
Fade
Blur

Effects

Switches for parts of the motion.

blur

boolean

Enables entrance and exit blur. Each has its own amount; entrance blur defaults to 0.

Default true

<Gust
  value={label}
  blur
/>
Fade

scale

boolean

Scales characters as they arrive and leave. Turn it off to keep every character at its normal size.

Default true

<Gust
  value={label}
  scale
/>
Rise

preservePrefix

boolean

Keeps matching leading characters still, so only what changed moves. The boxes show each character's role as the real transition runs.

Default true

<Gust value={status} />
What each character does
Uploading