Agent skill
lenis
Use when implementing Lenis smooth scroll or integrating Lenis with GSAP ScrollTrigger. Applies Lenis best practices for setup and performance.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/lenis
SKILL.md
Lenis Smooth Scroll Best Practices
Apply when implementing Lenis smooth scrolling.
Documentation: https://lenis.darkroom.engineering/
Required CSS
Always include this CSS for proper functionality:
html.lenis, html.lenis body {
height: auto;
}
.lenis.lenis-smooth {
scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
overscroll-behavior: contain;
}
.lenis.lenis-stopped {
overflow: hidden;
}
.lenis.lenis-scrolling iframe {
pointer-events: none;
}
Basic Setup
Standalone (Simple)
import Lenis from 'lenis';
const lenis = new Lenis({
autoRaf: true, // Uses built-in RAF loop
});
With GSAP ScrollTrigger (Recommended)
import Lenis from 'lenis';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
let lenisInstance: Lenis | null = null;
let tickerCallback: ((time: number) => void) | null = null;
function init() {
lenisInstance = new Lenis();
// Sync Lenis scroll position with ScrollTrigger
lenisInstance.on('scroll', ScrollTrigger.update);
// Store callback reference for cleanup
tickerCallback = (time) => lenisInstance?.raf(time * 1000);
gsap.ticker.add(tickerCallback);
// Disable GSAP lag smoothing for precise sync
gsap.ticker.lagSmoothing(0);
}
function destroy() {
// Remove ticker callback first (prevents memory leak!)
if (tickerCallback) {
gsap.ticker.remove(tickerCallback);
tickerCallback = null;
}
if (lenisInstance) {
lenisInstance.destroy();
lenisInstance = null;
}
}
Critical: Store the ticker callback reference. Without gsap.ticker.remove(), callbacks accumulate on each init, causing memory leaks and performance issues.
Configuration Options
const lenis = new Lenis({
duration: 1.2, // Scroll animation duration
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // Ease out expo
orientation: 'vertical', // or 'horizontal'
gestureOrientation: 'vertical',
smoothWheel: true, // Smooth wheel scrolling
syncTouch: false, // Don't smooth touch (usually unwanted)
touchMultiplier: 2, // Touch scroll speed
});
Recommended Defaults
duration: 1.2— Smooth but responsivesmoothWheel: true— Essential for smooth feelsyncTouch: false— Native touch usually better
Preventing Scroll on Elements
<!-- Prevent Lenis on scrollable containers -->
<div data-lenis-prevent>
<div class="scrollable-content">
<!-- This scrolls normally, Lenis ignores it -->
</div>
</div>
<!-- Prevent only wheel events -->
<div data-lenis-prevent-wheel>
<!-- Touch still uses Lenis -->
</div>
<!-- Prevent only touch events -->
<div data-lenis-prevent-touch>
<!-- Wheel still uses Lenis -->
</div>
Scroll Methods
// Scroll to element
lenis.scrollTo('#section', {
offset: -100, // Offset from target
duration: 2, // Override default duration
easing: (t) => t, // Custom easing
immediate: false, // Skip animation
lock: true, // Prevent user scroll during animation
});
// Scroll to position
lenis.scrollTo(500); // Scroll to 500px
lenis.scrollTo('top'); // Scroll to top
lenis.scrollTo('bottom'); // Scroll to bottom
// Control
lenis.stop(); // Pause scrolling
lenis.start(); // Resume scrolling
Event Handling
lenis.on('scroll', ({ scroll, velocity, direction, progress }) => {
// scroll: current scroll position
// velocity: scroll speed
// direction: 1 (down) or -1 (up)
// progress: 0-1 scroll progress
});
Cleanup
// On component unmount:
lenis.destroy();
Known Limitations
- Iframes — Smooth scroll stops over iframes (they don't forward wheel events)
- Safari pre-M1 —
position: fixedmay lag slightly - Nested scroll containers — Use
data-lenis-preventon them - Browser smooth scroll — Disable any built-in smooth scrolling
Troubleshooting
Scroll not smooth
- Check required CSS is included
- Verify
autoRaf: trueor GSAP ticker integration - Check for conflicting scroll libraries
ScrollTrigger not syncing
- Ensure
lenis.on('scroll', ScrollTrigger.update)is set - Call
ScrollTrigger.refresh()after Lenis init - Check
gsap.ticker.lagSmoothing(0)is set
Elements not receiving scroll
- Check for
data-lenis-preventon parent elements - Verify Lenis is initialized after DOM ready
Common Patterns
Anchor Links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
e.preventDefault();
const target = document.querySelector(anchor.getAttribute('href'));
if (target) {
lenis.scrollTo(target, { offset: -80 });
}
});
});
Stop During Modal
function openModal() {
lenis.stop();
// show modal
}
function closeModal() {
lenis.start();
// hide modal
}
Avoid
- Forgetting required CSS (causes jittery scroll)
- Using
syncTouch: true(native touch is usually better) - Multiple Lenis instances on the same page
- Forgetting to call
lenis.destroy()on unmount - Using both
autoRafand GSAP ticker (pick one) - Missing
ScrollTrigger.updatesync when using GSAP - Animating scroll position directly (use
lenis.scrollTo()) - Setting
durationtoo high (>2s feels sluggish)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?