Skip to the content

Ink reveal

A block of text that is already entirely on the page, pale, and takes its ink as the page is scrolled through it.

Become a member to unlock the full effect today.

Join now

Already a member? Sign in

Documentation

  1. Copy to Webflow

    Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed.

  2. Add custom CSS

    The colour of the text belongs to the page: the ink is the page's own colour, and the pale state is a share of it, so the effect works on any ground. A block near the end of the page needs no room under it: its run ends when the page stops scrolling, so the last word always takes ink.
  3. Add custom JS

  4. Use it on your own elements

    Custom attribute
    Select the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.
    Custom attributeWhat it does
    data-ink-reveal Marks the block whose words take ink. It takes no value: leave the value field empty. It goes on the element that carries the words: a paragraph, a heading, or a box holding several paragraphs, which then fill one after the other as a single run.
    Settings
    Every setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.
    AttributeDefaultWhat it is
    data-ink-reveal-rest 0.12 How much ink a word holds before its turn, as a share of the page's own text colour.
    data-ink-reveal-softness 0.14 How much of the run one word takes to fill, which is how many words are filling at the same time.
    data-ink-reveal-from 0.78 Where the run starts, as a share of the window height measured from the top: 1 is the bottom edge.
    data-ink-reveal-to 0.34 Where the run ends, as a share of the window height: the run is over when the block's bottom reaches that line.
    data-ink-reveal-unit word What takes ink at a time. Options: word (the default, and the one that reads), char.
    data-ink-reveal-rewind true Whether the ink drains again when the page is scrolled back up. Options: true, false (the ink stays where it got to).
    data-ink-reveal-ease none The shape of one word going from pale to full. Options: any GSAP ease name, none (even with the scroll), power1.out, power2.inOut, and so on.
    data-ink-reveal-debug false Writes the state, the unit count and the progress in data-ink-reveal-debug-* attributes. Options: false, true.

What it does

Ink reveal is a text animation for Webflow and vanilla JavaScript, built on GSAP 3 and ScrollTrigger. Also called text fill on scroll, word by word text reveal on scroll or scroll text color change.

A block of text that is already entirely on the page, pale, and takes its ink as the page is scrolled through it. Word by word, in reading order, left to right and top to bottom, each word goes from a faint tint of the page's own text colour to full ink, and the front of the fill follows the scroll position exactly: scroll back up and the ink drains again. Nothing appears and nothing moves; the text fills. The words are never hidden, never made transparent and never taken out of the document: the engine wraps each word in a bare inline span, leaves the spaces between them as they were, and animates one number per word that the stylesheet turns into an opacity, so reading order, tab order, selection, text search and screen readers are the ones the markup already had. Distinct from pixel-reveal, which writes text in block by block when it arrives on screen: here the text is present from the first paint and only its ink travels. Pattern type scroll fill text, ink fill, text opacity on scroll, reading highlight, word by word fill.

Updated

Questions

Add the custom attribute data-ink-reveal, with an empty value, to the paragraph, heading or box that carries the words, under Custom attributes in the Settings panel. One mark on a box of three paragraphs gives one run across the three, and one mark per paragraph gives three runs.

No. It uses GSAP 3.12.5 and its ScrollTrigger plugin, loaded from the CDN, and no other plugin: the engine splits the words itself. On a page where the libraries never load, the text stays at full ink and no word is dimmed.

data-ink-reveal-rest is the ink a waiting word holds, 0.12 by default: lower and the waiting words nearly vanish, higher and they are almost as dark as the inked ones. data-ink-reveal-softness, 0.14 by default, is how many words fill at the same time: lower gives a hard front of one word at a time, higher a long gradient of half inked words.

It starts when the top of the block reaches from, 0.78 of the window height measured from the top, and is over when the bottom of the block reaches to, 0.34. Scrolling back up drains the ink again unless you set data-ink-reveal-rewind="false". A block at the very bottom of the page fills faster, because its run is cut to the last scroll position the page has.

Yes. The words are never hidden or made transparent: each one is wrapped in a bare inline span and the spaces stay real text nodes, so the text is selectable, found by the browser's search and read as a sentence. Under prefers-reduced-motion: reduce the text is at full ink immediately and the words are not split at all.