gestures
Skill55k starsChanged 58 days agoMITView on GitHub
Build drag, swipe, and sheet interactions that track the finger 1:1 and stay interruptible. Use when building or fixing anything the user drags, swipes, flings, holds, or dismisses with a gesture — drawers, sheets, swipe-to-dismiss toasts and cards, drag-to-reorder, pull-to-refresh, hold-to-confirm — or when a gesture feels laggy, disconnected from the finger, jumps on release, or can't be caught mid-animation. Triggers on — gesture, drag, draggable, swipe, swipe to dismiss, fling, momentum, velocity, drawer, sheet, bottom sheet, snap points, Vaul, dragConstraints, dragElastic, dragMomentum, onDragEnd, whileDrag, useMotionValue, rubber-band, overscroll, pull to refresh, hold to delete, press and hold, touch-action, dismiss threshold, "doesn't follow my finger", "jumps when I let go", "can't grab it mid-animation".
2 other projects use a version of this.
Trending
More talk lately.thin dataabout the whole repository
Most recently taken up by
- malinskibeniamin/skillstheir own version, first seen Nov 8, 2026
- emilkowalski/skillsword for word, first seen Nov 8, 2026
Who's talking about emilkowalski/skill
- Sean Kochel“The Design Tools I Use To Ship Apps Fast”YouTube · May 7, 2026 · 12k views
- Poojan Ajani“3 Secret Claude Skills to Turn Average Claude Designs Into Masterpieces #anthropic #claudedesign”YouTube · May 29, 2026 · 735 views
- Ses2905/ai-toolkit“Add Emil Kowalski Design Engineering skill”GitHub · Sep 18, 2026 · 1 reactions
- jrech/starobrnensky_senk“Přidat skilly Emila Kowalského (design/animace) do .claude/skills”GitHub · Oct 30, 2026
- andreeyahlee/andrea-portfolio“Add Emil Kowalski, taste, and Impeccable design skills”GitHub · Jul 25, 2026
The biggest 5 of 7 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 7
Talked about on GitHub, YouTube and Bluesky (7 times).
On GitHub · 4
- Sep 18, 2026Add Emil Kowalski Design Engineering skill — Ses2905/ai-toolkit1 reaction · 1 comment
- Oct 30, 2026Přidat skilly Emila Kowalského (design/animace) do .claude/skills — jrech/starobrnensky_senk0 reactions · 1 comment
- Jul 25, 2026Add Emil Kowalski, taste, and Impeccable design skills — andreeyahlee/andrea-portfolio0 reactions · 2 comments
- May 29, 2026Add design agent skills (Taste Skill + Emil design-eng) — Abel356/Portfolio0 reactions · 1 comment
On YouTube · 2
- May 7, 2026The Design Tools I Use To Ship Apps Fast — Sean Kochel12k views · 8 comments
- May 29, 20263 Secret Claude Skills to Turn Average Claude Designs Into Masterpieces #anthropic #claudedesign — Poojan Ajani735 views
On Bluesky · 1
- May 29, 2026github.com/emilkowalski... — @adityamitra.bsky.social0 likes and reposts · 1 reply
Other versions2 projects use a version of this.
Word for word · 1
- emilkowalski/skills★ 55k100% same
Edited · 0
None found.
Wrote their own version · 1
- malinskibeniamin/skills★ 4same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository17 other files it gives its agents.
- animate-expoSkill
- animateSkill
- animation-performanceSkill
- animation-vocabularySkill
- apple-designSkill
- ask-sonnerSkill
- break-uiSkill
- choreographSkill
- emil-design-engSkill
- find-animation-opportunitiesSkill
- improve-animationsSkill
- mobile-nativeSkill
- pick-ui-librarySkill
- prototypeSkill
- remove-animationsSkill
- review-animationsSkill
- write-swiftSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 38
Snap-back is fast: If the gesture doesn't pass the threshold, return quickly with the spring — a slow snap-back feels like the UI is …
- Distinctive: line 79
The component must feel like a single entity: If the drawer opens in 200ms, its height changes and content crossfades must live in the same …
- Distinctive: line 93
Run through this for every gesture you ship:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Gesture-Driven UI
How to build gestures that feel physical. A gesture is direct manipulation: while the finger is down, the UI is the finger; the moment it lifts, physics takes over. Every rule below follows from that split.
First decision: build it, or use a solution that exists?
Doing a drawer gesture right means momentum-based dragging, overlay opacity matched to drag progress, velocity-aware dismissal, focus trapping, and Escape-to-close. That is weeks of edge cases, not an afternoon. For a bottom sheet / drawer, default to Vaul — it exists precisely because this is hard to hand-roll. Build the gesture yourself only when no library covers the interaction (custom swipe cards, bespoke drag interactions). Use the pick-ui-library skill when unsure.
The two phases of every gesture
Walk this split for any gesture you build. Mixing the phases up is the #1 cause of gestures that feel wrong.
Is the pointer currently down?
├── Yes → TRACK phase: position maps 1:1 to the pointer.
│ No easing. No duration. No spring. The element IS the finger.
└── No → RELEASE phase: physics finishes the motion.
A spring seeded with the release velocity. Never a keyframe.Track phase rules
- 1:1 means 1:1. Drive position from a
useMotionValue(or directtransformwrites), never a spring or a transition — a spring during tracking makes the element trail the finger and feel disconnected, like dragging something through syrup. - Write
transformdirectly on the dragged element. Never update a CSS variable on a parent to move children: CSS variables are inheritable, so every change recalculates styles for all descendants. This exact bug made Vaul's drag laggy past ~20 list items; settingtransformon the element fixed it. - No React state per move event. A re-render every pointermove drops frames. Motion values and direct style writes bypass the render cycle.
- Rubber-band at the edges. Dragging past a boundary should move the element a fraction of the distance (Motion:
dragElastic≈ 0.2), not stop dead — hard stops feel like hitting a wall; resistance communicates "there's nothing further" physically.
Release phase rules
- Finish with a spring, seeded with the gesture's velocity. The element should leave the finger at the speed it was moving. A fixed-duration ease here makes every fling land identically, which reads as fake.
- Dismiss on distance OR velocity. Passing a distance threshold (~40–50% of travel) dismisses, but so does a fast flick over a short distance. In Motion, read both from
onDragEnd'sinfo.offsetandinfo.velocity. Distance-only thresholds make flicks feel ignored. - Bounce belongs only at the end of a drag. A drag applies force — like throwing a ball at a wall — so a slight bounce on release feels physical. The same element closed by a button press gets zero bounce: no force was applied. Keep the value small, and remember bounce scales inversely with element size (smaller elements need more bounce to read the same).
- Snap-back is fast. If the gesture doesn't pass the threshold, return quickly with the spring — a slow snap-back feels like the UI is disagreeing with the user in slow motion.
Interruptibility is non-negotiable
The user must be able to catch a sheet mid-close and drag it back. Springs allow this: when retargeted mid-flight they keep their current velocity, so the redirect is seamless. CSS @keyframes restart from zero and cannot be caught — this is why Sonner's early CSS enter animation made toasts jump when a second toast arrived. Never use a keyframe animation on anything a gesture can touch. CSS transitions and springs only.
Linked values
The dragged element is rarely alone — an overlay fades, the page behind scales. Derive these from drag progress, don't animate them separately:
const y = useMotionValue(0);
const overlayOpacity = useTransform(y, [0, drawerHeight], [1, 0]);One source of truth means the overlay is always exactly as faded as the drawer is dismissed — including mid-gesture, including when the user reverses. Two separate animations drift apart the moment a gesture is interrupted.
Motion drag props
<motion.div
drag="y"
dragConstraints={{ top: 0 }}
dragElastic={0.2}
onDragEnd={(e, info) => {
if (info.offset.y > threshold || info.velocity.y > 500) dismiss();
}}
/>dragMomentum is on by default — right for a flung card, wrong for a simple reposition; disable it when the element should stop where the finger stops. dragConstraints takes a ref or bounds object.
Sheets without springs: the Vaul curve
Vaul mimics the iOS sheet with pure CSS to stay small: cubic-bezier(0.32, 0.72, 0, 1) over 500ms. The curve is extremely steep at the start — that's what lets a 500ms duration still feel snappy while landing with a spring-like gentle settle. Two rules from it:
- A small floating drawer (not touching the screen edge) should override to ~200ms — the 500ms iOS timing only reads right on a full-width edge-attached sheet:
[vaul-drawer] { transition: transform 0.2s cubic-bezier(0.165, 0.84, 0.44, 1); } [vaul-overlay] { transition: opacity 0.2s cubic-bezier(0.165, 0.84, 0.44, 1); } - The component must feel like a single entity. If the drawer opens in 200ms, its height changes and content crossfades must live in the same timing family — one slow sub-animation makes the whole thing feel broken.
Mark interactive children with data-vaul-no-drag so pressing a button inside the drawer doesn't start a drag.
Spatial consistency
An element dismisses in the direction it entered. Sonner's toast slides up from the bottom, so swipe-down dismisses it — enter and exit share one axis, which is what makes the gesture feel discoverable and intuitive without instruction. A gesture that dismisses along an axis the element never moved on has to be learned; one that reverses the entrance is felt.
Hold gestures are asymmetric
Hold-to-delete and similar press-and-hold interactions use linear during the hold — the animation visualizes time passing, and time passes linearly; any other curve lies about how long is left. On release before completion, snap back fast with ease-out. The deliberate phase is slow and honest; the cancel is instant. Symmetric timing here is a bug.
Touch checklist
Run through this for every gesture you ship:
- Test on a real phone — hit the dev server by local IP. Trackpad simulation lies about touch, and a 60Hz desktop monitor hides opacity-transition roughness that a 120Hz phone shows.
- Hit targets ≥ 44×44px. Enlarge small visual targets with an invisible
::beforehitbox instead of growing the layout. touch-actionon the drag axis (touch-action: pan-xfor a vertical drag, etc.) so the browser doesn't fight the gesture with native scrolling.- Gate hover effects behind
@media (hover: hover) and (pointer: fine)— touch fires phantom hovers on tap.
Reduced motion
Tracking is direct manipulation — the user is producing the motion — so it stays. What reduces: momentum flings, bounce, and any decorative motion around the gesture. On release under prefers-reduced-motion, settle with a short opacity/position change instead of a bouncy spring. See the animation-accessibility skill for the full two-variant workflow.
When it still feels wrong
A "weird" spring is usually fixed by increasing damping. A gesture that stutters is a performance problem — check the track-phase rules above first, then use the animation-performance skill. To diagnose a feeling you can't name, use the debug-animation skill: record the gesture and scrub it frame by frame.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

