[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6M33WZFWDS7C9R2Y90GPF74":3,"skill-same:01M6M33WZFWDS7C9R2Y90GPF74":81},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":13,"repositoryHtmlUrl":64,"repositoryHomepageUrl":6,"ownerHtmlUrl":65,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":66,"install":67,"resources":80},"01M6M33WZFWDS7C9R2Y90GPF74","gsap-plugins",null,"Official GSAP skill for GSAP plugins — 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.","endman100\u002Fskill-router-nexus","endman100","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F31997019?v=4","01M6KPDX17BYDWW4RRB0TNGGMX","01M6KPDX64Y2QBEWVFG5W5PWPF",0,"MIT","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWeb-Design\u002Ffrontend-and-motion-implementation\u002Fopen-design-gsap-plugins\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"gsap","gsap plugins","plugins","registration","when","animations","observer","for","about","inertia","SVG","scroll","physics","drawing","github","motion","use","user","Animation","https","plugin","official","prototype","2026-11-10 10:12:30",false,"---\nname: gsap-plugins\ndescription: |\n  Official GSAP skill for GSAP plugins — 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.\ntriggers:\n  - \"gsap plugins\"\n  - \"gsap plugin registration\"\n  - \"flip animation\"\n  - \"draggable\"\n  - \"morphsvg\"\n  - \"splittext\"\nlicense: MIT\nod:\n  mode: prototype\n  category: animation-motion\n  upstream: \"https:\u002F\u002Fgithub.com\u002Fgreensock\u002Fgsap-skills\"\n---\n\n# GSAP Plugins\n\n> Curated from GreenSock's official GSAP skills: https:\u002F\u002Fgithub.com\u002Fgreensock\u002Fgsap-skills\n\n## When to Use This Skill\n\nApply when using or reviewing code that uses GSAP plugins: registering plugins, scroll-to, flip\u002FFLIP 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).\n\n**Related skills:** For core tweens use **gsap-core**; for ScrollTrigger use **gsap-scrolltrigger**; for React use **gsap-react**.\n\n## Licensing & Install (important)\n\nEvery GSAP plugin is **free**, including for commercial use. Since [Webflow's acquisition of GSAP](https:\u002F\u002Fgsap.com\u002Fblog\u002Fwebflow-GSAP\u002F), Club GSAP is no longer a paid tier and **no plugin requires a membership, license key, or auth token** — this includes formerly Club-only plugins (**SplitText**, **MorphSVG**, etc.).\n\n- ✅ Install everything from the public `gsap` npm package: `npm install gsap`. All plugins are included — import them as `gsap\u002FSplitText`, `gsap\u002FMorphSVGPlugin`, etc.\n- ❌ Do **not** generate an `.npmrc` with a GreenSock auth token, suggest the private `npm.greensock.com` registry, or tell users to sign up for Club GSAP to access a plugin. Those instructions are outdated.\n\n## Registering Plugins\n\nRegister each plugin once so GSAP (and bundlers) know to include it. Use **gsap.registerPlugin()** with every plugin used in the project:\n\n```javascript\nimport gsap from \"gsap\";\nimport { ScrollToPlugin } from \"gsap\u002FScrollToPlugin\";\nimport { Flip } from \"gsap\u002FFlip\";\nimport { Draggable } from \"gsap\u002FDraggable\";\n\ngsap.registerPlugin(ScrollToPlugin, Flip, Draggable);\n```\n\n- ✅ Register before using the plugin in any tween or API call.\n- ✅ 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.\n\n## Scroll\n\n### ScrollToPlugin\n\nAnimates scroll position (window or a scrollable element). Use for “scroll to element” or “scroll to position” without ScrollTrigger.\n\n```javascript\ngsap.registerPlugin(ScrollToPlugin);\n\ngsap.to(window, { duration: 1, scrollTo: { y: 500 } });\ngsap.to(window, { duration: 1, scrollTo: { y: \"#section\", offsetY: 50 } });\ngsap.to(scrollContainer, { duration: 1, scrollTo: { x: \"max\" } });\n```\n\n**ScrollToPlugin — key config (scrollTo object):**\n\n| Option | Description |\n|--------|-------------|\n| `x`, `y` | Target scroll position (number), or `\"max\"` for maximum |\n| `element` | Selector or element to scroll to (for scroll-into-view) |\n| `offsetX`, `offsetY` | Offset in pixels from the target position |\n\n### ScrollSmoother\n\nSmooth 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: \n\n```html\n\u003Cbody>\n\t\u003Cdiv id=\"smooth-wrapper\">\n\t\t\u003Cdiv id=\"smooth-content\">\n\t\t\t\u003C!--- ALL YOUR CONTENT HERE --->\n\t\t\u003C\u002Fdiv>\n\t\u003C\u002Fdiv>\n\t\u003C!-- position: fixed elements can go outside --->\n\u003C\u002Fbody>\n```\n\n## DOM \u002F UI\n\n### Flip\n\nCapture 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\u002Fcollapsed).\n\n```javascript\ngsap.registerPlugin(Flip);\n\nconst state = Flip.getState(\".item\");\n\u002F\u002F change DOM (reorder, add\u002Fremove, change classes)\nFlip.from(state, { duration: 0.5, ease: \"power2.inOut\" });\n```\n\n**Flip — key config (Flip.from vars):**\n\n| Option | Description |\n|--------|-------------|\n| `absolute` | Use `position: absolute` during the flip (default: `false`) |\n| `nested` | When true, only the first level of children is measured (better for nested transforms) |\n| `scale` | When true, scale elements to fit (avoids stretch); default `true` |\n| `simple` | When true, only position\u002Fscale are animated (faster, less accurate) |\n| `duration`, `ease` | Standard tween options |\n\n#### More information\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FFlip\n\n### Draggable\n\nMakes elements draggable, spinnable, or throwable with mouse\u002Ftouch. Use for sliders, cards, reorderable lists, or any drag interaction.\n\n```javascript\ngsap.registerPlugin(Draggable, InertiaPlugin);\n\nDraggable.create(\".box\", { type: \"x,y\", bounds: \"#container\", inertia: true });\nDraggable.create(\".knob\", { type: \"rotation\" });\n```\n\n**Draggable — key config options:**\n\n| Option | Description |\n|--------|-------------|\n| `type` | `\"x\"`, `\"y\"`, `\"x,y\"`, `\"rotation\"`, `\"scroll\"` |\n| `bounds` | Element, selector, or `{ minX, maxX, minY, maxY }` to constrain drag |\n| `inertia` | `true` to enable throw\u002Fmomentum (requires InertiaPlugin) |\n| `edgeResistance` | 0–1; resistance when dragging past bounds |\n| `cursor` | CSS cursor during drag |\n| `onDragStart`, `onDrag`, `onDragEnd` | Callbacks; receive event and target |\n| `onThrowUpdate`, `onThrowComplete` | Callbacks when inertia is active |\n\n### Inertia (InertiaPlugin)\n\nWorks with Draggable for momentum after release, or track the inertia\u002Fvelocity 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`:\n\n```javascript\ngsap.registerPlugin(Draggable, InertiaPlugin);\nDraggable.create(\".box\", { type: \"x,y\", inertia: true });\n```\n\nOr track velocity of a property: \n```javascript\nInertiaPlugin.track(\".box\", \"x\");\n```\n\nThen use `\"auto\"` to continue the current velocity and glide to a stop: \n\n```javascript\ngsap.to(obj, { inertia: { x: \"auto\" } });\n```\n\n### Observer\n\nNormalizes pointer and scroll input across devices. Use for swipe, scroll direction, or custom gesture logic without tying directly to scroll position like ScrollTrigger.\n\n```javascript\ngsap.registerPlugin(Observer);\n\nObserver.create({\n  target: \"#area\",\n  onUp: () => {},\n  onDown: () => {},\n  onLeft: () => {},\n  onRight: () => {},\n  tolerance: 10\n});\n```\n\n**Observer — key config options:**\n\n| Option | Description |\n|--------|-------------|\n| `target` | Element or selector to observe |\n| `onUp`, `onDown`, `onLeft`, `onRight` | Callbacks when swipe\u002Fscroll passes tolerance in that direction |\n| `tolerance` | Pixels before direction is detected; default 10 |\n| `type` | `\"touch\"`, `\"pointer\"`, or `\"wheel\"` (default: `\"touch,pointer\"`) |\n\n## Text\n\n### SplitText\n\nSplits an element’s text into characters, words, and\u002For lines (each in its own element) for staggered or per-unit animation. Use when animating text character-by-character, word-by-word, or line-by-line. Returns an instance with **chars**, **words**, **lines** (and **masks** when `mask` is set). Restore original markup with **revert()** or let **gsap.context()** revert. Integrates with **gsap.context()**, **matchMedia()**, and **useGSAP()**. API: **SplitText.create(target, vars)** (target = selector, element, or array).\n\n```javascript\ngsap.registerPlugin(SplitText);\n\nconst split = SplitText.create(\".heading\", { type: \"words, chars\" });\ngsap.from(split.chars, { opacity: 0, y: 20, stagger: 0.03, duration: 0.4 });\n\u002F\u002F later: split.revert() or let gsap.context() cleanup revert\n```\n\nWith **onSplit()** (v3.13.0+), animations run on each split and on re-split when **autoSplit** is used; returning a tween\u002Ftimeline from **onSplit()** lets SplitText clean up and sync progress on re-split:\n\n```javascript\nSplitText.create(\".split\", {\n  type: \"lines\",\n  autoSplit: true,\n  onSplit(self) {\n    return gsap.from(self.lines, { y: 100, opacity: 0, stagger: 0.05, duration: 0.5 });\n  }\n});\n```\n\n**SplitText — key config (SplitText.create vars):**\n\n| Option | Description |\n|--------|-------------|\n| **type** | Comma-separated: `\"chars\"`, `\"words\"`, `\"lines\"`. Default `\"chars,words,lines\"`. Only split what is needed (e.g. `\"words, chars\"` if not using lines) for performance. Avoid chars-only without words\u002Flines or use **smartWrap: true** to prevent odd line breaks. |\n| **charsClass**, **wordsClass**, **linesClass** | CSS class on each split element. Append `\"++\"` to add an incremented class (e.g. `linesClass: \"line++\"` → `line1`, `line2`, …). |\n| **aria** | `\"auto\"` (default), `\"hidden\"`, or `\"none\"`. Accessibility: `\"auto\"` adds `aria-label` on the split element and `aria-hidden` on line\u002Fword\u002Fchar elements so screen readers read the label; `\"hidden\"` hides all from readers; `\"none\"` leaves aria unchanged. Use `\"none\"` plus a screen-reader-only duplicate if nested links\u002Fsemantics must be exposed. |\n| **autoSplit** | When `true`, reverts and re-splits when fonts finish loading or when the element width changes (and lines are split), avoiding wrong line breaks. **Animations must be created inside onSplit()** so they target the newly split elements; **return** the animation from **onSplit()** for automatic cleanup and time-sync on re-split. |\n| **onSplit(self)** | Callback when split completes (and on each re-split if **autoSplit** is `true`). Receives the SplitText instance. Returning a GSAP tween or timeline enables automatic revert\u002Fsync of that animation when re-splitting. |\n| **mask** | `\"lines\"`, `\"words\"`, or `\"chars\"`. Wraps each unit in an extra element with `overflow: clip` for mask\u002Freveal effects. Only one type; access wrappers on the instance’s **masks** array (or use class `-mask` if a class is set). |\n| **tag** | Wrapper element tag; default `\"div\"`. Use `\"span\"` for inline (note: transforms like rotation\u002Fscale may not render on inline elements in some browsers). |\n| **deepSlice** | When `true` (default), nested elements (e.g. `\u003Cstrong>`) that span multiple lines are subdivided so lines don’t stretch vertically. Only applies when splitting lines. |\n| **ignore** | Selector or element(s) to leave unsplit (e.g. `ignore: \"sup\"`). |\n| **smartWrap** | When splitting **chars** only, wraps words in a `white-space: nowrap` span to avoid mid-word line breaks. Ignored if words or lines are split. Default `false`. |\n| **wordDelimiter** | Word boundary: string (default `\" \"`), RegExp, or `{ delimiter: RegExp, replaceWith: string }` for custom splitting (e.g. zero-width joiner for hashtags, or non-Latin). |\n| **prepareText(text, parent)** | Function that receives raw text and parent element; return modified text before splitting (e.g. to insert break markers for languages without spaces). |\n| **propIndex** | When `true`, adds a CSS variable with index on each split element (e.g. `--word: 1`, `--char: 2`). |\n| **reduceWhiteSpace** | Collapse consecutive spaces; default `true`. From v3.13.0 also honors line breaks and can insert `\u003Cbr>` for `\u003Cpre>`. |\n| **onRevert** | Callback when the instance is reverted. |\n\n**Tips:** Split only what is animated (e.g. skip chars if only animating words). For custom fonts, split after they load (e.g. `document.fonts.ready.then(...)`) or use **autoSplit: true** with **onSplit()**. To avoid kerning shift when splitting chars, use CSS `font-kerning: none; text-rendering: optimizeSpeed;`. Avoid `text-wrap: balance`; it can interfere with splitting. SplitText does not support SVG `\u003Ctext>`.\n\n**Learn more:** [SplitText](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FSplitText\u002F)\n\n### ScrambleText\n\nAnimates text with a scramble\u002Fglitch effect. Use when revealing or transitioning text with a scramble.\n\n```javascript\ngsap.registerPlugin(ScrambleTextPlugin);\n\ngsap.to(\".text\", {\n  duration: 1,\n  scrambleText: { text: \"New message\", chars: \"01\", revealDelay: 0.5 }\n});\n```\n\n## SVG\n\n### DrawSVG (DrawSVGPlugin)\n\nReveals or hides the stroke of SVG elements by animating `stroke-dashoffset` \u002F `stroke-dasharray`. Works on `\u003Cpath>`, `\u003Cline>`, `\u003Cpolyline>`, `\u003Cpolygon>`, `\u003Crect>`, `\u003Cellipse>`. Use when “drawing” or “erasing” strokes.\n\n**drawSVG value:** Describes the **visible segment** of the stroke along the path (start and end positions), not “animate from A to B over time.” Format: `\"start end\"` in percent or length. Examples: `\"0% 100%\"` = full stroke; `\"20% 80%\"` = stroke only between 20% and 80% (gaps at both ends). The tween animates from the element’s **current** segment to the **target** segment — e.g. `gsap.to(\"#path\", { drawSVG: \"0% 100%\" })` goes from whatever it is now to full stroke. Single value (e.g. `0`, `\"100%\"`) means start is 0: `\"100%\"` is equivalent to `\"0% 100%\"`. \n\n**Required:** The element must have a visible stroke — set `stroke` and `stroke-width` in CSS or as SVG attributes; otherwise nothing is drawn.\n\n```javascript\ngsap.registerPlugin(DrawSVGPlugin);\n\n\u002F\u002F draw from nothing to full stroke\ngsap.from(\"#path\", { duration: 1, drawSVG: 0 });\n\u002F\u002F or explicit segment: from 0–0 to 0–100%\ngsap.fromTo(\"#path\", { drawSVG: \"0% 0%\" }, { drawSVG: \"0% 100%\", duration: 1 });\n\u002F\u002F stroke only in the middle (gaps at ends)\ngsap.to(\"#path\", { duration: 1, drawSVG: \"20% 80%\" });\n```\n\n**Caveats:** Only affects stroke (not fill). Prefer single-segment `\u003Cpath>` elements; multi-segment paths can render oddly in some browsers. Contents of `\u003Cuse>` cannot be visually changed. **DrawSVGPlugin.getLength(element)** and **DrawSVGPlugin.getPosition(element)** return stroke length and current position.\n\n**Learn more:** [DrawSVG](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FDrawSVGPlugin)\n\n### MorphSVG (MorphSVGPlugin)\n\nMorphs one SVG shape into another by animating the `d` attribute (path data). Start and end shapes do not need the same number of points — MorphSVG converts to cubic beziers and adds points as needed. Use for icon-to-icon morphs, shape transitions, or path-based animations. Works on `\u003Cpath>`, `\u003Cpolyline>`, and `\u003Cpolygon>`; `\u003Ccircle>`, `\u003Crect>`, `\u003Cellipse>`, and `\u003Cline>` are converted internally or via **MorphSVGPlugin.convertToPath(selector | element)** (replaces the element in the DOM with a `\u003Cpath>`).\n\n**morphSVG value:** Can be a **selector** (e.g. `\"#lightning\"`), an **element**, **raw path data** (e.g. `\"M47.1,0.8 73.3,0.8...\"`), or for polygon\u002Fpolyline a **points string** (e.g. `\"240,220 240,70 70,70 70,220\"`). For full config use the **object form** with **shape** as the only required property.\n\n```javascript\ngsap.registerPlugin(MorphSVGPlugin);\n\n\u002F\u002F convert primitives to path first if needed:\nMorphSVGPlugin.convertToPath(\"circle, rect, ellipse, line\");\n\ngsap.to(\"#diamond\", { duration: 1, morphSVG: \"#lightning\", ease: \"power2.inOut\" });\n\u002F\u002F object form:\ngsap.to(\"#diamond\", {\n  duration: 1,\n  morphSVG: { shape: \"#lightning\", type: \"rotational\", shapeIndex: 2 }\n});\n\n```\n\n**MorphSVG — key config (morphSVG object):**\n\n| Option | Description |\n|--------|-------------|\n| **shape** | _(Required.)_ Target shape: selector, element, or raw path string. |\n| **type** | `\"linear\"` (default) or `\"rotational\"`. Rotational uses angle\u002Flength interpolation and can avoid kinks mid-morph; try it when linear looks wrong. |\n| **map** | How segments are matched: `\"size\"` (default), `\"position\"`, or `\"complexity\"`. Use when start\u002Fend segments don’t line up; if none work, split into multiple paths and morph each. |\n| **shapeIndex** | Offsets which point in the start path maps to the first point in the end path (avoids shape “crossing over” or inverting). Number for single-segment paths; **array** for multi-segment (e.g. `[5, 1, -8]`). Negative reverses that segment. Use **shapeIndex: \"log\"** once to log the auto-calculated value, then paste the number\u002Farray into the tween. **findShapeIndex(start, end)** (separate utility) provides an interactive UI to find a good value. Only applies to closed paths. |\n| **smooth** | (v3.14+). Adds smoothing points. Number (e.g. `80`), `\"auto\"`, or object: `{ points: 40 \\| \"auto\", redraw: true \\| false, persist: true \\| false }`. `redraw: false` keeps original anchors (perfect fidelity, less even spacing). `persist: false` removes added points when the tween ends. Use when the default morph looks jagged or unnatural. |\n| **curveMode** | Boolean (v3.14+). Interpolates control-handle angle\u002Flength instead of raw x\u002Fy to avoid kinks on curves. Try if a morph has a mid-morph kink. |\n| **origin** | Rotation origin for **type: \"rotational\"**. String: `\"50% 50%\"` (default) or `\"20% 60%, 35% 90%\"` for different start\u002Fend origins. |\n| **precision** | Decimal places for output path data; default `2`. |\n| **precompile** | Array of precomputed path strings (or use **precompile: \"log\"** once, copy from console). Skips expensive startup calculations; use for very complex morphs. Only for `\u003Cpath>` (convert polygon\u002Fpolyline first). |\n| **render** | Function(rawPath, target) called each update — e.g. draw to canvas. RawPath is an array of segments (each segment = array of alternating x,y cubic bezier coords). |\n| **updateTarget** | When using **render** (e.g. canvas-only), set **updateTarget: false** so the original `\u003Cpath>` is not updated. **MorphSVGPlugin.defaultUpdateTarget** sets default. |\n\n**Utilities:** **MorphSVGPlugin.convertToPath(selector | element)** converts circle\u002Frect\u002Fellipse\u002Fline\u002Fpolygon\u002Fpolyline to `\u003Cpath>` in the DOM. **MorphSVGPlugin.rawPathToString(rawPath)** and **stringToRawPath(d)** convert between path strings and raw arrays. The plugin stores the original `d` on the target (e.g. for tweening back: `morphSVG: \"#originalId\"` or the same element).\n\n**Tips:** For twisted or inverted morphs, set **shapeIndex** (use `\"log\"` or findShapeIndex()). For multi-segment paths, **shapeIndex** is an array (one value per segment). Precompile only when the first frame is slow; it does not fix jank during the tween (simplify the SVG or reduce size if needed).\n\n**Learn more:** [MorphSVG](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FMorphSVGPlugin)\n\n### MotionPath (MotionPathPlugin)\n\nAnimates an element along an SVG path. Use when moving an object along a path (e.g. a curve or custom route).\n\n```javascript\ngsap.registerPlugin(MotionPathPlugin);\n\ngsap.to(\".dot\", {\n  duration: 2,\n  motionPath: { path: \"#path\", align: \"#path\", alignOrigin: [0.5, 0.5] }\n});\n```\n\n**MotionPath — key config (motionPath object):**\n\n| Option | Description |\n|--------|-------------|\n| `path` | SVG path element, selector, or path data string |\n| `align` | Path element or selector to align the target to |\n| `alignOrigin` | `[x, y]` origin (0–1); default `[0.5, 0.5]` |\n| `autoRotate` | Rotate element to follow path tangent |\n| `curviness` | 0–2; path smoothing |\n\n### MotionPathHelper\n\nVisual editor for MotionPath (alignment, offset). Use during development to tune path alignment.\n\n```javascript\ngsap.registerPlugin(MotionPathPlugin, MotionPathHelperPlugin);\n\nconst helper = MotionPathHelper.create(\".dot\", \"#path\", { end: 0.5 });\n\u002F\u002F adjust in UI, then use helper.path or helper.getProgress() in your animation\n```\n\n## Easing\n\n### CustomEase\n\nCustom 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:\n\n```javascript\ngsap.registerPlugin(CustomEase);\nconst ease = CustomEase.create(\"name\", \".17,.67,.83,.67\");\ngsap.to(\".el\", { x: 100, ease: ease, duration: 1 });\n```\n\n### EasePack\n\nAdds more named eases (e.g. SlowMo, RoughEase, ExpoScaleEase). Register and use the ease names in tweens.\n\n### CustomWiggle\n\nWiggle\u002Fshake easing. Use when a value should “wiggle” (multiple oscillations).\n\n### CustomBounce\n\nBounce-style easing with configurable strength.\n\n## Physics\n\n### Physics2D (Physics2DPlugin)\n\n2D physics (velocity, angle, gravity). Use when animating with simple physics (e.g. projectiles, bouncing).\n\n```javascript\ngsap.registerPlugin(Physics2DPlugin);\n\ngsap.to(\".ball\", {\n  duration: 2,\n  physics2D: {\n    velocity: 250,\n    angle: 80,\n    gravity: 500\n  }\n});\n```\n\n### PhysicsProps (PhysicsPropsPlugin)\n\nApplies physics to property values. Use for physics-driven property animation.\n\n```javascript\ngsap.registerPlugin(PhysicsPropsPlugin);\n\ngsap.to(\".obj\", {\n  duration: 2,\n  physicsProps: {\n    x: { velocity: 100, end: 300 },\n    y: { velocity: -50, acceleration: 200 }\n  }\n});\n```\n\n## Development\n\n### GSDevTools\n\nUI for scrubbing timelines, toggling animations, and debugging. Use during development only; do not ship. Register and create an instance with a timeline reference.\n\n```javascript\ngsap.registerPlugin(GSDevTools);\nGSDevTools.create({ animation: tl });\n```\n\n## Other\n\n### Pixi (PixiPlugin)\n\nIntegrates GSAP with PixiJS for animating Pixi display objects. Register when animating Pixi objects with GSAP.\n\n```javascript\ngsap.registerPlugin(PixiPlugin);\n\nconst sprite = new PIXI.Sprite(texture);\ngsap.to(sprite, { pixi: { x: 200, y: 100, scale: 1.5 }, duration: 1 });\n```\n\n## Best practices\n\n- ✅ Register every plugin used with **gsap.registerPlugin()** before first use.\n- ✅ Use **Flip.getState()** → DOM change → **Flip.from()** for layout transitions; use **Draggable** + **InertiaPlugin** for drag with momentum.\n- ✅ Revert plugin instances (e.g. `SplitTextInstance.revert()`) when components unmount or elements are removed.\n\n## Do Not\n\n- ❌ Use a plugin in a tween or API without registering it first (**gsap.registerPlugin()**).\n- ❌ Ship GSDevTools or development-only plugins to production.\n\n### Learn More\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002F\n","# GSAP Plugins\n\n> Curated from GreenSock's official GSAP skills: https:\u002F\u002Fgithub.com\u002Fgreensock\u002Fgsap-skills\n\n## When to Use This Skill\n\nApply when using or reviewing code that uses GSAP plugins: registering plugins, scroll-to, flip\u002FFLIP 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).\n\n**Related skills:** For core tweens use **gsap-core**; for ScrollTrigger use **gsap-scrolltrigger**; for React use **gsap-react**.\n\n## Licensing & Install (important)\n\nEvery GSAP plugin is **free**, including for commercial use. Since [Webflow's acquisition of GSAP](https:\u002F\u002Fgsap.com\u002Fblog\u002Fwebflow-GSAP\u002F), Club GSAP is no longer a paid tier and **no plugin requires a membership, license key, or auth token** — this includes formerly Club-only plugins (**SplitText**, **MorphSVG**, etc.).\n\n- ✅ Install everything from the public `gsap` npm package: `npm install gsap`. All plugins are included — import them as `gsap\u002FSplitText`, `gsap\u002FMorphSVGPlugin`, etc.\n- ❌ Do **not** generate an `.npmrc` with a GreenSock auth token, suggest the private `npm.greensock.com` registry, or tell users to sign up for Club GSAP to access a plugin. Those instructions are outdated.\n\n## Registering Plugins\n\nRegister each plugin once so GSAP (and bundlers) know to include it. Use **gsap.registerPlugin()** with every plugin used in the project:\n\n```javascript\nimport gsap from \"gsap\";\nimport { ScrollToPlugin } from \"gsap\u002FScrollToPlugin\";\nimport { Flip } from \"gsap\u002FFlip\";\nimport { Draggable } from \"gsap\u002FDraggable\";\n\ngsap.registerPlugin(ScrollToPlugin, Flip, Draggable);\n```\n\n- ✅ Register before using the plugin in any tween or API call.\n- ✅ 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.\n\n## Scroll\n\n### ScrollToPlugin\n\nAnimates scroll position (window or a scrollable element). Use for “scroll to element” or “scroll to position” without ScrollTrigger.\n\n```javascript\ngsap.registerPlugin(ScrollToPlugin);\n\ngsap.to(window, { duration: 1, scrollTo: { y: 500 } });\ngsap.to(window, { duration: 1, scrollTo: { y: \"#section\", offsetY: 50 } });\ngsap.to(scrollContainer, { duration: 1, scrollTo: { x: \"max\" } });\n```\n\n**ScrollToPlugin — key config (scrollTo object):**\n\n| Option | Description |\n|--------|-------------|\n| `x`, `y` | Target scroll position (number), or `\"max\"` for maximum |\n| `element` | Selector or element to scroll to (for scroll-into-view) |\n| `offsetX`, `offsetY` | Offset in pixels from the target position |\n\n### ScrollSmoother\n\nSmooth 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: \n\n```html\n\u003Cbody>\n\t\u003Cdiv id=\"smooth-wrapper\">\n\t\t\u003Cdiv id=\"smooth-content\">\n\t\t\t\u003C!--- ALL YOUR CONTENT HERE --->\n\t\t\u003C\u002Fdiv>\n\t\u003C\u002Fdiv>\n\t\u003C!-- position: fixed elements can go outside --->\n\u003C\u002Fbody>\n```\n\n## DOM \u002F UI\n\n### Flip\n\nCapture 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\u002Fcollapsed).\n\n```javascript\ngsap.registerPlugin(Flip);\n\nconst state = Flip.getState(\".item\");\n\u002F\u002F change DOM (reorder, add\u002Fremove, change classes)\nFlip.from(state, { duration: 0.5, ease: \"power2.inOut\" });\n```\n\n**Flip — key config (Flip.from vars):**\n\n| Option | Description |\n|--------|-------------|\n| `absolute` | Use `position: absolute` during the flip (default: `false`) |\n| `nested` | When true, only the first level of children is measured (better for nested transforms) |\n| `scale` | When true, scale elements to fit (avoids stretch); default `true` |\n| `simple` | When true, only position\u002Fscale are animated (faster, less accurate) |\n| `duration`, `ease` | Standard tween options |\n\n#### More information\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FFlip\n\n### Draggable\n\nMakes elements draggable, spinnable, or throwable with mouse\u002Ftouch. Use for sliders, cards, reorderable lists, or any drag interaction.\n\n```javascript\ngsap.registerPlugin(Draggable, InertiaPlugin);\n\nDraggable.create(\".box\", { type: \"x,y\", bounds: \"#container\", inertia: true });\nDraggable.create(\".knob\", { type: \"rotation\" });\n```\n\n**Draggable — key config options:**\n\n| Option | Description |\n|--------|-------------|\n| `type` | `\"x\"`, `\"y\"`, `\"x,y\"`, `\"rotation\"`, `\"scroll\"` |\n| `bounds` | Element, selector, or `{ minX, maxX, minY, maxY }` to constrain drag |\n| `inertia` | `true` to enable throw\u002Fmomentum (requires InertiaPlugin) |\n| `edgeResistance` | 0–1; resistance when dragging past bounds |\n| `cursor` | CSS cursor during drag |\n| `onDragStart`, `onDrag`, `onDragEnd` | Callbacks; receive event and target |\n| `onThrowUpdate`, `onThrowComplete` | Callbacks when inertia is active |\n\n### Inertia (InertiaPlugin)\n\nWorks with Draggable for momentum after release, or track the inertia\u002Fvelocity 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`:\n\n```javascript\ngsap.registerPlugin(Draggable, InertiaPlugin);\nDraggable.create(\".box\", { type: \"x,y\", inertia: true });\n```\n\nOr track velocity of a property: \n```javascript\nInertiaPlugin.track(\".box\", \"x\");\n```\n\nThen use `\"auto\"` to continue the current velocity and glide to a stop: \n\n```javascript\ngsap.to(obj, { inertia: { x: \"auto\" } });\n```\n\n### Observer\n\nNormalizes pointer and scroll input across devices. Use for swipe, scroll direction, or custom gesture logic without tying directly to scroll position like ScrollTrigger.\n\n```javascript\ngsap.registerPlugin(Observer);\n\nObserver.create({\n  target: \"#area\",\n  onUp: () => {},\n  onDown: () => {},\n  onLeft: () => {},\n  onRight: () => {},\n  tolerance: 10\n});\n```\n\n**Observer — key config options:**\n\n| Option | Description |\n|--------|-------------|\n| `target` | Element or selector to observe |\n| `onUp`, `onDown`, `onLeft`, `onRight` | Callbacks when swipe\u002Fscroll passes tolerance in that direction |\n| `tolerance` | Pixels before direction is detected; default 10 |\n| `type` | `\"touch\"`, `\"pointer\"`, or `\"wheel\"` (default: `\"touch,pointer\"`) |\n\n## Text\n\n### SplitText\n\nSplits an element’s text into characters, words, and\u002For lines (each in its own element) for staggered or per-unit animation. Use when animating text character-by-character, word-by-word, or line-by-line. Returns an instance with **chars**, **words**, **lines** (and **masks** when `mask` is set). Restore original markup with **revert()** or let **gsap.context()** revert. Integrates with **gsap.context()**, **matchMedia()**, and **useGSAP()**. API: **SplitText.create(target, vars)** (target = selector, element, or array).\n\n```javascript\ngsap.registerPlugin(SplitText);\n\nconst split = SplitText.create(\".heading\", { type: \"words, chars\" });\ngsap.from(split.chars, { opacity: 0, y: 20, stagger: 0.03, duration: 0.4 });\n\u002F\u002F later: split.revert() or let gsap.context() cleanup revert\n```\n\nWith **onSplit()** (v3.13.0+), animations run on each split and on re-split when **autoSplit** is used; returning a tween\u002Ftimeline from **onSplit()** lets SplitText clean up and sync progress on re-split:\n\n```javascript\nSplitText.create(\".split\", {\n  type: \"lines\",\n  autoSplit: true,\n  onSplit(self) {\n    return gsap.from(self.lines, { y: 100, opacity: 0, stagger: 0.05, duration: 0.5 });\n  }\n});\n```\n\n**SplitText — key config (SplitText.create vars):**\n\n| Option | Description |\n|--------|-------------|\n| **type** | Comma-separated: `\"chars\"`, `\"words\"`, `\"lines\"`. Default `\"chars,words,lines\"`. Only split what is needed (e.g. `\"words, chars\"` if not using lines) for performance. Avoid chars-only without words\u002Flines or use **smartWrap: true** to prevent odd line breaks. |\n| **charsClass**, **wordsClass**, **linesClass** | CSS class on each split element. Append `\"++\"` to add an incremented class (e.g. `linesClass: \"line++\"` → `line1`, `line2`, …). |\n| **aria** | `\"auto\"` (default), `\"hidden\"`, or `\"none\"`. Accessibility: `\"auto\"` adds `aria-label` on the split element and `aria-hidden` on line\u002Fword\u002Fchar elements so screen readers read the label; `\"hidden\"` hides all from readers; `\"none\"` leaves aria unchanged. Use `\"none\"` plus a screen-reader-only duplicate if nested links\u002Fsemantics must be exposed. |\n| **autoSplit** | When `true`, reverts and re-splits when fonts finish loading or when the element width changes (and lines are split), avoiding wrong line breaks. **Animations must be created inside onSplit()** so they target the newly split elements; **return** the animation from **onSplit()** for automatic cleanup and time-sync on re-split. |\n| **onSplit(self)** | Callback when split completes (and on each re-split if **autoSplit** is `true`). Receives the SplitText instance. Returning a GSAP tween or timeline enables automatic revert\u002Fsync of that animation when re-splitting. |\n| **mask** | `\"lines\"`, `\"words\"`, or `\"chars\"`. Wraps each unit in an extra element with `overflow: clip` for mask\u002Freveal effects. Only one type; access wrappers on the instance’s **masks** array (or use class `-mask` if a class is set). |\n| **tag** | Wrapper element tag; default `\"div\"`. Use `\"span\"` for inline (note: transforms like rotation\u002Fscale may not render on inline elements in some browsers). |\n| **deepSlice** | When `true` (default), nested elements (e.g. `\u003Cstrong>`) that span multiple lines are subdivided so lines don’t stretch vertically. Only applies when splitting lines. |\n| **ignore** | Selector or element(s) to leave unsplit (e.g. `ignore: \"sup\"`). |\n| **smartWrap** | When splitting **chars** only, wraps words in a `white-space: nowrap` span to avoid mid-word line breaks. Ignored if words or lines are split. Default `false`. |\n| **wordDelimiter** | Word boundary: string (default `\" \"`), RegExp, or `{ delimiter: RegExp, replaceWith: string }` for custom splitting (e.g. zero-width joiner for hashtags, or non-Latin). |\n| **prepareText(text, parent)** | Function that receives raw text and parent element; return modified text before splitting (e.g. to insert break markers for languages without spaces). |\n| **propIndex** | When `true`, adds a CSS variable with index on each split element (e.g. `--word: 1`, `--char: 2`). |\n| **reduceWhiteSpace** | Collapse consecutive spaces; default `true`. From v3.13.0 also honors line breaks and can insert `\u003Cbr>` for `\u003Cpre>`. |\n| **onRevert** | Callback when the instance is reverted. |\n\n**Tips:** Split only what is animated (e.g. skip chars if only animating words). For custom fonts, split after they load (e.g. `document.fonts.ready.then(...)`) or use **autoSplit: true** with **onSplit()**. To avoid kerning shift when splitting chars, use CSS `font-kerning: none; text-rendering: optimizeSpeed;`. Avoid `text-wrap: balance`; it can interfere with splitting. SplitText does not support SVG `\u003Ctext>`.\n\n**Learn more:** [SplitText](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FSplitText\u002F)\n\n### ScrambleText\n\nAnimates text with a scramble\u002Fglitch effect. Use when revealing or transitioning text with a scramble.\n\n```javascript\ngsap.registerPlugin(ScrambleTextPlugin);\n\ngsap.to(\".text\", {\n  duration: 1,\n  scrambleText: { text: \"New message\", chars: \"01\", revealDelay: 0.5 }\n});\n```\n\n## SVG\n\n### DrawSVG (DrawSVGPlugin)\n\nReveals or hides the stroke of SVG elements by animating `stroke-dashoffset` \u002F `stroke-dasharray`. Works on `\u003Cpath>`, `\u003Cline>`, `\u003Cpolyline>`, `\u003Cpolygon>`, `\u003Crect>`, `\u003Cellipse>`. Use when “drawing” or “erasing” strokes.\n\n**drawSVG value:** Describes the **visible segment** of the stroke along the path (start and end positions), not “animate from A to B over time.” Format: `\"start end\"` in percent or length. Examples: `\"0% 100%\"` = full stroke; `\"20% 80%\"` = stroke only between 20% and 80% (gaps at both ends). The tween animates from the element’s **current** segment to the **target** segment — e.g. `gsap.to(\"#path\", { drawSVG: \"0% 100%\" })` goes from whatever it is now to full stroke. Single value (e.g. `0`, `\"100%\"`) means start is 0: `\"100%\"` is equivalent to `\"0% 100%\"`. \n\n**Required:** The element must have a visible stroke — set `stroke` and `stroke-width` in CSS or as SVG attributes; otherwise nothing is drawn.\n\n```javascript\ngsap.registerPlugin(DrawSVGPlugin);\n\n\u002F\u002F draw from nothing to full stroke\ngsap.from(\"#path\", { duration: 1, drawSVG: 0 });\n\u002F\u002F or explicit segment: from 0–0 to 0–100%\ngsap.fromTo(\"#path\", { drawSVG: \"0% 0%\" }, { drawSVG: \"0% 100%\", duration: 1 });\n\u002F\u002F stroke only in the middle (gaps at ends)\ngsap.to(\"#path\", { duration: 1, drawSVG: \"20% 80%\" });\n```\n\n**Caveats:** Only affects stroke (not fill). Prefer single-segment `\u003Cpath>` elements; multi-segment paths can render oddly in some browsers. Contents of `\u003Cuse>` cannot be visually changed. **DrawSVGPlugin.getLength(element)** and **DrawSVGPlugin.getPosition(element)** return stroke length and current position.\n\n**Learn more:** [DrawSVG](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FDrawSVGPlugin)\n\n### MorphSVG (MorphSVGPlugin)\n\nMorphs one SVG shape into another by animating the `d` attribute (path data). Start and end shapes do not need the same number of points — MorphSVG converts to cubic beziers and adds points as needed. Use for icon-to-icon morphs, shape transitions, or path-based animations. Works on `\u003Cpath>`, `\u003Cpolyline>`, and `\u003Cpolygon>`; `\u003Ccircle>`, `\u003Crect>`, `\u003Cellipse>`, and `\u003Cline>` are converted internally or via **MorphSVGPlugin.convertToPath(selector | element)** (replaces the element in the DOM with a `\u003Cpath>`).\n\n**morphSVG value:** Can be a **selector** (e.g. `\"#lightning\"`), an **element**, **raw path data** (e.g. `\"M47.1,0.8 73.3,0.8...\"`), or for polygon\u002Fpolyline a **points string** (e.g. `\"240,220 240,70 70,70 70,220\"`). For full config use the **object form** with **shape** as the only required property.\n\n```javascript\ngsap.registerPlugin(MorphSVGPlugin);\n\n\u002F\u002F convert primitives to path first if needed:\nMorphSVGPlugin.convertToPath(\"circle, rect, ellipse, line\");\n\ngsap.to(\"#diamond\", { duration: 1, morphSVG: \"#lightning\", ease: \"power2.inOut\" });\n\u002F\u002F object form:\ngsap.to(\"#diamond\", {\n  duration: 1,\n  morphSVG: { shape: \"#lightning\", type: \"rotational\", shapeIndex: 2 }\n});\n\n```\n\n**MorphSVG — key config (morphSVG object):**\n\n| Option | Description |\n|--------|-------------|\n| **shape** | _(Required.)_ Target shape: selector, element, or raw path string. |\n| **type** | `\"linear\"` (default) or `\"rotational\"`. Rotational uses angle\u002Flength interpolation and can avoid kinks mid-morph; try it when linear looks wrong. |\n| **map** | How segments are matched: `\"size\"` (default), `\"position\"`, or `\"complexity\"`. Use when start\u002Fend segments don’t line up; if none work, split into multiple paths and morph each. |\n| **shapeIndex** | Offsets which point in the start path maps to the first point in the end path (avoids shape “crossing over” or inverting). Number for single-segment paths; **array** for multi-segment (e.g. `[5, 1, -8]`). Negative reverses that segment. Use **shapeIndex: \"log\"** once to log the auto-calculated value, then paste the number\u002Farray into the tween. **findShapeIndex(start, end)** (separate utility) provides an interactive UI to find a good value. Only applies to closed paths. |\n| **smooth** | (v3.14+). Adds smoothing points. Number (e.g. `80`), `\"auto\"`, or object: `{ points: 40 \\| \"auto\", redraw: true \\| false, persist: true \\| false }`. `redraw: false` keeps original anchors (perfect fidelity, less even spacing). `persist: false` removes added points when the tween ends. Use when the default morph looks jagged or unnatural. |\n| **curveMode** | Boolean (v3.14+). Interpolates control-handle angle\u002Flength instead of raw x\u002Fy to avoid kinks on curves. Try if a morph has a mid-morph kink. |\n| **origin** | Rotation origin for **type: \"rotational\"**. String: `\"50% 50%\"` (default) or `\"20% 60%, 35% 90%\"` for different start\u002Fend origins. |\n| **precision** | Decimal places for output path data; default `2`. |\n| **precompile** | Array of precomputed path strings (or use **precompile: \"log\"** once, copy from console). Skips expensive startup calculations; use for very complex morphs. Only for `\u003Cpath>` (convert polygon\u002Fpolyline first). |\n| **render** | Function(rawPath, target) called each update — e.g. draw to canvas. RawPath is an array of segments (each segment = array of alternating x,y cubic bezier coords). |\n| **updateTarget** | When using **render** (e.g. canvas-only), set **updateTarget: false** so the original `\u003Cpath>` is not updated. **MorphSVGPlugin.defaultUpdateTarget** sets default. |\n\n**Utilities:** **MorphSVGPlugin.convertToPath(selector | element)** converts circle\u002Frect\u002Fellipse\u002Fline\u002Fpolygon\u002Fpolyline to `\u003Cpath>` in the DOM. **MorphSVGPlugin.rawPathToString(rawPath)** and **stringToRawPath(d)** convert between path strings and raw arrays. The plugin stores the original `d` on the target (e.g. for tweening back: `morphSVG: \"#originalId\"` or the same element).\n\n**Tips:** For twisted or inverted morphs, set **shapeIndex** (use `\"log\"` or findShapeIndex()). For multi-segment paths, **shapeIndex** is an array (one value per segment). Precompile only when the first frame is slow; it does not fix jank during the tween (simplify the SVG or reduce size if needed).\n\n**Learn more:** [MorphSVG](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002FMorphSVGPlugin)\n\n### MotionPath (MotionPathPlugin)\n\nAnimates an element along an SVG path. Use when moving an object along a path (e.g. a curve or custom route).\n\n```javascript\ngsap.registerPlugin(MotionPathPlugin);\n\ngsap.to(\".dot\", {\n  duration: 2,\n  motionPath: { path: \"#path\", align: \"#path\", alignOrigin: [0.5, 0.5] }\n});\n```\n\n**MotionPath — key config (motionPath object):**\n\n| Option | Description |\n|--------|-------------|\n| `path` | SVG path element, selector, or path data string |\n| `align` | Path element or selector to align the target to |\n| `alignOrigin` | `[x, y]` origin (0–1); default `[0.5, 0.5]` |\n| `autoRotate` | Rotate element to follow path tangent |\n| `curviness` | 0–2; path smoothing |\n\n### MotionPathHelper\n\nVisual editor for MotionPath (alignment, offset). Use during development to tune path alignment.\n\n```javascript\ngsap.registerPlugin(MotionPathPlugin, MotionPathHelperPlugin);\n\nconst helper = MotionPathHelper.create(\".dot\", \"#path\", { end: 0.5 });\n\u002F\u002F adjust in UI, then use helper.path or helper.getProgress() in your animation\n```\n\n## Easing\n\n### CustomEase\n\nCustom 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:\n\n```javascript\ngsap.registerPlugin(CustomEase);\nconst ease = CustomEase.create(\"name\", \".17,.67,.83,.67\");\ngsap.to(\".el\", { x: 100, ease: ease, duration: 1 });\n```\n\n### EasePack\n\nAdds more named eases (e.g. SlowMo, RoughEase, ExpoScaleEase). Register and use the ease names in tweens.\n\n### CustomWiggle\n\nWiggle\u002Fshake easing. Use when a value should “wiggle” (multiple oscillations).\n\n### CustomBounce\n\nBounce-style easing with configurable strength.\n\n## Physics\n\n### Physics2D (Physics2DPlugin)\n\n2D physics (velocity, angle, gravity). Use when animating with simple physics (e.g. projectiles, bouncing).\n\n```javascript\ngsap.registerPlugin(Physics2DPlugin);\n\ngsap.to(\".ball\", {\n  duration: 2,\n  physics2D: {\n    velocity: 250,\n    angle: 80,\n    gravity: 500\n  }\n});\n```\n\n### PhysicsProps (PhysicsPropsPlugin)\n\nApplies physics to property values. Use for physics-driven property animation.\n\n```javascript\ngsap.registerPlugin(PhysicsPropsPlugin);\n\ngsap.to(\".obj\", {\n  duration: 2,\n  physicsProps: {\n    x: { velocity: 100, end: 300 },\n    y: { velocity: -50, acceleration: 200 }\n  }\n});\n```\n\n## Development\n\n### GSDevTools\n\nUI for scrubbing timelines, toggling animations, and debugging. Use during development only; do not ship. Register and create an instance with a timeline reference.\n\n```javascript\ngsap.registerPlugin(GSDevTools);\nGSDevTools.create({ animation: tl });\n```\n\n## Other\n\n### Pixi (PixiPlugin)\n\nIntegrates GSAP with PixiJS for animating Pixi display objects. Register when animating Pixi objects with GSAP.\n\n```javascript\ngsap.registerPlugin(PixiPlugin);\n\nconst sprite = new PIXI.Sprite(texture);\ngsap.to(sprite, { pixi: { x: 200, y: 100, scale: 1.5 }, duration: 1 });\n```\n\n## Best practices\n\n- ✅ Register every plugin used with **gsap.registerPlugin()** before first use.\n- ✅ Use **Flip.getState()** → DOM change → **Flip.from()** for layout transitions; use **Draggable** + **InertiaPlugin** for drag with momentum.\n- ✅ Revert plugin instances (e.g. `SplitTextInstance.revert()`) when components unmount or elements are removed.\n\n## Do Not\n\n- ❌ Use a plugin in a tween or API without registering it first (**gsap.registerPlugin()**).\n- ❌ Ship GSDevTools or development-only plugins to production.\n\n### Learn More\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FPlugins\u002F\n",{"od":51,"name":5,"license":14,"triggers":54,"description":60},{"mode":45,"category":52,"upstream":53},"animation-motion","https:\u002F\u002Fgithub.com\u002Fgreensock\u002Fgsap-skills",[24,55,56,57,58,59],"gsap plugin registration","flip animation","draggable","morphsvg","splittext","Official GSAP skill for GSAP plugins — 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.\n","main","f19b254e8975d0bfddb394686706106930d7964d","Web-Design\u002Ffrontend-and-motion-implementation\u002Fopen-design-gsap-plugins","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus","https:\u002F\u002Fgithub.com\u002Fendman100","2026-11-12 18:13:37",{"source":8,"skillName":5,"commands":68,"prompt":78,"zipAvailable":79},[69,72,75],{"tool":70,"command":71},"npx","npx skills add endman100\u002Fskill-router-nexus --skill gsap-plugins",{"tool":73,"command":74},"bunx","bunx skills add endman100\u002Fskill-router-nexus --skill gsap-plugins",{"tool":76,"command":77},"pnpm","pnpm dlx skills add endman100\u002Fskill-router-nexus --skill gsap-plugins","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWeb-Design\u002Ffrontend-and-motion-implementation\u002Fopen-design-gsap-plugins\u002FSKILL.md",true,[],[82,106,140,161,170,194],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":86,"sourceHtmlUrl":87,"categories":88,"keywords":94,"publishedAt":46},"01M6MPCT5BXVER8HQZTW3QE9AS","create-master","基于佛教经典文献，生成特定高僧大德的 AI 教学角色","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FMetaphysics-and-Spirituality\u002FMaster-skill\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FMetaphysics-and-Spirituality\u002FMaster-skill\u002FSKILL.md",[89],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000039","教师与教育","PROFESSION","适用职业",[95,96,97,98,99,100,101,102,103,104,105],"create master","master","create","生成","true","webfetch","edit","write","read","grep","Bash",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":110,"sourceHtmlUrl":111,"categories":112,"keywords":122,"publishedAt":46},"01M6M43AKE95Y64E1JRXEF5QQ3","writing-dna-skill","从至少 20 篇完整文章中蒸馏可复用的写作 DNA，分析语言、文章结构、选题逻辑、素材策略、认知框架和视觉风格，并生成 Writing-DNA.md；按该 DNA 写作时会读取全部蒸馏产物和 5 篇相关原文。用于中英文作者、账号、品牌或出版物的风格分析与一致性写作。 Distill reusable Writing DNA from at least 20 complete articles for Chinese or English authors, publications, brands, and accounts; use for language, structure, topic logic, source strategy, cognitive-frame, and visual-style analysis.","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fwriting-dna-skill\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fwriting-dna-skill\u002FSKILL.md",[113,116,119],{"categoryNo":114,"categoryName":115,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":117,"categoryName":118,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":120,"categoryName":121,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000036","内容创作者",[123,124,125,126,127,128,129,130,131,132,39,133,134,98,135,136,137,30,138,139],"writing dna skill","DNA","writing","strategy","english","logic","visual","structure","chinese","reusable","style","distill","analysis","frame","source","at","complete",{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":144,"sourceHtmlUrl":145,"categories":146,"keywords":149,"publishedAt":46},"01M6M428TTCGQ4ME3KY99VN037","stop-slop","Remove AI writing patterns from prose. Use when drafting, editing, or reviewing text to eliminate predictable AI tells.","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fstop-slop\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fstop-slop\u002FSKILL.md",[147,148],{"categoryNo":114,"categoryName":115,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":120,"categoryName":121,"taxonomyType":92,"taxonomyTypeDesc":93},[150,151,152,153,27,154,42,155,156,39,157,158,159,30,160,125],"slop","stop slop","stop","drafting","drafts","patterns","prose","remove","editing","text","content",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":165,"sourceHtmlUrl":166,"categories":167,"keywords":168,"publishedAt":46},"01M6M41X0B7EBX42TK435DMGGR","shuorenhua","检查和清理中英文文本里的 AI 套路，适用于“去 AI 味”“说人话”“自然一点”“别像模板”“先标问题”这类改写和审稿需求；按场景控制力度，同时保留事实、术语、语域和责任主体。","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fshuorenhua\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fshuorenhua\u002FSKILL.md",[],[163,169],"文本",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":174,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":46},"01M6M3ZD12WBEW5KXKDM4N6DFG","naming","Name products, SaaS, brands, open source projects, bots, and apps. Use when the user needs to name something, find a brand name, or pick a product name. Metaphor-driven process that produces memorable, meaningful names and avoids AI slop.","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fnaming-main\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fnaming-main\u002FSKILL.md",[],[172,178,179,180,181,182,39,183,103,137,184,185,186,187,105,188,189,190,191,27,192,193,150],"repo","websearch","product name","apps","bots","view","brand","pick","gh","projects","open","saas","open source","product","describe","ai slop",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":198,"sourceHtmlUrl":199,"categories":200,"keywords":202,"publishedAt":46},"01M6M3YVXAFAAWJ7F6JMPFREYE","humanizer-zh","去除文本中的 AI 生成痕迹。适用于编辑或审阅文本，使其听起来更自然、更像人类书写。\n基于维基百科的\"AI 写作特征\"综合指南。检测并修复以下模式：夸大的象征意义、\n宣传性语言、以 -ing 结尾的肤浅分析、模糊的归因、破折号过度使用、三段式法则、\nAI 词汇、否定式排比、过多的连接性短语。","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fhumanizer-zh\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fendman100\u002Fskill-router-nexus\u002Fblob\u002Fmain\u002FWriting-and-Content\u002Fhumanizer-zh\u002FSKILL.md",[201],{"categoryNo":114,"categoryName":115,"taxonomyType":20,"taxonomyTypeDesc":21},[203,204,205,103,102,101,125,98,169,206,150,152],"humanizer","zh","humanizer zh","翻译"]