kinetic_text 0.2.0 copy "kinetic_text: ^0.2.0" to clipboard
kinetic_text: ^0.2.0 copied to clipboard

Kinetic typography for Flutter — per-letter, per-word and per-line text motion from ONE shaped paragraph: staggered reveals, sheen and shimmer sweeps, gradient and rainbow ink on any span, sparkle, ma [...]

kinetic_text #

Kinetic typography for Flutter — per-letter, per-word and per-line text motion from ONE shaped paragraph: staggered reveals, sheen and shimmer sweeps, gradient and rainbow ink on any span, sparkle, marker highlight, draw-on underline, typewriter, a text morph that rewrites a label in place, and a ticker whose digits turn like an odometer.

  • 🪶 Zero dependencies. Nothing beyond the Flutter SDK. No shaders to ship, no Rive, no Lottie.
  • 🔤 Every script stays joined. The text is laid out once as a whole, and each letter is re-drawn from that one layout. Arabic and Kurdish keep their cursive joins, ligatures keep their shape, bidi keeps its order — a per-letter effect never splits the string into separate Texts.
  • 🎯 Effects compose. A cascade, a shimmer and a rainbow on the same word all write into one pose per letter and paint in one layer. Stagger in reading order, reverse, from the centre, from the edges, or scattered.
  • ♿ Reduced motion is a first-class path. One-shots resolve to their end state, loops go quiet, fills and markers stay.
  • 📐 Lays out like Text. Reads the ambient DefaultTextStyle, Directionality, text scale and bold-text setting; wraps to its constraints; reports intrinsic sizes and a text baseline (so it sits in a baseline-aligned Row or an IntrinsicWidth like any text); speaks its plain text to assistive technology.
  • 🧊 Cheap when still. A finished reveal is one plain paint. Effects compare by value, so a parent rebuild never re-lays the paragraph out.

By Armanic Studio. Sibling of iconic_morph.

Install #

dependencies:
  kinetic_text: ^0.2.0
import 'package:kinetic_text/kinetic_text.dart';

Quick start #

// A headline cascading in, word by word.
KineticText(
  'Fresh harvest, every morning',
  style: headline,
  unit: TextUnit.word,
  effects: const [Rise(distance: 10)],
);

// A rainbow on one word, a marker under another — the rest plain.
KineticText.rich([
  const TextRun('Pay '),
  TextRun('12,000', effects: [Highlight(color: tint), Underline(color: accent)]),
  const TextRun(' before '),
  TextRun('Friday', effects: [GradientInk.rainbow(seed: accent, flow: const Duration(seconds: 4))]),
], style: body);

// A button label that shimmers while a payment clears.
KineticText('Pay now', style: label, effects: const [Shimmer()]);

// A figure whose digits turn like an odometer — retarget it mid-roll and
// every wheel just redirects.
TickerText(formatted, style: figure);

// A value that rewrites itself — the changed letters roll on the same drum.
TextMorph('$amount', style: figure, morph: const MorphStyle.roll());

// A title that dissolves into the next one under a sheen.
TextMorph(title, style: headline, morph: MorphStyle.sheen(sheen: [accent]));

Effects #

Kind Effect What it does
Reveal Rise Cascade in from below (or any side), Rise.fade, Rise.pop
Reveal Glint Grow + fade in under a travelling sheen
Reveal Blur Resolve out of a blur (word/line units)
Reveal Typewriter Hard-cut, one unit at a time, optional blinking cursor
Reveal Bounce Drop in from above, land with one soft overshoot and squash
Reveal Squeeze Wide and flat, stretching upright as it lands (a stamp)
Reveal Outline A stroke sweeps round each letter, then the fill rises inside it
Reveal Scramble Random glyphs lock onto the real ones in order (the terminal)
Loop Shimmer A light band sweeps in reading order, letters lift under it
Loop Sparkle A few small glints twinkle on the glyphs
Loop Float A tiny slow drift, each letter a beat behind
Loop Wave A rounded ripple runs through the line
Loop Pulse A slow glow breathes through the ink, no motion
Loop Spotlight The shimmer's band as light: the line sits dim, letters under it are full ink, optional focus outline
Loop Flicker One or two letters stutter dark and recover (a loose sign)
Ink GradientInk Gradient fill on a span, rainbow, optional flow
Ink Tint Flat recolour of a span, no relayout
Decor Highlight A rounded marker sweeps in behind a span
Decor Underline A stroke draws on under (or strike through) a span

Reveals play over KineticText.duration on mount, on a replayKey change, or from a KineticController; pass progress: to drive them from a scroll or a parent animation instead. Loops run on their own clock while mounted.

Morph #

TextMorph diffs the two texts by unit: the shared prefix and suffix stay (gliding to their new place when the width changes), the differing middle leaves and arrives in the chosen style — sheen, slide, roll, fold (split-flap), wipe or crossfade — and the box's width eases between the two.

roll turns the changed letters over a drum: the old glyph curves away (foreshortening and dimming as it leaves the drum's window), the new one curves in from the other side on the same clock, up when the number in the text grew and down when it shrank. Nothing is clipped, so no sliver of the leaving glyph is ever left behind. Because it works on the shaped paragraph, it keeps cursive scripts joined.

Ticker #

TickerText is the odometer proper — the SwiftUI numericText feel. Each character sits in a slot keyed from the right (or TickerAnchor.left for a label) and owns a continuous wheel that chases its target every frame, not a 0→1 timeline that restarts on each change. Set a new value mid-roll and every wheel redirects from where it is; a digit that has to go from 2 to 7 passes 3, 4, 5 and 6 on the way, the shorter way round the 0–9 ring. The width eases as characters come and go; new slots fade in, dropped slots fade out. Pass a formatted string and a tabular-figure style:

TickerText('1,250,000', style: figure.copyWith(fontFeatures: const [FontFeature.tabularFigures()]));

Characters are laid out one per slot, so use it for figures and Latin labels; for cursive scripts reach for TextMorph with MorphStyle.roll, which turns the same drum from one shaped paragraph.

Your own effect #

class Wobble extends TextEffect {
  const Wobble();
  @override
  bool get continuous => true;
  @override
  void apply(TextFrame frame, UnitSlice slice) {
    for (var k = 0; k < slice.length; k++) {
      frame.pose(slice.units[k]).dy += 2 * sin(frame.time * 4 + k);
    }
  }
}

A TextFrame gives you the ShapedText (every unit's rect, line and range), the one-shot progress, the loop time, and lets you add ink passes and decor painters behind or over the glyphs.

Notes on cost #

  • Shaping happens once per text/style/width — never on a rebuild that only constructs a fresh effect list; a frame at rest with no ink pass is one plain paint.
  • A moving letter is one clipped re-draw of the paragraph; a fading or blurred one costs a small layer. Staggers keep the moving set small.
  • Blur on every letter of a paragraph is a layer per letter — use word or line units.
  • Spotlight and Pulse are one ink pass per frame and no layer per letter; Flicker poses only the letters that flicker.
  • Outline lays the paragraph out a second time with a stroked ink — once, cached on the shaped text. Scramble sets its stand-in glyphs one at a time, so keep it to Latin text and figures.
  • Horizontal travel suits word units; letters have no slack to slide.

Names #

The effect classes are short on purpose — Rise, Shimmer, Blur, Float, Tint — because they read as a list: effects: const [Rise(), Shimmer()]. If another library in your file exports one of these names (package:shimmer has a Shimmer), hide it on one side:

import 'package:kinetic_text/kinetic_text.dart' hide Shimmer;

Nothing else in the barrel collides with Flutter's own exports.

License #

MIT — see LICENSE.

0
likes
150
points
864
downloads

Documentation

API reference

Publisher

verified publisherarmanic.studio

Weekly Downloads

Kinetic typography for Flutter — per-letter, per-word and per-line text motion from ONE shaped paragraph: staggered reveals, sheen and shimmer sweeps, gradient and rainbow ink on any span, sparkle, marker highlight, draw-on underline, typewriter, and a text morph that rewrites a label in place. Every script (Arabic, Kurdish, ligatures, bidi) stays correctly joined, because the text is shaped once and the glyph clusters are re-drawn from that one layout. No shaders to ship, ZERO external dependencies.

Repository (GitHub)
View/report issues
Contributing

Topics

#text #animation #typography #motion #shimmer

License

MIT (license)

Dependencies

flutter

More

Packages that depend on kinetic_text