October 7, 2026
You are on a site where a headline slides in, the page glides rather than jumps, and a 3D object turns as you scroll. Someone on your team asks the obvious question: “what are they using for that?” The answer is rarely one library. It is usually a small stack — one thing for scrolling, one for motion, sometimes one for 3D — and each leaves different fingerprints. Here are five checks, from thirty seconds to a few minutes, that identify most of them.
Check 1: ask the console
Open DevTools, switch to the Console, and type the library names. Libraries loaded from a script tag often expose a global; the ones bundled by a build tool usually do not, so a miss here proves nothing.
window.gsap && gsap.version // "3.13.0"
window.ScrollTrigger // present if the plugin is registered globally
window.__THREE__ // three.js sets this to its revision number
window.Lenis || window.lenis // sometimes exposed, often not
A hit is strong evidence. A miss only means the code is inside a bundle, which is the norm for modern React, Next and Vite sites.
Check 2: read the DOM for fingerprints
Libraries change the page they run on, and the changes are distinctive. Inspect
the elements and the <html> tag:
- GSAP ScrollTrigger wraps pinned sections in an element with
the class
pin-spacer. ScrollSmoother adds#smooth-wrapperand#smooth-content. - Lenis puts classes such as
lenisandlenis-smoothon the root element when smooth scrolling is active. - Locomotive Scroll uses
data-scroll-containeranddata-scrollattributes throughout the markup. - Webflow interactions leave
data-w-idattributes on animated elements, which tells you the motion is Webflow’s own engine rather than a separately loaded library. - Three.js and its relatives draw into a
<canvas>, often fixed behind the content. A full-viewport canvas with no visible markup is a strong hint. - Framer Motion has no obvious class names. Look for elements
carrying inline
stylevalues fortransformandopacitythat change as you interact, inside a React tree.
Check 3: scan the network panel
Reload with the Network tab open and filter by JS. Library names often survive
in chunk filenames (gsap, three, lenis),
and CDN-hosted sites load them from URLs like cdn.jsdelivr.net/npm/gsap@3.13.0/...
that spell out both the library and the version. If a site ships one large
main.js, filenames will not help, and you need the next check.
Check 4: use the source maps
When a site publishes source maps, they list every module that went into the
bundle, and the dependency folder names are an exact inventory. Search the map for
node_modules/gsap, node_modules/three,
node_modules/framer-motion or node_modules/lenis. Plenty
of production sites do not publish maps, but of those that do, this is the most
reliable static check because it names the version too. Enrichr’s
extract_source_maps tool collects them for you rather than leaving you
to hunt through the Sources panel.
Check 5: watch what actually runs
Every static check above shares one weakness: it tells you what is present, not what is doing the work. A site can ship GSAP in the bundle and drive its hero entirely with CSS keyframes. It can load Three.js for one small widget while the headline motion comes from somewhere else. Treating “found in the bundle” as “used for that effect” is the single most common mistake in this kind of detective work.
The reliable answer comes from the page at runtime. Run
extract_site_profile first for a cheap survey of the stack, then
reverse_engineer_animations to see what animated: the tweens and
timelines that played, the ScrollTrigger settings, the CSS keyframes and the
easing curves. If the page draws to a canvas, add
reverse_engineer_webgl to see the shaders and draw calls. The call
order we recommend is in
our step-by-step walkthrough.
Telling the lookalikes apart
A few confusions come up constantly, so it is worth being explicit about them.
- Smooth scrolling is not animation. Lenis, Locomotive and ScrollSmoother change how the page scrolls. GSAP and Framer Motion change what elements do while it scrolls. Sites often combine one of each.
- Three.js is not the animation. It draws the scene. Something else, usually GSAP, decides when anything in it moves, which is why the two are so often found together. We unpack that split in Three.js and GSAP: the two libraries behind almost every award-site hero.
- Framer the site builder is not Framer Motion the library. The first generates whole sites; the second is a React animation library you can use anywhere. Their markup looks different, so check which one you are actually looking at.
When the answer is “no library at all”
Some of the smoothest sites on the web use no animation library whatsoever, and it is worth ruling this out before you go hunting. Modern browsers can do a great deal natively:
- CSS transitions and keyframes handle hovers, fades and
looping motion, and run off the main thread when limited to
transformandopacity. - CSS scroll-driven animations (
animation-timeline: scroll()andview()) now cover many effects that previously needed a scroll library, in browsers that support them. - The Web Animations API (
element.animate()) gives scripted, interruptible animation with no dependency. - The View Transitions API handles page-to-page morphs that used to need a router plus a motion library.
If the Animations panel in DevTools shows CSS animations or WAAPI entries and the console shows no library globals, you may simply be looking at the platform doing its job. That is also good news if you are the one rebuilding it: fewer dependencies to ship.
A worked example: reading a hero in two minutes
Say the hero text reveals line by line as the page loads, then a background
object rotates as you scroll. Start with the console: gsap.version
returns a number, so GSAP is present. The elements panel shows a
pin-spacer around the hero, which means ScrollTrigger is pinning it.
A fixed canvas sits behind the content and window.__THREE__ is set, so
Three.js draws the rotating object. The page scrolls smoothly and the
<html> element carries a lenis class. Four findings,
one stack: Lenis for scroll, GSAP and ScrollTrigger for timing, Three.js for the
object. What you still do not know is which of those drives which behaviour, or
with what numbers, and that is where a runtime capture earns its cost.
A thirty-second routine
- Console:
gsap,__THREE__,lenis. - Elements:
pin-spacer,lenisclasses, a fixed canvas. - Network: library names in filenames and CDN URLs.
- Source maps: search for the
node_modulesfolders. - Still unsure, or need the exact settings? Capture the runtime.
Identifying the stack is step one. The step after it — understanding why the combination feels good — is the subject of what actually makes a site Awwwards-worthy, where we compared a dozen Site of the Day winners and found the same few patterns repeating. For a ready-made set of real examples to practise on, browse the Enrichr gallery.