animation-on-scroll — Claude Code skill: scroll-triggered animation
A skill that wires up scroll-reveal with IntersectionObserver, plus Tailwind animation classes and keyframes.
npx skills add MengTo/Skills --skill animation-on-scroll -a claude-codeWhat animation-on-scroll does
The skill runs a three-step workflow: it confirms the animation style, timing, and whether the effect plays once or repeats, then hands back the keyframes, a JS observer snippet, and the exact Tailwind class to apply. After that it only offers focused tweaks — threshold, rootMargin, duration, delay, transform and blur values.
Two code blocks do the work. The script injects CSS that keeps .animate-on-scroll paused, sets up an IntersectionObserver with threshold: 0.2 and rootMargin: "0px 0px -10% 0px", and adds the animate class when an element intersects. The keyframes define animationIn with opacity, a Y shift and a blur. In markup the whole thing looks like animate-on-scroll [animation:animationIn_0.8s_ease-out_0.1s_both].
Order matters: the keyframes go in the <head> before the script, or nothing animates. The keyframe name in the Tailwind value has to match the declared one — a mismatch fails quietly. Another common trap is an element already in view before the observer initialises, which means no animation at all. Flip once = false if you want the effect to replay on every re-entry.
What it helps with
- add scroll-reveal to a page without pulling in an animation library
- hook viewport-triggered animation into a Tailwind project
- tune delay and duration to match a design
- choose between playing the animation once or on every re-entry
- debug an animation that never fires because of load order
Example prompts for the agent
- add scroll-reveal to the card section, play it once
- animate the heading with a blur and upward shift using Tailwind
- the animation isn't firing — check that the keyframes come before the script
How to install animation-on-scroll
1Skills CLI (Vercel)
npx skills add MengTo/Skills --skill animation-on-scroll -a claude-code2Manually: put the files in place
~/.claude/skills/animation-on-scroll/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/animation-on-scroll/
1Skills CLI (Vercel)
npx skills add MengTo/Skills --skill animation-on-scroll -a codex2Manually: put the files in place
.agents/skills/animation-on-scroll/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add MengTo/Skills --skill animation-on-scroll -a cursor2Manually: put the files in place
.cursor/skills/animation-on-scroll/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install MengTo/Skills animation-on-scroll2Manually: put the files in place
.github/skills/animation-on-scroll/SKILL.md1Skills CLI (Vercel)
npx skills add MengTo/Skills --skill animation-on-scroll -a gemini-cli2Platform CLI
gemini skills install https://github.com/MengTo/Skills --path agent-skills/web-design/animation-on-scrollManually: put the files in place
.devin/skills/animation-on-scroll/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add MengTo/Skills --skill animation-on-scroll -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about animation-on-scroll
How do I install animation-on-scroll in Claude?
Run npx skills add MengTo/Skills --skill animation-on-scroll -a claude-code. The skill lands at ~/.claude/skills/animation-on-scroll/SKILL.md.
What does animation-on-scroll do?
It sets up viewport-triggered reveals: keyframes, an IntersectionObserver snippet, and the Tailwind class to apply to elements.
Why isn't my scroll animation running?
The skill lists three usual causes: keyframes loaded after the script, a keyframe name that doesn't match the Tailwind animation reference, or an element already in view before the observer initialises.
Source text
SKILL.md · MIT
---
name: animation-on-scroll
description: Create an on-scroll animation trigger using IntersectionObserver with Tailwind-friendly animation classes and keyframes. Use when asked for scroll-reveal, animate-on-scroll, or sequencing element animations when they enter the viewport.
---
# Animation On Scroll Skill
## Workflow
1. Confirm animation style, timing, and whether animations should run once or repeat.
2. Provide the keyframes + JS observer snippet and the exact Tailwind class to apply.
3. Offer focused tweaks only (threshold, rootMargin, duration, delay, transform/blur values).
## Usage checklist
- Insert the JS snippet in the `<head>` after the keyframes.
- Add the animation class and `animate-on-scroll` to elements.
- Ensure your keyframes name matches the Tailwind animation reference.
## IntersectionObserver trigger
```html
<script>
/*
Sequence animation on scroll when visible. Requires Animation Keyframe. Usage:
1) Insert this code in the <head> along with the Animation Keyframe code.
2) Add to Tailwind Classes: [animation:animationIn_0.8s_ease-out_0.1s_both] animate-on-scroll
*/
(function () {
// Inject CSS for paused/running states
const style = document.createElement("style");
style.textContent = `
/* Default: paused */
.animate-on-scroll { animation-play-state: paused !important; }
/* Activated by JS */
.animate-on-scroll.animate { animation-play-state: running !important; }
`;
document.head.appendChild(style);
const once = true;
if (!window.__inViewIO) {
window.__inViewIO = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("animate");
if (once) window.__inViewIO.unobserve(entry.target);
}
});
}, { threshold: 0.2, rootMargin: "0px 0px -10% 0px" });
}
window.initInViewAnimations = function (selector = ".animate-on-scroll") {
document.querySelectorAll(selector).forEach((el) => {
window.__inViewIO.observe(el); // observing twice is a no-op
});
};
document.addEventListener("DOMContentLoaded", () => initInViewAnimations());
})();
</script>
```
## Keyframes
```html
<style>
/*
Sequence animation intro. Usage:
1) Insert this code in the <head>
2) Add to Tailwind Classes: [animation:animationIn_0.8s_ease-out_0.1s_both]
*/
@keyframes animationIn {
0% {
opacity: 0;
transform: translateY(30px);
filter: blur(8px);
}
100% {
opacity: 1;
transform: translateY(0);
filter: blur(0px);
}
}
</style>
```
## Tailwind example
```html
<div class="animate-on-scroll [animation:animationIn_0.8s_ease-out_0.1s_both]">
...
</div>
```
## Customization knobs
- Trigger: adjust `threshold` and `rootMargin` for earlier/later reveals.
- Repeat: set `once = false` to allow replays when re-entering.
- Motion: tweak `translateY` and `blur` in keyframes.
- Timing: change duration and delay in the Tailwind animation value.
## Common pitfalls
- Forgetting to include the keyframes before the JS snippet.
- Using a different keyframe name than in the Tailwind animation.
- Animations not running because the element is already in view before observer init.
## Questions to ask when specs are missing
- Should animations run once or every time the element re-enters?
- How far before entering the viewport should they start?
- What motion style (fade, slide, blur, scale) do you want?
© MengTo · MIT · MengTo/Skills