Added Github Copilot support

This commit is contained in:
jackdoyle
2026-03-05 19:36:56 -06:00
parent fe605114ed
commit 97b7cc3e4d
8 changed files with 101 additions and 8 deletions
+15
View File
@@ -0,0 +1,15 @@
# GSAP — Repository-wide instructions for GitHub Copilot
When writing or suggesting GSAP (GreenSock Animation Platform) code in this repository:
- **Imports:** Use `import { gsap } from "gsap"` (or named plugin imports, e.g. `import { ScrollTrigger } from "gsap/ScrollTrigger"`). Register plugins once with `gsap.registerPlugin(ScrollTrigger)` before use.
- **Sequencing:** Prefer `gsap.timeline()` for multi-step animations instead of chained `delay` values. Use the position parameter (e.g. `"+=0.5"`, `"<"`, `"label"`) to place tweens on the timeline.
- **Transforms:** Prefer GSAP transform properties (`x`, `y`, `scale`, `rotation`, `xPercent`, `yPercent`) over animating raw CSS `transform` or layout properties (`top`, `left`, `width`, `height`) for movement and scale — better performance and consistent order of operations.
- **Opacity:** Prefer `autoAlpha` over `opacity` for fade in/out so elements get `visibility: hidden` at 0 and do not block clicks.
- **from() / fromTo():** `gsap.from()` animates from the given values to the element’s current state. When **multiple from() or fromTo()** tweens target the same property of the same element, set **immediateRender: false** on the later one(s) so the first tween’s end state is not overwritten before it runs.
- **Scroll-based animation:** When scroll-driven or scroll-linked animation is requested, use ScrollTrigger (register the plugin, then use `scrollTrigger: { trigger, start, end, scrub }` or attach to a timeline). Do **not** put a ScrollTrigger on a tween that is a child of a timeline — put it on the timeline or a top-level tween.
- **ScrollTrigger:** Use **scrub** for scroll-linked progress or **toggleActions** for discrete play/reverse, not both. Call **ScrollTrigger.refresh()** after DOM/layout changes that affect trigger positions. Create ScrollTriggers in top-to-bottom page order or set **refreshPriority** so they refresh in that order.
- **React:** In React projects, prefer `useGSAP()` (from `@gsap/react`) or `gsap.context()` with cleanup so animations and ScrollTriggers are reverted when the component unmounts.
- **Cleanup:** When elements are removed or routes change (e.g. SPAs), kill associated ScrollTrigger instances or revert SplitText/Draggable so nothing runs on stale elements. Use **clearProps** when a tween should not leave inline styles after it completes (e.g. so CSS classes can take over).
**More detail:** The `skills/` directory in this repo contains full SKILL.md guidance (core, timeline, ScrollTrigger, plugins, React, performance). For agents that support the Agent Skills format (Cursor, Claude Code, etc.), install this repo as a skill for the complete reference.
@@ -0,0 +1,15 @@
---
applyTo: ["**/*.tsx", "**/*.jsx", "**/components/**"]
---
# GSAP in React — path-specific instructions
When writing or suggesting GSAP code in React/JSX/TSX files:
- Prefer **useGSAP()** from `@gsap/react` over raw `useEffect` for GSAP setup. Register the hook once: `gsap.registerPlugin(useGSAP)` (and any other plugins used).
- Pass a **scope** (ref to container) so selectors are scoped: `useGSAP(() => { ... }, { scope: containerRef })`. This avoids animating elements outside the component.
- When targeting by ref, pass the **DOM element** (e.g. `ref.current`), not the ref object. Wrong: `gsap.to(myRef, ...)`. Right: `gsap.to(myRef.current, ...)`. With useGSAP, the scope ref limits selectors to that subtree.
- Rely on useGSAP’s automatic **cleanup** on unmount (reverts animations and kills ScrollTriggers). Do not leave ScrollTriggers or timelines running after unmount.
- Use **contextSafe** (returned from useGSAP) to wrap callbacks like `onComplete` so they no-op after unmount and avoid React state-update warnings.
- By default useGSAP runs once (empty dependency array). To re-run when deps change, pass `{ dependencies: [dep1, dep2] }` or `{ revertOnUpdate: true }` as the second argument. Put animation logic in the callback, not in a separate effect.
- If not using useGSAP, use **gsap.context()** in useEffect and return a cleanup that calls `ctx.revert()`.
@@ -0,0 +1,18 @@
---
applyTo: ["**/*scroll*", "**/*ScrollTrigger*", "**/scroll*"]
---
# ScrollTrigger — path-specific instructions
When writing or suggesting scroll-linked GSAP code (ScrollTrigger):
- Register the plugin once: `gsap.registerPlugin(ScrollTrigger)`.
- Use **scrub: true** (or a number) for scroll-driven progress; use **toggleActions** for discrete play/reverse. Do not use both on the same trigger.
- Put ScrollTrigger on the **timeline** or a **top-level tween**, not on a tween that is a child of a timeline (wrong: `tl.to(..., { scrollTrigger: {... } })`; right: `gsap.timeline({ scrollTrigger: {... } }).to(...)`).
- When **pinning**, do not animate the pinned element itself; animate its children. Use **pinSpacing: true** (default) so layout does not collapse.
- Prefer **transform** properties (`x`, `y`, `scale`, `rotation`) for the animated element; avoid animating layout properties when possible.
- For “fake” horizontal scroll (pin a section, content moves horizontally while scrolling vertically), use **containerAnimation** and set **ease: "none"** on the horizontal tween so scroll and position stay in sync.
- **start** / **end** format: `"triggerPosition viewportPosition"` (e.g. `"top center"`, `"bottom top"`). Use `endTrigger` if the end is based on a different element.
- Call **ScrollTrigger.refresh()** after DOM or layout changes that affect trigger positions (e.g. new content, fonts loaded). Viewport resize is handled automatically.
- Create ScrollTriggers in **top-to-bottom** page order, or set **refreshPriority** so they refresh in that order when creation order differs.
- When removing elements or changing routes (SPAs), **kill** ScrollTrigger instances: `ScrollTrigger.getAll().forEach(t => t.kill())` or kill by id.