gsap-scroll — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited gsap-scroll (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-scroll → gsap-optimise → gsap-test Cross-reference gsap-animate for context/cleanup, gsap-optimise for batch/scrub tuning.
Companion: For ScrollTrigger API reference, invoke gsap-scrolltrigger. This skill covers scroll animation recipes only. Requires: greensock/gsap-skillsctx = gsap.context(() => {
const els = gsap.utils.toArray('.reveal', sectionRef.value)
gsap.set(els, { y: 28, autoAlpha: 0 })
els.forEach((el) => {
gsap.to(el, {
y: 0, autoAlpha: 1, duration: 0.8, ease: 'power2.out', force3D: true,
scrollTrigger: {
trigger: el, start: 'top 88%',
toggleActions: 'play none none reverse',
invalidateOnRefresh: true,
},
})
})
}, sectionRef.value)autoAlpha not opacity — sets visibility: hidden at 0toggleActions: 'play none none reverse' — plays on enter, reverses on leave-backctx = gsap.context(() => {
const cards = gsap.utils.toArray('.masonry-card')
gsap.set(cards, { y: 60, autoAlpha: 0, rotation: () => gsap.utils.random(-3, 3) })
const ENTER = { y: 0, autoAlpha: 1, rotation: 0, stagger: 0.08, duration: 0.8,
ease: 'power3.out', force3D: true, overwrite: 'auto' }
const EXIT_UP = { y: -20, autoAlpha: 0, duration: 0.4, ease: 'power2.in', overwrite: 'auto' }
const EXIT_DOWN = { y: 60, autoAlpha: 0, duration: 0.4, ease: 'power2.in', overwrite: 'auto' }
ScrollTrigger.batch(cards, {
onEnter: (batch) => gsap.to(batch, ENTER),
onLeave: (batch) => gsap.to(batch, EXIT_UP),
onEnterBack: (batch) => gsap.to(batch, ENTER),
onLeaveBack: (batch) => gsap.to(batch, EXIT_DOWN),
start: 'top 85%', end: 'bottom 15%',
})
}, sectionRef.value)overwrite: 'auto' prevents conflicting tweens on fast scrollrotation re-evaluates per element for organic randomness<div class="parallax-layer" data-speed="0.2"><!-- slow --></div>
<div class="parallax-layer" data-speed="0.6"><!-- fast --></div>ctx = gsap.context(() => {
gsap.utils.toArray('.parallax-layer', sectionRef.value).forEach((layer) => {
const speed = parseFloat(layer.dataset.speed) || 0.5
gsap.to(layer, {
yPercent: -50 * speed, ease: 'none', force3D: true,
scrollTrigger: {
trigger: sectionRef.value, start: 'top bottom', end: 'bottom top', scrub: 0.5, invalidateOnRefresh: true,
},
})
})
}, sectionRef.value)yPercent not y — percentage-based, scales with element sizescrub: 0.5 — smoother than scrub: true, 0.5s catch-upawait nextTick(); ScrollTrigger.refresh() // v-if toggles
img.addEventListener('load', () => ScrollTrigger.refresh()) // lazy images
document.fonts.ready.then(() => ScrollTrigger.refresh()) // font swap
ScrollTrigger.config({ ignoreMobileResize: true }) // address barSee references/scroll-patterns.md for:
gsap.context() scoped to a refautoAlpha not opacity for revealsinvalidateOnRefresh: true when animating positional valuesoverwrite: 'auto' or true when elements can be re-triggeredwill-change lifecycle in ST callbacks (set on enter, release on leave)ScrollTrigger.refresh() after DOM changes that affect document heightscrub: 0.5 over scrub: true for smoother motion~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.