Skip to main content
skill CX Codex

staggered-word-reveal — Claude Code skill

Builds word-by-word text reveals as content enters the viewport. Use it for short headlines, section intros, quotes, and hero copy.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add MengTo/Skills --skill staggered-word-reveal -a claude-code
Open on GitHub

What staggered-word-reveal does

This skill defines a word-by-word reveal for text that enters the viewport. Each word starts transparent and shifted vertically, then transitions into place with a 0.06s–0.08s delay between words.

Its script splits text without innerHTML, preserves whitespace, and exposes the original sentence to screen readers through aria-label. IntersectionObserver triggers the reveal once, then stops observing the element. Text stays visible when JavaScript is disabled, while reduced-motion settings show readable static content.

For React, Vue, and Svelte, run the splitter after mount and clean up observers on route changes. This is a poor fit for long paragraphs or text containing links, buttons, or meaningful inline markup.

What it helps with

  • reveal headline words in sequence
  • trigger text motion when a block enters the viewport
  • keep content readable without JavaScript
  • respect reduced-motion preferences

Example prompts for the agent

  • Add a word-by-word reveal to this h1 with [data-word-reveal].
  • Animate this short quote with IntersectionObserver and prevent replay after scrolling.
  • Set up word-reveal and word-reveal__word styles with reduced-motion handling.

How to install staggered-word-reveal

1Skills CLI (Vercel)

npx skills add MengTo/Skills --skill staggered-word-reveal -a claude-code

2Manually: put the files in place

~/.claude/skills/staggered-word-reveal/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/staggered-word-reveal/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about staggered-word-reveal

How do I install staggered-word-reveal in Claude Code?

Run npx skills add MengTo/Skills --skill staggered-word-reveal -a claude-code twice. The skill file is placed at ~/.claude/skills/staggered-word-reveal/SKILL.md.

What does staggered-word-reveal do?

It helps create restrained word-by-word text reveals for short copy. The effect runs when the element enters the viewport and does not replay on later scrolling.

What happens when reduced motion is enabled?

With prefers-reduced-motion: reduce, words remain visible without transitions or movement. The same static treatment is used when IntersectionObserver is unavailable.

Source text

SKILL.md · MIT
---
name: staggered-word-reveal
description: Create subtle editorial word-by-word text reveal animations where each word fades and rises into place once it enters the viewport. Use for premium portfolio headlines, hero copy, section intros, and short marketing text that needs a cinematic staggered reveal with IntersectionObserver or in-view detection.
---

# Staggered Word Reveal

## Use When
- A short headline, intro, or pull quote should reveal word by word.
- The motion should feel editorial, premium, and restrained.
- The reveal should trigger only once when the text enters the viewport.
- The project does not need heavy GSAP SplitText behavior.

## Motion Defaults
- Initial state: `opacity: 0`, `transform: translateY(20px)`.
- Final state: `opacity: 1`, `transform: translateY(0)`.
- Duration: `0.8s`.
- Ease: `cubic-bezier(0.16, 1, 0.3, 1)`.
- Stagger: `0.06s` to `0.08s` per word. Default to `0.07s`.
- Trigger: start around `20%` visible, with a slight lower viewport bias.
- Replay: once only.

## HTML

```html
<h1 class="word-reveal" data-word-reveal>
  Build interfaces that feel calm, cinematic, and alive.
</h1>
```

## CSS

Keep no-JS content visible. Hide only after JavaScript is active and before the text has been split.

```css
.word-reveal {
  visibility: visible;
}

html.js .word-reveal[data-word-reveal]:not(.is-ready) {
  opacity: 0;
}

.word-reveal__word {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 20px, 0);
  transition:
    opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--word-index) * 0.07s);
  will-change: opacity, transform;
}

.word-reveal.is-visible .word-reveal__word {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
  html.js .word-reveal[data-word-reveal]:not(.is-ready),
  .word-reveal__word {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
```

## JavaScript

This splitter preserves spaces, avoids `innerHTML`, exposes the original sentence to screen readers, and unobserves after the first reveal.

```js
document.documentElement.classList.add("js");

function splitWordReveal(element) {
  if (element.dataset.wordRevealReady === "true") return;

  const text = element.textContent || "";
  const parts = text.split(/(\s+)/);
  let wordIndex = 0;

  element.textContent = "";
  element.setAttribute("aria-label", text.trim());

  parts.forEach((part) => {
    if (!part.trim()) {
      element.appendChild(document.createTextNode(part));
      return;
    }

    const word = document.createElement("span");
    word.className = "word-reveal__word";
    word.setAttribute("aria-hidden", "true");
    word.style.setProperty("--word-index", wordIndex);
    word.textContent = part;

    element.appendChild(word);
    wordIndex += 1;
  });

  element.dataset.wordRevealReady = "true";
  element.classList.add("is-ready");
}

function initWordReveals(selector = "[data-word-reveal]") {
  const elements = Array.from(document.querySelectorAll(selector));
  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  if (reduceMotion || !("IntersectionObserver" in window)) {
    elements.forEach((element) => {
      element.classList.add("is-ready", "is-visible");
    });
    return;
  }

  const observer = new IntersectionObserver(
    (entries, io) => {
      entries.forEach((entry) => {
        if (!entry.isIntersecting) return;

        entry.target.classList.add("is-visible");
        io.unobserve(entry.target);
      });
    },
    {
      threshold: 0.2,
      rootMargin: "0px 0px -10% 0px",
    }
  );

  elements.forEach((element) => {
    splitWordReveal(element);
    observer.observe(element);
  });
}

document.addEventListener("DOMContentLoaded", () => {
  initWordReveals();
});
```

## Framework Notes
- React/Vue/Svelte: run the splitter after mount, then clean up observer instances on route changes.
- Framer Motion: keep the same tokens: `y: 20`, `opacity: 0`, duration `0.8`, ease `[0.16, 1, 0.3, 1]`, stagger `0.06` to `0.08`, `once: true`.
- GSAP: use `fromTo(words, { y: 20, opacity: 0 }, { y: 0, opacity: 1, duration: 0.8, ease: "expo.out", stagger: 0.07 })`.

## Taste Rules
- Use on short text: headlines, subheads, labels, and quotes. Avoid long paragraphs.
- Stagger words, not letters, for a calmer premium feel.
- Keep the offset subtle. Do not add bounce, rotation, or large blur.
- Animate `transform` and `opacity` only.
- Do not split text containing links, buttons, or meaningful inline markup.
- If wrapping is important, initialize after web fonts are ready.

## Quick Checks
- Text is visible when JavaScript is disabled.
- Words begin at `translateY(20px)` and `opacity: 0`.
- Each word reveals once with a `0.06s` to `0.08s` delay.
- Repeated scrolling does not replay the animation.
- Reduced-motion users see static readable text.

© MengTo · MIT · MengTo/Skills

Similar skills

Everything for Frontend and UI →

From the same set148

css-border-gradient Applies refined gradient border treatments to cards, modals, and buttons in CSS or Tailwind. Useful when surfaces need subtle edge highlights without loud glowing outlines. CX Codex +1 1,500installs scroll-scrubbed-visual-sequence Builds reversible visual scenes driven by native scrolling, from product assembly to interface walkthroughs. Useful for interactive hero sections, diagrams, and image sequences. CX Codex +1 1,500installs unsplash-asset-images This skill picks Unsplash photos for avatars, headshots, backgrounds and wallpapers, and names the ratios and resolutions you need. CX Codex +1 1,600installs scroll-world-storytelling Turns articles, case studies, and product journeys into visual scroll-driven landing pages. Useful when you need a connected story instead of generic stacked sections. CX Codex +1 1,600installs editorial-portfolio-chapters A skill for creative-studio, agency, photographer and artist sites where the work leads the story. Useful when a portfolio has to read as a run of magazine chapters. CX Codex +1 1,400installs performance-profiling Guides performance profiling for Apple apps using Instruments and MetricKit. It directs the AI agent to pinpoint hangs and slow launch times. CX Codex +1 1,400installs audit-verify-explain-grade-5 This skill makes the agent audit a change, back every claim with evidence, and then explain the result in plain language. Handy when you review someone else's fix or a test report. CX Codex +1 1,400installs product-proof-saas A skill for SaaS and AI landing pages where the proof is a real interface or a clearly labeled demo, not atmospheric decoration. CX Codex +1 1,400installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor