[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JGSXYMP0KAZERGPTEGXVN7":3,"skill-same:01M6JGSXYMP0KAZERGPTEGXVN7":62},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":34,"linkOnly":35,"markdownContent":36,"markdownBody":37,"frontMatter":38,"refName":39,"commitSha":40,"skillDirectory":41,"forksCount":42,"repositoryHtmlUrl":43,"repositoryHomepageUrl":44,"ownerHtmlUrl":45,"ownerBlogUrl":6,"ownerDescription":46,"updatedAt":47,"install":48,"resources":61},"01M6JGSXYMP0KAZERGPTEGXVN7","gsap-utils",null,"Official GSAP skill for gsap.utils — clamp, mapRange, normalize, interpolate, random, snap, toArray, wrap, pipe. Use when the user asks about gsap.utils, clamp, mapRange, random, snap, toArray, wrap, or helper utilities in GSAP.","ancyloce\u002Fanvilkit-studio","ancyloce","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F103255835?v=4","01M6JGS0GSF9KTQE3VS6HA5FZ2","Ancyloce","01M6JGS0NK83XM8EJYT39C39CD",2,"MIT","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fgsap-utils\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33],"gsap","utils","gsap utils","official","user","use","wrap","pipe","normalize","helper","Utilities","about","random","snap","for","2026-11-10 10:12:30",false,"---\nname: gsap-utils\ndescription: Official GSAP skill for gsap.utils — clamp, mapRange, normalize, interpolate, random, snap, toArray, wrap, pipe. Use when the user asks about gsap.utils, clamp, mapRange, random, snap, toArray, wrap, or helper utilities in GSAP.\nlicense: MIT\n---\n\n# gsap.utils\n\n## When to Use This Skill\n\nApply when writing or reviewing code that uses **gsap.utils** for math, array\u002Fcollection handling, unit parsing, or value mapping in animations (e.g. mapping scroll to a value, randomizing, snapping to a grid, or normalizing inputs).\n\n**Related skills:** Use with **gsap-core**, **gsap-timeline**, and **gsap-scrolltrigger** when building animations; CustomEase and other easing utilities are in **gsap-plugins**.\n\n## Overview\n\n**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()`).\n\n**Omitting the value: function form.** Many utils accept the value to transform as the **last** argument. If you omit that argument, the util returns a **function** that accepts the value later. Use the function form when you need to clamp, map, normalize, or snap many values with the same config (e.g. in a mousemove handler or tween callback). **Exception: random()** — pass **true** as the last argument to get a reusable function (do not omit the value); see [random()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002Frandom()).\n\n```javascript\n\u002F\u002F With value: returns the result\ngsap.utils.clamp(0, 100, 150); \u002F\u002F 100\n\n\u002F\u002F Without value: returns a function you call with the value later\nlet c = gsap.utils.clamp(0, 100);\nc(150);  \u002F\u002F 100\nc(-10);  \u002F\u002F 0\n```\n\n## Clamping and Ranges\n\n### clamp(min, max, value?)\n\nConstrains a value between min and max. Omit **value** to get a function: `clamp(min, max)(value)`.\n\n```javascript\ngsap.utils.clamp(0, 100, 150); \u002F\u002F 100\ngsap.utils.clamp(0, 100, -10); \u002F\u002F 0\n\nlet clampFn = gsap.utils.clamp(0, 100);\nclampFn(150); \u002F\u002F 100\n```\n\n### mapRange(inMin, inMax, outMin, outMax, value?)\n\nMaps a value from one range to another. Use when converting scroll position, progress (0–1), or input range to an animation range. Omit **value** to get a function: `mapRange(inMin, inMax, outMin, outMax)(value)`.\n\n```javascript\ngsap.utils.mapRange(0, 100, 0, 500, 50);  \u002F\u002F 250\ngsap.utils.mapRange(0, 1, 0, 360, 0.5);   \u002F\u002F 180 (progress to degrees)\n\nlet mapFn = gsap.utils.mapRange(0, 100, 0, 500);\nmapFn(50);  \u002F\u002F 250\n```\n\n### normalize(min, max, value?)\n\nReturns a value normalized to 0–1 for the given range. Inverse of mapping when the target range is 0–1. Omit **value** to get a function: `normalize(min, max)(value)`.\n\n```javascript\ngsap.utils.normalize(0, 100, 50);   \u002F\u002F 0.5\ngsap.utils.normalize(100, 300, 200); \u002F\u002F 0.5\n\nlet normFn = gsap.utils.normalize(0, 100);\nnormFn(50); \u002F\u002F 0.5\n```\n\n### interpolate(start, end, progress?)\n\nInterpolates between two values at a given progress (0–1). Handles numbers, colors, and objects with matching keys. Omit **progress** to get a function: `interpolate(start, end)(progress)`.\n\n```javascript\ngsap.utils.interpolate(0, 100, 0.5);       \u002F\u002F 50\ngsap.utils.interpolate(\"#ff0000\", \"#0000ff\", 0.5); \u002F\u002F mid color\ngsap.utils.interpolate({ x: 0, y: 0 }, { x: 100, y: 50 }, 0.5); \u002F\u002F { x: 50, y: 25 }\n\nlet lerp = gsap.utils.interpolate(0, 100);\nlerp(0.5); \u002F\u002F 50\n```\n\n## Random and Snap\n\n### random(minimum, maximum[, snapIncrement, returnFunction]) \u002F random(array[, returnFunction])\n\nReturns a random number in the range **minimum**–**maximum**, or a random element from an **array**. Optional **snapIncrement** snaps the result to the nearest multiple (e.g. `5` → multiples of 5). **To get a reusable function**, pass **true** as the last argument (**returnFunction**); the returned function takes no args and returns a new random value each time. This is the only util that uses `true` for the function form instead of omitting the value.\n\n```javascript\n\u002F\u002F immediate value: number in range\ngsap.utils.random(-100, 100);        \u002F\u002F e.g. 42.7\ngsap.utils.random(0, 500, 5);        \u002F\u002F 0–500, snapped to nearest 5\n\n\u002F\u002F reusable function: pass true as last argument\nlet randomFn = gsap.utils.random(-200, 500, 10, true);\nrandomFn();  \u002F\u002F random value in range, snapped to 10\nrandomFn();  \u002F\u002F another random value\n\n\u002F\u002F array: pick one value at random\ngsap.utils.random([\"red\", \"blue\", \"green\"]);  \u002F\u002F \"red\", \"blue\", or \"green\"\nlet randomFromArray = gsap.utils.random([0, 100, 200], true);\nrandomFromArray();  \u002F\u002F 0, 100, or 200\n```\n\n**String form in tween vars:** use `\"random(-100, 100)\"`, `\"random(-100, 100, 5)\"`, or `\"random([0, 100, 200])\"`; GSAP evaluates it per target.\n\n```javascript\ngsap.to(\".box\", { x: \"random(-100, 100, 5)\", duration: 1 });\ngsap.to(\".item\", { backgroundColor: \"random([red, blue, green])\" });\n```\n\n### snap(snapTo, value?)\n\nSnaps a value to the nearest multiple of **snapTo**, or to the nearest value in an array of allowed values. Omit **value** to get a function: `snap(snapTo)(value)` (or `snap(snapArray)(value)`).\n\n```javascript\ngsap.utils.snap(10, 23);     \u002F\u002F 20\ngsap.utils.snap(0.25, 0.7);  \u002F\u002F 0.75\ngsap.utils.snap([0, 100, 200], 150); \u002F\u002F 100 or 200 (nearest in array)\n\nlet snapFn = gsap.utils.snap(10);\nsnapFn(23); \u002F\u002F 20\n```\n\nUse in tweens for grid or step-based animation:\n\n```javascript\ngsap.to(\".x\", { x: 200, snap: { x: 20 } });\n```\n\n### shuffle(array)\n\nReturns a new array with the same elements in random order. Use for randomizing order (e.g. stagger from \"random\" with a copy).\n\n```javascript\ngsap.utils.shuffle([1, 2, 3, 4]); \u002F\u002F e.g. [3, 1, 4, 2]\n```\n\n### distribute(config)\n\n**Returns a function** that assigns a value to each target based on its position in the array (or in a grid). Used internally for advanced staggers; use it whenever you need values spread across many elements (e.g. scale, opacity, x, delay). The returned function receives `(index, target, targets)` — either call it manually or pass the result directly into a tween; GSAP will call it per target with index, element, and array.\n\n**Config (all optional):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `base` | Number | Starting value. Default `0`. |\n| `amount` | Number | Total to distribute across all targets (added to base). E.g. `amount: 1` with 100 targets → 0.01 between each. Use **each** instead to set a fixed step per target. |\n| `each` | Number | Amount to add between each target (added to base). E.g. `each: 1` with 4 targets → 0, 1, 2, 3. Use **amount** instead to split a total. |\n| `from` | Number \\| String \\| Array | Where distribution starts: index, or `\"start\"`, `\"center\"`, `\"edges\"`, `\"random\"`, `\"end\"`, or ratios like `[0.25, 0.75]`. Default `0`. |\n| `grid` | String \\| Array | Use grid position instead of flat index: `[rows, columns]` (e.g. `[5, 10]`) or `\"auto\"` to detect. Omit for flat array. |\n| `axis` | String | For grid: limit to one axis (`\"x\"` or `\"y\"`). |\n| `ease` | Ease | Distribute values along an ease curve (e.g. `\"power1.inOut\"`). Default `\"none\"`. |\n\n**In a tween:** pass the result of `distribute(config)` as the property value; GSAP calls the function for each target with `(index, target, targets)`.\n\n```javascript\n\u002F\u002F Scale: middle elements 0.5, outer edges 3 (amount 2.5 distributed from center)\ngsap.to(\".class\", {\n  scale: gsap.utils.distribute({\n    base: 0.5,\n    amount: 2.5,\n    from: \"center\"\n  })\n});\n```\n\n**Manual use:** call the returned function with `(index, target, targets)` to get the value for that index.\n\n```javascript\nconst distributor = gsap.utils.distribute({\n  base: 50,\n  amount: 100,\n  from: \"center\",\n  ease: \"power1.inOut\"\n});\nconst targets = gsap.utils.toArray(\".box\");\nconst valueForIndex2 = distributor(2, targets[2], targets);\n```\n\nSee [distribute()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002Fdistribute\u002F) for more.\n\n## Units and Parsing\n\n### getUnit(value)\n\nReturns the unit string of a value (e.g. `\"px\"`, `\"%\"`, `\"deg\"`). Use when normalizing or converting values.\n\n```javascript\ngsap.utils.getUnit(\"100px\");   \u002F\u002F \"px\"\ngsap.utils.getUnit(\"50%\");     \u002F\u002F \"%\"\ngsap.utils.getUnit(42);        \u002F\u002F \"\" (unitless)\n```\n\n### unitize(value, unit)\n\nAppends 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.\n\n```javascript\ngsap.utils.unitize(100, \"px\");  \u002F\u002F \"100px\"\ngsap.utils.unitize(\"2rem\", \"px\"); \u002F\u002F \"2rem\" (unchanged)\n```\n\n### splitColor(color, returnHSL?)\n\nConverts a color string into an array: **[red, green, blue]** (0–255), or **[red, green, blue, alpha]** (4 elements for RGBA when alpha is present or required). Pass **true** as the second argument (**returnHSL**) to get **[hue, saturation, lightness]** or **[hue, saturation, lightness, alpha]** (HSL\u002FHSLA) instead. Works with `\"rgb()\"`, `\"rgba()\"`, `\"hsl()\"`, `\"hsla()\"`, hex, and named colors (e.g. `\"red\"`). Use when animating color components or building gradients. See [splitColor()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002FsplitColor\u002F).\n\n```javascript\ngsap.utils.splitColor(\"red\");                    \u002F\u002F [255, 0, 0]\ngsap.utils.splitColor(\"#6fb936\");                \u002F\u002F [111, 185, 54]\ngsap.utils.splitColor(\"rgba(204, 153, 51, 0.5)\"); \u002F\u002F [204, 153, 51, 0.5] (4 elements)\ngsap.utils.splitColor(\"#6fb936\", true);          \u002F\u002F [94, 55, 47] (HSL: hue, saturation, lightness)\n```\n\n## Arrays and Collections\n\n### selector(scope)\n\nReturns 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`).\n\n```javascript\nconst q = gsap.utils.selector(containerRef);\nq(\".box\");        \u002F\u002F array of .box elements inside container\ngsap.to(q(\".circle\"), { x: 100 });\n```\n\n### toArray(value, scope?)\n\nConverts 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.\n\n```javascript\ngsap.utils.toArray(\".item\");           \u002F\u002F array of elements\ngsap.utils.toArray(\".item\", container); \u002F\u002F scoped to container\ngsap.utils.toArray(nodeList);          \u002F\u002F [ ... ] from NodeList\n```\n\n### pipe(...functions)\n\nComposes 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.\n\n```javascript\nconst fn = gsap.utils.pipe(\n  (v) => gsap.utils.normalize(0, 100, v),\n  (v) => gsap.utils.snap(0.1, v)\n);\nfn(50); \u002F\u002F normalized then snapped\n```\n\n### wrap(min, max, value?)\n\nWraps a value into the range min–max (inclusive min, exclusive max). Use for infinite scroll or cyclic values. Omit **value** to get a function: `wrap(min, max)(value)`.\n\n```javascript\ngsap.utils.wrap(0, 360, 370);  \u002F\u002F 10\ngsap.utils.wrap(0, 360, -10);   \u002F\u002F 350\n\nlet wrapFn = gsap.utils.wrap(0, 360);\nwrapFn(370); \u002F\u002F 10\n```\n\n### wrapYoyo(min, max, value?)\n\nWraps value in range with a yoyo (bounces at ends). Use for back-and-forth within a range. Omit **value** to get a function: `wrapYoyo(min, max)(value)`.\n\n```javascript\ngsap.utils.wrapYoyo(0, 100, 150); \u002F\u002F 50 (bounces back)\n\nlet wrapY = gsap.utils.wrapYoyo(0, 100);\nwrapY(150); \u002F\u002F 50\n```\n\n## Best practices\n\n- ✅ Omit the value argument to get a reusable function when the same range\u002Fconfig is used many times (e.g. scroll handler, tween callback): `let mapFn = gsap.utils.mapRange(0, 1, 0, 360); mapFn(progress)`.\n- ✅ Use **snap** for grid-aligned or step-based values; use **toArray** when GSAP or your code needs a real array from a selector or NodeList.\n- ✅ Use **gsap.utils.selector(scope)** in components so selectors are scoped to a container or ref.\n\n## Do Not\n\n- ❌ Assume **mapRange** \u002F **normalize** handle units; they work on numbers. Use **getUnit** \u002F **unitize** when units matter.\n- ❌ Override or rely on undocumented behavior; stick to the documented API.\n\n### Learn More\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FHelperFunctions\n","# gsap.utils\n\n## When to Use This Skill\n\nApply when writing or reviewing code that uses **gsap.utils** for math, array\u002Fcollection handling, unit parsing, or value mapping in animations (e.g. mapping scroll to a value, randomizing, snapping to a grid, or normalizing inputs).\n\n**Related skills:** Use with **gsap-core**, **gsap-timeline**, and **gsap-scrolltrigger** when building animations; CustomEase and other easing utilities are in **gsap-plugins**.\n\n## Overview\n\n**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()`).\n\n**Omitting the value: function form.** Many utils accept the value to transform as the **last** argument. If you omit that argument, the util returns a **function** that accepts the value later. Use the function form when you need to clamp, map, normalize, or snap many values with the same config (e.g. in a mousemove handler or tween callback). **Exception: random()** — pass **true** as the last argument to get a reusable function (do not omit the value); see [random()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002Frandom()).\n\n```javascript\n\u002F\u002F With value: returns the result\ngsap.utils.clamp(0, 100, 150); \u002F\u002F 100\n\n\u002F\u002F Without value: returns a function you call with the value later\nlet c = gsap.utils.clamp(0, 100);\nc(150);  \u002F\u002F 100\nc(-10);  \u002F\u002F 0\n```\n\n## Clamping and Ranges\n\n### clamp(min, max, value?)\n\nConstrains a value between min and max. Omit **value** to get a function: `clamp(min, max)(value)`.\n\n```javascript\ngsap.utils.clamp(0, 100, 150); \u002F\u002F 100\ngsap.utils.clamp(0, 100, -10); \u002F\u002F 0\n\nlet clampFn = gsap.utils.clamp(0, 100);\nclampFn(150); \u002F\u002F 100\n```\n\n### mapRange(inMin, inMax, outMin, outMax, value?)\n\nMaps a value from one range to another. Use when converting scroll position, progress (0–1), or input range to an animation range. Omit **value** to get a function: `mapRange(inMin, inMax, outMin, outMax)(value)`.\n\n```javascript\ngsap.utils.mapRange(0, 100, 0, 500, 50);  \u002F\u002F 250\ngsap.utils.mapRange(0, 1, 0, 360, 0.5);   \u002F\u002F 180 (progress to degrees)\n\nlet mapFn = gsap.utils.mapRange(0, 100, 0, 500);\nmapFn(50);  \u002F\u002F 250\n```\n\n### normalize(min, max, value?)\n\nReturns a value normalized to 0–1 for the given range. Inverse of mapping when the target range is 0–1. Omit **value** to get a function: `normalize(min, max)(value)`.\n\n```javascript\ngsap.utils.normalize(0, 100, 50);   \u002F\u002F 0.5\ngsap.utils.normalize(100, 300, 200); \u002F\u002F 0.5\n\nlet normFn = gsap.utils.normalize(0, 100);\nnormFn(50); \u002F\u002F 0.5\n```\n\n### interpolate(start, end, progress?)\n\nInterpolates between two values at a given progress (0–1). Handles numbers, colors, and objects with matching keys. Omit **progress** to get a function: `interpolate(start, end)(progress)`.\n\n```javascript\ngsap.utils.interpolate(0, 100, 0.5);       \u002F\u002F 50\ngsap.utils.interpolate(\"#ff0000\", \"#0000ff\", 0.5); \u002F\u002F mid color\ngsap.utils.interpolate({ x: 0, y: 0 }, { x: 100, y: 50 }, 0.5); \u002F\u002F { x: 50, y: 25 }\n\nlet lerp = gsap.utils.interpolate(0, 100);\nlerp(0.5); \u002F\u002F 50\n```\n\n## Random and Snap\n\n### random(minimum, maximum[, snapIncrement, returnFunction]) \u002F random(array[, returnFunction])\n\nReturns a random number in the range **minimum**–**maximum**, or a random element from an **array**. Optional **snapIncrement** snaps the result to the nearest multiple (e.g. `5` → multiples of 5). **To get a reusable function**, pass **true** as the last argument (**returnFunction**); the returned function takes no args and returns a new random value each time. This is the only util that uses `true` for the function form instead of omitting the value.\n\n```javascript\n\u002F\u002F immediate value: number in range\ngsap.utils.random(-100, 100);        \u002F\u002F e.g. 42.7\ngsap.utils.random(0, 500, 5);        \u002F\u002F 0–500, snapped to nearest 5\n\n\u002F\u002F reusable function: pass true as last argument\nlet randomFn = gsap.utils.random(-200, 500, 10, true);\nrandomFn();  \u002F\u002F random value in range, snapped to 10\nrandomFn();  \u002F\u002F another random value\n\n\u002F\u002F array: pick one value at random\ngsap.utils.random([\"red\", \"blue\", \"green\"]);  \u002F\u002F \"red\", \"blue\", or \"green\"\nlet randomFromArray = gsap.utils.random([0, 100, 200], true);\nrandomFromArray();  \u002F\u002F 0, 100, or 200\n```\n\n**String form in tween vars:** use `\"random(-100, 100)\"`, `\"random(-100, 100, 5)\"`, or `\"random([0, 100, 200])\"`; GSAP evaluates it per target.\n\n```javascript\ngsap.to(\".box\", { x: \"random(-100, 100, 5)\", duration: 1 });\ngsap.to(\".item\", { backgroundColor: \"random([red, blue, green])\" });\n```\n\n### snap(snapTo, value?)\n\nSnaps a value to the nearest multiple of **snapTo**, or to the nearest value in an array of allowed values. Omit **value** to get a function: `snap(snapTo)(value)` (or `snap(snapArray)(value)`).\n\n```javascript\ngsap.utils.snap(10, 23);     \u002F\u002F 20\ngsap.utils.snap(0.25, 0.7);  \u002F\u002F 0.75\ngsap.utils.snap([0, 100, 200], 150); \u002F\u002F 100 or 200 (nearest in array)\n\nlet snapFn = gsap.utils.snap(10);\nsnapFn(23); \u002F\u002F 20\n```\n\nUse in tweens for grid or step-based animation:\n\n```javascript\ngsap.to(\".x\", { x: 200, snap: { x: 20 } });\n```\n\n### shuffle(array)\n\nReturns a new array with the same elements in random order. Use for randomizing order (e.g. stagger from \"random\" with a copy).\n\n```javascript\ngsap.utils.shuffle([1, 2, 3, 4]); \u002F\u002F e.g. [3, 1, 4, 2]\n```\n\n### distribute(config)\n\n**Returns a function** that assigns a value to each target based on its position in the array (or in a grid). Used internally for advanced staggers; use it whenever you need values spread across many elements (e.g. scale, opacity, x, delay). The returned function receives `(index, target, targets)` — either call it manually or pass the result directly into a tween; GSAP will call it per target with index, element, and array.\n\n**Config (all optional):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `base` | Number | Starting value. Default `0`. |\n| `amount` | Number | Total to distribute across all targets (added to base). E.g. `amount: 1` with 100 targets → 0.01 between each. Use **each** instead to set a fixed step per target. |\n| `each` | Number | Amount to add between each target (added to base). E.g. `each: 1` with 4 targets → 0, 1, 2, 3. Use **amount** instead to split a total. |\n| `from` | Number \\| String \\| Array | Where distribution starts: index, or `\"start\"`, `\"center\"`, `\"edges\"`, `\"random\"`, `\"end\"`, or ratios like `[0.25, 0.75]`. Default `0`. |\n| `grid` | String \\| Array | Use grid position instead of flat index: `[rows, columns]` (e.g. `[5, 10]`) or `\"auto\"` to detect. Omit for flat array. |\n| `axis` | String | For grid: limit to one axis (`\"x\"` or `\"y\"`). |\n| `ease` | Ease | Distribute values along an ease curve (e.g. `\"power1.inOut\"`). Default `\"none\"`. |\n\n**In a tween:** pass the result of `distribute(config)` as the property value; GSAP calls the function for each target with `(index, target, targets)`.\n\n```javascript\n\u002F\u002F Scale: middle elements 0.5, outer edges 3 (amount 2.5 distributed from center)\ngsap.to(\".class\", {\n  scale: gsap.utils.distribute({\n    base: 0.5,\n    amount: 2.5,\n    from: \"center\"\n  })\n});\n```\n\n**Manual use:** call the returned function with `(index, target, targets)` to get the value for that index.\n\n```javascript\nconst distributor = gsap.utils.distribute({\n  base: 50,\n  amount: 100,\n  from: \"center\",\n  ease: \"power1.inOut\"\n});\nconst targets = gsap.utils.toArray(\".box\");\nconst valueForIndex2 = distributor(2, targets[2], targets);\n```\n\nSee [distribute()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002Fdistribute\u002F) for more.\n\n## Units and Parsing\n\n### getUnit(value)\n\nReturns the unit string of a value (e.g. `\"px\"`, `\"%\"`, `\"deg\"`). Use when normalizing or converting values.\n\n```javascript\ngsap.utils.getUnit(\"100px\");   \u002F\u002F \"px\"\ngsap.utils.getUnit(\"50%\");     \u002F\u002F \"%\"\ngsap.utils.getUnit(42);        \u002F\u002F \"\" (unitless)\n```\n\n### unitize(value, unit)\n\nAppends 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.\n\n```javascript\ngsap.utils.unitize(100, \"px\");  \u002F\u002F \"100px\"\ngsap.utils.unitize(\"2rem\", \"px\"); \u002F\u002F \"2rem\" (unchanged)\n```\n\n### splitColor(color, returnHSL?)\n\nConverts a color string into an array: **[red, green, blue]** (0–255), or **[red, green, blue, alpha]** (4 elements for RGBA when alpha is present or required). Pass **true** as the second argument (**returnHSL**) to get **[hue, saturation, lightness]** or **[hue, saturation, lightness, alpha]** (HSL\u002FHSLA) instead. Works with `\"rgb()\"`, `\"rgba()\"`, `\"hsl()\"`, `\"hsla()\"`, hex, and named colors (e.g. `\"red\"`). Use when animating color components or building gradients. See [splitColor()](https:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FGSAP\u002FUtilityMethods\u002FsplitColor\u002F).\n\n```javascript\ngsap.utils.splitColor(\"red\");                    \u002F\u002F [255, 0, 0]\ngsap.utils.splitColor(\"#6fb936\");                \u002F\u002F [111, 185, 54]\ngsap.utils.splitColor(\"rgba(204, 153, 51, 0.5)\"); \u002F\u002F [204, 153, 51, 0.5] (4 elements)\ngsap.utils.splitColor(\"#6fb936\", true);          \u002F\u002F [94, 55, 47] (HSL: hue, saturation, lightness)\n```\n\n## Arrays and Collections\n\n### selector(scope)\n\nReturns 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`).\n\n```javascript\nconst q = gsap.utils.selector(containerRef);\nq(\".box\");        \u002F\u002F array of .box elements inside container\ngsap.to(q(\".circle\"), { x: 100 });\n```\n\n### toArray(value, scope?)\n\nConverts 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.\n\n```javascript\ngsap.utils.toArray(\".item\");           \u002F\u002F array of elements\ngsap.utils.toArray(\".item\", container); \u002F\u002F scoped to container\ngsap.utils.toArray(nodeList);          \u002F\u002F [ ... ] from NodeList\n```\n\n### pipe(...functions)\n\nComposes 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.\n\n```javascript\nconst fn = gsap.utils.pipe(\n  (v) => gsap.utils.normalize(0, 100, v),\n  (v) => gsap.utils.snap(0.1, v)\n);\nfn(50); \u002F\u002F normalized then snapped\n```\n\n### wrap(min, max, value?)\n\nWraps a value into the range min–max (inclusive min, exclusive max). Use for infinite scroll or cyclic values. Omit **value** to get a function: `wrap(min, max)(value)`.\n\n```javascript\ngsap.utils.wrap(0, 360, 370);  \u002F\u002F 10\ngsap.utils.wrap(0, 360, -10);   \u002F\u002F 350\n\nlet wrapFn = gsap.utils.wrap(0, 360);\nwrapFn(370); \u002F\u002F 10\n```\n\n### wrapYoyo(min, max, value?)\n\nWraps value in range with a yoyo (bounces at ends). Use for back-and-forth within a range. Omit **value** to get a function: `wrapYoyo(min, max)(value)`.\n\n```javascript\ngsap.utils.wrapYoyo(0, 100, 150); \u002F\u002F 50 (bounces back)\n\nlet wrapY = gsap.utils.wrapYoyo(0, 100);\nwrapY(150); \u002F\u002F 50\n```\n\n## Best practices\n\n- ✅ Omit the value argument to get a reusable function when the same range\u002Fconfig is used many times (e.g. scroll handler, tween callback): `let mapFn = gsap.utils.mapRange(0, 1, 0, 360); mapFn(progress)`.\n- ✅ Use **snap** for grid-aligned or step-based values; use **toArray** when GSAP or your code needs a real array from a selector or NodeList.\n- ✅ Use **gsap.utils.selector(scope)** in components so selectors are scoped to a container or ref.\n\n## Do Not\n\n- ❌ Assume **mapRange** \u002F **normalize** handle units; they work on numbers. Use **getUnit** \u002F **unitize** when units matter.\n- ❌ Override or rely on undocumented behavior; stick to the documented API.\n\n### Learn More\n\nhttps:\u002F\u002Fgsap.com\u002Fdocs\u002Fv3\u002FHelperFunctions\n",{"name":5,"license":15,"description":7},"main","e4eeaefbd56226a251b228f1beb87a293ab3140a",".agents\u002Fskills\u002Fgsap-utils",1,"https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio","http:\u002F\u002Fanvilkit.aiiua.com\u002F","https:\u002F\u002Fgithub.com\u002Fancyloce","🧙‍♂️  Front-end mage with a secret back-end talent. \r\n🔮  Fluent in React, Vue, Go, and Rust.\r\n📚  Book addict and  🎵  music lover. Let's create some  ✨ magic","2026-11-01 10:38:50",{"source":8,"skillName":5,"commands":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add ancyloce\u002Fanvilkit-studio --skill gsap-utils",{"tool":54,"command":55},"bunx","bunx skills add ancyloce\u002Fanvilkit-studio --skill gsap-utils",{"tool":57,"command":58},"pnpm","pnpm dlx skills add ancyloce\u002Fanvilkit-studio --skill gsap-utils","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fgsap-utils\u002FSKILL.md",true,[],[63,94,118,139,162,168],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":74,"publishedAt":34},"01M6JGVQAQWDRDT2CAQ2VH7D9V","react-doctor","Use when finishing a feature, fixing a bug, before committing React code, or when the user types `\u002Fdoctor`, asks to scan, triage, or clean up React diagnostics. Covers lint, accessibility, bundle size, architecture. Includes a regression check and a full local-triage workflow that fetches the canonical playbook.","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002Fpackages\u002Fruntime\u002Fcore\u002F.claude\u002Fskills\u002Freact-doctor\u002FSKILL.md",[69],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[75,76,77,78,79,80,81,82,83,84,85,24,86,87,88,89,90,91,92,93],"react","doctor","react doctor","workflow","architecture","lint","code","playbook","regression","bundle size","check","regression check","up","clean","scan","local","feature","types","size",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":34},"01M6JGVJ7H21GFHTJ57RBWC6C1","review-remediate","Use for the review-then-fix-everything loop on a package or diff — deliver a grounded review report immediately (no scoping questions, no plan-approval), then remediate every finding as tracked numbered items, gating each batch on typecheck\u002Flint\u002Ftest\u002Fbuild plus an independent Codex pass until clean. Trigger on \"review and fix \u003Cpackage>\", \"remediate the review\", \"review-fix-verify\", or when the user wants a deep review followed by autonomous remediation. Distinct from gstack `review` (pre-landing PR review) and `code-review` (diff only) — this reviews from scratch AND fixes to green.","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Freview-remediate\u002FSKILL.md",[],[101,102,103,104,105,106,107,108,24,109,110,88,111,112,113,114,115,33,116,117],"review","review remediate","pr review","pr","package","autonomous","fix","landing","diff","only","green","deep","as","trigger","reviews","fixes","review report",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":34},"01M6JGVDZD39P3Q97XGQPTTKQN","review-fixes","Close out an EXISTING code-review findings report — one subagent per finding, each with a regression test — then regenerate EN\u002Fzh\u002Fja\u002Fko docs, run all gates, and verify no stale or unexported symbols remain. Trigger on \"\u002Freview-fixes\", \"fix all N review findings\", \"close the review findings\", or when the user hands over a findings report to remediate. Distinct from review-remediate, which produces the review itself first — this skill starts from a report that already exists.","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Freview-fixes\u002FSKILL.md",[],[101,116,125,126,81,127,128,129,130,83,107,131,132,133,134,114,135,136,137,138],"review fixes","test","code-review","first","verify","subagent","regression test","en","zh","gates","with","review findings","which","Existing",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":34},"01M6JGV8J3ZRFGCXR2W3Q9ZWYK","release-prep","Pre-release verification + go\u002Fno-go checklist for publishing @anvilkit packages. Detects the release surface (main workspace fixed-group vs components submodule), runs changeset status and the check:all release gates, enforces this repo's publish gotchas (version.ts drift, ui peer ranges, never-publish canvas-templates, bundle\u002Fapi-snapshot), then hands the exact publish command to the user. Use when asked to \"prep a release\", \"check release readiness\", \"\u002Frelease-prep\", or before cutting a version. Does NOT commit or publish.","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frelease-prep\u002FSKILL.md",[],[146,147,148,149,150,151,152,153,154,155,24,156,157,158,159,39,160,134,161,33],"release","prep","release prep","canvas","components","commit","api","Bash","changeset","repo","version","never","publishing","peer","drift","true",{"skillNo":163,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":164,"categories":165,"keywords":167,"publishedAt":34},"01M6JGV33MBTTHMZ1SNJZHAA6H","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Freact-doctor\u002FSKILL.md",[166],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},[75,76,77,78,79,80,81,82,83,84,85,24,86,87,88,89,90,91,92,93],{"skillNo":169,"name":170,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":176,"publishedAt":34},"01M6JGV1KQAFYH6ZQ864ZBCVVH","pre-refactor","https:\u002F\u002Fgithub.com\u002Fancyloce\u002Fanvilkit-studio\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpre-refactor\u002FSKILL.md",[173],{"categoryNo":174,"categoryName":175,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000007","代码审查",[177,178],"refactor","pre refactor"]