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
@@ -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.