gsap-optimise — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited gsap-optimise (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Flow: gsap-setup → gsap-animate → gsap-optimise → gsap-test References: See gsap-performance skill for extended API details.
Companion: For general GSAP performance guidance, invoke gsap-performance. This skill covers optimisation recipes and audit checklists only. Requires: greensock/gsap-skills// GOOD — GPU-composited
gsap.to(el, { x: 100, y: 50, rotation: 45, scale: 1.2, opacity: 0.8 })
// BAD — triggers layout/reflow
gsap.to(el, { left: 100, top: 50, width: '120%', height: 200 })| force3D | Behaviour | Use when |
|---|---|---|
"auto" | 3D during tween, 2D after | Default — usually best |
true | Stay 3D permanently | Elements animated repeatedly |
false | Always 2D | Upscaled images (avoids blur) |
CSS will-change: transform is fine for always-animating elements (scroll-driven, looping). For interactive/repeated animations, manage in JS:
self.add('applyEffect', (el) => {
el.style.willChange = 'transform'
gsap.to(el, { scale: 1.03, ...HOVER_IN })
})
self.add('resetEffect', (el) => {
gsap.to(el, { scale: 1, ...HOVER_OUT,
onComplete: () => { el.style.willChange = 'auto' }
})
})See gsap-performance skill for quickTo, quickSetter, and piping API reference. Use the fastest tool that fits:
gsap.quickTo()gsap.quickSetter()style.setProperty()GSAP defers first-render writes to end of tick — avoids layout thrashing. Default lazy: true.
When multiple from()/fromTo() target the same property, set immediateRender: false on later ones.
// BAD: bare gsap.to inside event handler — orphaned tween
el.addEventListener('mousemove', () => gsap.to(el, { x: 10 }))
// BAD: rapid fire without overwrite — tween pile-up
onMouseMove = () => gsap.to(el, { x: pos, duration: 0.3 })
// BAD: layout properties — triggers reflow
gsap.to(el, { width: 200, height: 100, left: 50 })
// BAD: transformPerspective on every frame (set once with gsap.set)
// BAD: permanent will-change on interactive elements
// BAD: new timeline every call (create once, play/reverse)
// BAD: no reduced motion check
// BAD: markers left in productionGPU & Rendering
force3D: true on repeatedly animated elementswill-change managed: CSS for scroll-driven, JS for interactiveautoAlpha used instead of opacityHigh-Frequency
overwrite: 'auto' on all rapid-fire tweensquickTo() for repeated animated updatesquickSetter() for per-frame value pipingScrollTrigger
ScrollTrigger.batch() for large grids (50+ elements)once: true on one-shot triggersinvalidateOnRefresh: true on responsive layoutsScrollTrigger.refresh() after dynamic contentCleanup
gsap.context() or ctx.add()ctx.revert() in onUnmountedAccessibility
prefers-reduced-motion respected via gsap.matchMedia()~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.