diff --git a/README.md b/README.md index f96372f..19c0060 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Agents use each skill when the task matches the skill’s `description` (e.g. | **gsap-core** | Core API: `gsap.to()` / `from()` / `fromTo()`, easing, duration, stagger, defaults | | **gsap-timeline** | Timelines: sequencing, position parameter, labels, nesting, playback | | **gsap-scrolltrigger** | ScrollTrigger: scroll-linked animations, pinning, scrub, triggers, refresh & cleanup | +| **gsap-plugins** | Plugins: ScrollToPlugin, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, SVG & physics plugins, CustomEase, EasePack, GSDevTools, etc. | +| **gsap-utils** | gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, toArray, selector, wrap, pipe, and other helpers | | **gsap-react** | React: useGSAP hook, refs, `gsap.context()`, cleanup, SSR | | **gsap-performance** | Performance: transforms over layout props, will-change, batching, ScrollTrigger tips | @@ -46,6 +48,8 @@ gsap-skills/ gsap-core/ SKILL.md gsap-timeline/ SKILL.md gsap-scrolltrigger/ SKILL.md + gsap-plugins/ SKILL.md + gsap-utils/ SKILL.md gsap-react/ SKILL.md gsap-performance/ SKILL.md ``` diff --git a/skills/gsap-plugins/SKILL.md b/skills/gsap-plugins/SKILL.md new file mode 100644 index 0000000..981bd16 --- /dev/null +++ b/skills/gsap-plugins/SKILL.md @@ -0,0 +1,235 @@ +--- +name: gsap-plugins +description: Use GSAP plugins correctly — registration, ScrollToPlugin, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, SVG and physics plugins, CustomEase, EasePack, CustomWiggle, CustomBounce, GSDevTools. Use when the user asks about a GSAP plugin, scroll-to, flip animations, draggable, SVG drawing, or plugin registration. +license: MIT +--- + +# GSAP Plugins + +## When to Use This Skill + +Apply when using or reviewing code that uses GSAP plugins: registering plugins, scroll-to, flip/FLIP animations, draggable elements, SVG (DrawSVG, MorphSVG, MotionPath), text (SplitText, ScrambleText), physics, easing plugins (CustomEase, EasePack, CustomWiggle, CustomBounce), or GSDevTools. ScrollTrigger has its own skill (gsap-scrolltrigger). + +## Registering Plugins + +Register each plugin once so GSAP (and bundlers) know to include it. Use **gsap.registerPlugin()** with every plugin used in the project: + +```javascript +import gsap from "gsap"; +import { ScrollToPlugin } from "gsap/ScrollToPlugin"; +import { Flip } from "gsap/Flip"; +import { Draggable } from "gsap/Draggable"; + +gsap.registerPlugin(ScrollToPlugin, Flip, Draggable); +``` + +- Register before using the plugin in any tween or API call. +- In React, register at top level or once in the app (e.g. before first useGSAP); do not register inside a component that re-renders. useGSAP is a plugin that needs to be registered before use. + +## Scroll + +### ScrollToPlugin + +Animates scroll position (window or a scrollable element). Use for “scroll to element” or “scroll to position” without ScrollTrigger. + +```javascript +gsap.registerPlugin(ScrollToPlugin); + +gsap.to(window, { duration: 1, scrollTo: { y: 500 } }); +gsap.to(window, { duration: 1, scrollTo: { y: "#section", offsetY: 50 } }); +gsap.to(scrollContainer, { duration: 1, scrollTo: { x: "max" } }); +``` + +- **scrollTo**: `{ x, y, element, offsetX, offsetY }`. Use `"max"` for maximum scroll. Element can be selector or numeric position. + +### ScrollSmoother + +Smooth scroll wrapper (smooths native scroll). Requires ScrollTrigger and a specific DOM structure (content wrapper + smooth wrapper). Use when smooth, momentum-style scroll is needed. See GSAP docs for setup; register after ScrollTrigger. DOM structure would look like: + +```html + +
+
+ +
+
+ + +``` + +## DOM / UI + +### Flip + +Capture state with `Flip.getState()`, then apply changes (e.g. layout or class changes), then use `Flip.from()` to animate from the previous state to the new state (FLIP: First, Last, Invert, Play). Use when animating between two layout states (lists, grids, expanded/collapsed). + +```javascript +gsap.registerPlugin(Flip); + +const state = Flip.getState(".item"); +// change DOM (reorder, add/remove, change classes) +Flip.from(state, { duration: 0.5, ease: "power2.inOut" }); +``` + +- **Flip.getState()** — pass element(s) or selector; returns state object. +- **Flip.from(state, vars)** — animate from that state to current layout. Options: `absolute`, `nested`, `scale`, `simple`, etc. + +#### More information + +https://gsap.com/docs/v3/Plugins/Flip + +### Draggable + +Makes elements draggable, spinnable, or throwable with mouse/touch. Use for sliders, cards, reorderable lists, or any drag interaction. + +```javascript +gsap.registerPlugin(Draggable, InertiaPlugin); + +Draggable.create(".box", { type: "x,y", bounds: "#container", inertia: true }); +Draggable.create(".knob", { type: "rotation" }); +``` + +- **type**: `"x"`, `"y"`, `"x,y"`, `"rotation"`, etc. +- **bounds**: element or `{ minX, maxX, minY, maxY }`. +- **inertia**: boolean; uses InertiaPlugin if true (requires InertiaPlugin registered). +- Events: **onDragStart**, **onDrag**, **onDragEnd**, **onThrowUpdate**, **onThrowComplete**. + +### Inertia (InertiaPlugin) + +Works with Draggable for momentum after release, or track the inertia/velocity of any property of any object so that it can then seamlessly glide to a stop using a simple tween. Register with Draggable when using `inertia: true`: + +```javascript +gsap.registerPlugin(Draggable, InertiaPlugin); +Draggable.create(".box", { type: "x,y", inertia: true }); +``` + +Or track velocity of a property: +```javascript +InertiaPlugin.track(".box", "x"); +``` + +Then use `"auto"` to continue the current velocity and glide to a stop: + +```javascript +gsap.to(obj, { inertia: { x: "auto" } }); +``` + +### Observer + +Normalizes pointer and scroll input across devices. Use for swipe, scroll direction, or custom gesture logic without tying directly to scroll position like ScrollTrigger. + +```javascript +gsap.registerPlugin(Observer); + +Observer.create({ + target: "#area", + onUp: () => {}, + onDown: () => {}, + onLeft: () => {}, + onRight: () => {}, + tolerance: 10 +}); +``` + +## Text + +### SplitText + +Splits text into chars, words, or lines for staggered or per-char animation. Use when animating text character-by-character or word-by-word. Restores original text on `revert()`; or let `gsap.context()` revert. + +### ScrambleText + +Animates text with a scramble/glitch effect. Use when revealing or transitioning text with a scramble. + +## SVG + +### DrawSVG (DrawSVGPlugin) + +Animates SVG stroke dash (draw/undraw strokes). Use when “drawing” or “erasing” SVG paths. + +```javascript +gsap.registerPlugin(DrawSVGPlugin); + +gsap.fromTo("#path", { drawSVG: "0% 0%" }, { drawSVG: "0% 100%", duration: 1 }); +``` + +### MorphSVG (MorphSVGPlugin) + +Morphs one SVG shape into another. Use when morphing paths (e.g. icon A → icon B). Uses path data; shapes do not need to have the same number of points; they're converted to cubic beziers internally and points are added as necessary. + +### MotionPath (MotionPathPlugin) + +Animates an element along an SVG path. Use when moving an object along a path (e.g. a curve or custom route). + +```javascript +gsap.registerPlugin(MotionPathPlugin); + +gsap.to(".dot", { + duration: 2, + motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5] } +}); +``` + +### MotionPathHelper + +Visual editor for MotionPath (alignment, offset). Use during development to tune path alignment. + +## Easing + +### CustomEase + +Custom easing curves (cubic-bezier or SVG path). Use when a built-in ease is not enough. Basic usage is covered in gsap-core; register when using: + +```javascript +gsap.registerPlugin(CustomEase); +const ease = CustomEase.create("name", ".17,.67,.83,.67"); +gsap.to(".el", { x: 100, ease: ease, duration: 1 }); +``` + +### EasePack + +Adds more named eases (e.g. SlowMo, RoughEase, ExpoScaleEase). Register and use the ease names in tweens. + +### CustomWiggle + +Wiggle/shake easing. Use when a value should “wiggle” (multiple oscillations). + +### CustomBounce + +Bounce-style easing with configurable strength. + +## Physics + +### Physics2D (Physics2DPlugin) + +2D physics (velocity, angle, gravity). Use when animating with simple physics (e.g. projectiles, bouncing). + +### PhysicsProps (PhysicsPropsPlugin) + +Applies physics to property values. Use for physics-driven property animation. + +## Development + +### GSDevTools + +UI for scrubbing timelines, toggling animations, and debugging. Use during development only; do not ship. Register and create an instance with a timeline reference. + +```javascript +gsap.registerPlugin(GSDevTools); +GSDevTools.create({ animation: tl }); +``` + +## Other + +### Pixi (PixiPlugin) + +Integrates GSAP with PixiJS for animating Pixi display objects. Register when animating Pixi objects with GSAP. + +## Do Not + +- Use a plugin in a tween or API without registering it first (**gsap.registerPlugin()**). +- Ship GSDevTools or development-only plugins to production. + +### Learn More + +https://gsap.com/docs/v3/Plugins/ diff --git a/skills/gsap-utils/SKILL.md b/skills/gsap-utils/SKILL.md new file mode 100644 index 0000000..ef5941b --- /dev/null +++ b/skills/gsap-utils/SKILL.md @@ -0,0 +1,190 @@ +--- +name: gsap-utils +description: Use gsap.utils for clamping, distribution, interpolation, mapping, random, snapping, arrays, and strings. Use when the user asks about gsap.utils, clamp, mapRange, random, snap, toArray, wrap, or helper utilities in GSAP. +license: MIT +--- + +# gsap.utils + +## When to Use This Skill + +Apply when writing or reviewing code that uses **gsap.utils** for math, array/collection handling, unit parsing, or value mapping in animations (e.g. mapping scroll to a value, randomizing, snapping to a grid, or normalizing inputs). + +## Overview + +**gsap.utils** provides pure helpers; no need to register. Use in tween vars (e.g. function-based values), in ScrollTrigger or Observer callbacks, or in any JS that drives GSAP. All are on **gsap.utils** (e.g. `gsap.utils.clamp()`). + +## Clamping and Ranges + +### clamp(min, max, value) + +Constrains a value between min and max. + +```javascript +gsap.utils.clamp(0, 100, 150); // 100 +gsap.utils.clamp(0, 100, -10); // 0 +``` + +### mapRange(inMin, inMax, outMin, outMax, value) + +Maps a value from one range to another. Use when converting scroll position, progress (0–1), or input range to an animation range. + +```javascript +gsap.utils.mapRange(0, 100, 0, 500, 50); // 250 +gsap.utils.mapRange(0, 1, 0, 360, 0.5); // 180 (progress to degrees) +``` + +### normalize(min, max, value) + +Returns a value normalized to 0–1 for the given range. Inverse of mapping when the target range is 0–1. + +```javascript +gsap.utils.normalize(0, 100, 50); // 0.5 +gsap.utils.normalize(100, 300, 200); // 0.5 +``` + +### interpolate(start, end, progress) + +Interpolates between two values at a given progress (0–1). Handles numbers, colors, and objects with matching keys. + +```javascript +gsap.utils.interpolate(0, 100, 0.5); // 50 +gsap.utils.interpolate("#ff0000", "#0000ff", 0.5); // mid color +gsap.utils.interpolate({ x: 0, y: 0 }, { x: 100, y: 50 }, 0.5); // { x: 50, y: 25 } +``` + +## Random and Snap + +### random(min, max, increment?) + +Returns a random number between min and max. Optional **increment** snaps to steps (e.g. `increment: 1` for integers). + +```javascript +gsap.utils.random(10, 20); // e.g. 14.3 +gsap.utils.random(1, 10, 1); // integer 1–10 +gsap.utils.random(-100, 100, 10); // -100, -90, ..., 100 +``` + +### snap(snapTo, value) + +Snaps a value to the nearest multiple of **snapTo**, or to the nearest value in an array of allowed values. + +```javascript +gsap.utils.snap(10, 23); // 20 +gsap.utils.snap(0.25, 0.7); // 0.75 +gsap.utils.snap([0, 100, 200], 150); // 100 or 200 (nearest in array) +``` + +Use in tweens for grid or step-based animation: + +```javascript +gsap.to(".x", { x: 200, snap: { x: 20 } }); +``` + +### shuffle(array) + +Returns a new array with the same elements in random order. Use for randomizing order (e.g. stagger from "random" with a copy). + +```javascript +gsap.utils.shuffle([1, 2, 3, 4]); // e.g. [3, 1, 4, 2] +``` + +### distribute(baseObject) + +Distributes values across a range (e.g. for positioning many elements). Returns a function that, given an index and total, returns a value in the range. See GSAP docs for **base**, **amount**, **from**, **grid**, etc. + +```javascript +const dist = gsap.utils.distribute({ base: 0, amount: 100, from: "center" }); +dist(0, 5); // value for index 0 of 5 +dist(2, 5); // value for index 2 of 5 +``` + +## Units and Parsing + +### getUnit(value) + +Returns the unit string of a value (e.g. `"px"`, `"%"`, `"deg"`). Use when normalizing or converting values. + +```javascript +gsap.utils.getUnit("100px"); // "px" +gsap.utils.getUnit("50%"); // "%" +gsap.utils.getUnit(42); // "" (unitless) +``` + +### unitize(value, unit) + +Appends a unit to a number, or returns the value as-is if it already has a unit. Use when building CSS values or tween end values. + +```javascript +gsap.utils.unitize(100, "px"); // "100px" +gsap.utils.unitize("2rem", "px"); // "2rem" (unchanged) +``` + +### splitColor(color) + +Splits a color string into RGB components (0–255) or an array. Use when animating color components or building gradients. + +```javascript +gsap.utils.splitColor("#ff0000"); // [255, 0, 0] or similar +``` + +## Arrays and Collections + +### selector(scope) + +Returns a scoped selector function that finds elements only within the given element (or ref). Use in components so selectors like `".box"` match only descendants of that component, not the whole document. Accepts a DOM element or a ref (e.g. React ref; handles `.current`). + +```javascript +const q = gsap.utils.selector(containerRef); +q(".box"); // array of .box elements inside container +gsap.to(q(".circle"), { x: 100 }); +``` + +### toArray(value, scope?) + +Converts a value to an array: selector string (scoped to element), NodeList, HTMLCollection, single element, or array. Use when passing mixed inputs to GSAP (e.g. targets) and a true array is needed. + +```javascript +gsap.utils.toArray(".item"); // array of elements +gsap.utils.toArray(".item", container); // scoped to container +gsap.utils.toArray(nodeList); // [ ... ] from NodeList +``` + +### pipe(...functions) + +Composes functions: **pipe(f1, f2, f3)(value)** returns f3(f2(f1(value))). Use when applying a chain of transforms (e.g. normalize → mapRange → snap) in a tween or callback. + +```javascript +const fn = gsap.utils.pipe( + (v) => gsap.utils.normalize(0, 100, v), + (v) => gsap.utils.snap(0.1, v) +); +fn(50); // normalized then snapped +``` + +### wrap(min, max, value) + +Wraps a value into the range min–max (inclusive min, exclusive max). Use for infinite scroll or cyclic values. + +```javascript +gsap.utils.wrap(0, 360, 370); // 10 +gsap.utils.wrap(0, 360, -10); // 350 +``` + +### wrapYoyo(min, max, value) + +Wraps value in range with a yoyo (bounces at ends). Use for back-and-forth within a range. + +```javascript +gsap.utils.wrapYoyo(0, 100, 150); // 50 (bounces back) +``` + +## Do Not + +- Use **gsap.utils** for DOM queries when a simple selector or ref is enough; **toArray** is for when GSAP or your code needs a real array. +- Assume **mapRange** / **normalize** handle units; they work on numbers. Use **getUnit** / **unitize** when units matter. +- Override or rely on undocumented behavior; stick to the documented API. + +### Learn More + +https://gsap.com/docs/v3/HelperFunctions