ScrollMagic: JavaScript Scroll Interaction Library
| File Size: | 585 KB |
|---|---|
| Views Total: | 24392 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
ScrollMagic is a framework-agnostic JavaScript library that tracks an element's position relative to a scroll container and reports entry, exit, and scroll progress changes.
The latest ScrollMagic 3 uses IntersectionObserver and ResizeObserver, requires no jQuery dependency, and leaves animation work to CSS or libraries such as GSAP, Motion, and anime.js.
Existing ScrollMagic 2 projects can keep the Controller and Scene API through the legacy v2 package, and v3 uses a new per-element API under the next npm tag.
Features
- Element entry, exit, and scroll-progress tracking.
- Vertical and horizontal scroll containers.
- Window or custom element scroll containers.
- Numeric, percentage, named, and function-based range offsets.
- Per-instance progress, velocity, active-range, and resolved-bound values.
on,off, andsubscribeevent APIs.- Runtime option updates, bounds refresh, pause, resume, and destroy methods.
- Plugin lifecycle hooks and native TypeScript definitions.
Use Cases
- Scroll progress bars tied to a document or a page section.
- Class toggles for reveal transitions when a section enters or leaves the viewport.
- Parallax, video scrubbing, and storytelling sequences driven by a 0-to-1 progress value.
- Lazy loading, analytics hooks, or content activation linked to viewport position.
How To Use ScrollMagic 3
Install The Current v3 Package
Use the next npm tag for ScrollMagic 3.
npm install scrollmagic@next
Track An Element Entering And Leaving The Viewport
Import ScrollMagic, point the instance at one element, and bind the scroll state events you need.
<section id="feature-story"> <h2>Product Story</h2> <p>Scroll to watch this content react to viewport changes.</p> </section>
import ScrollMagic from 'scrollmagic';
var story = document.querySelector('#feature-story');
var tracker = new ScrollMagic({
element: story
});
tracker
.on('enter', function () {
story.classList.add('is-active');
})
.on('leave', function () {
story.classList.remove('is-active');
});
Track Scroll Progress
The progress value runs from 0 to 1 across the configured active range. This value works for progress indicators, parallax transforms, video timelines, and other scroll-linked logic.
import ScrollMagic from 'scrollmagic';
var progressBar = document.querySelector('#story-progress');
new ScrollMagic({
element: '#story-section'
}).on('progress', function (event) {
progressBar.style.transform =
'scaleX(' + event.target.progress + ')';
});
Define A Custom Tracking Zone
ScrollMagic uses element bounds and container bounds to calculate the active range. Named positions include here (0%), center (50%), and opposite (100%).
var tracker = new ScrollMagic({
element: '#chapter',
containerStart: 'center',
containerEnd: 'center',
elementStart: -50,
elementEnd: -100
});
ScrollMagic 3 Options
| Option | Description |
|---|---|
element |
Type: Element, String, or null. Tracks the element or first selector match. The default resolves to the first child of the container. |
elementStart |
Type: Number, String, or Function. Default: 0. Sets the start inset on the tracked element. |
elementEnd |
Type: Number, String, or Function. Default: 0. Sets the end inset on the tracked element. |
container |
Type: Window, Element, String, or null. Default: window. Sets the scroll container or first selector match. |
containerStart |
Type: Number, String, Function, or null. Its inferred value depends on the element option. Sets the start inset on the scroll container. |
containerEnd |
Type: Number, String, Function, or null. Its inferred value depends on the element option. Sets the end inset on the scroll container. |
vertical |
Type: Boolean. Default: true. Uses vertical tracking when true and horizontal tracking when false. |
Events
| Event | Fires When |
|---|---|
enter |
The element enters the active range and progress leaves an endpoint. |
leave |
The element leaves the active range and progress reaches 0 or 1. |
progress |
The progress value changes inside the active range. |
Read Event Data
tracker.on('progress', function (event) {
console.log(event.type); // progress
console.log(event.direction); // forward or reverse
console.log(event.location); // start, inside, or end
console.log(event.target.progress);
});
Instance Methods
| Method | Description |
|---|---|
on(type, callback, options) |
Registers an event listener and returns the instance. The options object accepts once: true. |
off(type, callback) |
Removes a registered event listener and returns the instance. |
subscribe(type, callback, options) |
Registers a listener and returns an unsubscribe function. |
modify(options) |
Updates multiple instance options in one call. |
refresh() |
Recalculates cached bounds after external layout changes. |
disable() |
Disconnects the tracking observers and freezes the current progress value. |
enable() |
Reconnects tracking after disable() and recalculates the current state. |
destroy() |
Destroys the instance and disconnects its observers. |
addPlugin(plugin) |
Registers a plugin object on the instance. |
removePlugin(plugin) |
Removes a plugin object and runs its removal hook. |
Plugin Lifecycle Hooks
| Hook | Runs When |
|---|---|
onAdd() |
addPlugin() registers the plugin. |
onRemove() |
removePlugin() removes the plugin while the instance is active. |
onEnable() |
enable() resumes tracking. |
onDisable() |
disable() pauses tracking. It also runs before onDestroy() during destruction of an enabled instance. |
onDestroy() |
destroy() tears down the instance. |
onModify(changes) |
modify() or an option setter changes one or more public options. |
State Properties
| Property | Description |
|---|---|
progress |
Current progress from 0 to 1. |
activeRange |
Container scroll positions for the start and end of the active range. |
scrollVelocity |
Scroll velocity in pixels per second along the tracked axis. |
resolvedBounds |
Cached element and container layout bounds. |
disabled |
True after tracking is disabled or the instance is destroyed. |
pluginList |
A snapshot of plugins registered on the instance. |
Static Methods
| Method | Description |
|---|---|
ScrollMagic.defaultOptions(options) |
Reads or changes defaults used by new instances. |
ScrollMagic.refreshAll() |
Recalculates bounds for every active ScrollMagic instance. |
ScrollMagic.destroyAll() |
Destroys every active ScrollMagic instance. |
Update Multiple Options At Runtime
tracker.modify({
containerStart: 'center',
containerEnd: 'center',
elementStart: '20%'
});
Refresh Bounds After Layout Changes
ResizeObserver handles element size changes, but some DOM and CSS updates move an element while its size stays unchanged. Call refresh() after these changes:
- Margin, padding, or positioning changes that move the tracked element.
- Class changes that alter page layout.
- Sibling elements inserted or removed above the tracked element.
- Images that load with no explicit dimensions.
- Web fonts that shift document layout after loading.
Pinning Elements In ScrollMagic 3
ScrollMagic 3 has no setPin() method. Use CSS position: sticky for pinned sections. The v2 JavaScript pin system switches element positioning during scroll and can show a one-frame jump during fast scrolling. ScrollMagic 3 removes that subsystem.
.sticky-panel {
position: sticky;
top: 0;
}
Using ScrollMagic With Animation Code
ScrollMagic 3 reports state and progress but does not include the v2 GSAP or Velocity animation bridges. Feed event.target.progress into your animation code, or use enter and leave to change classes.
var card = document.querySelector('#scroll-card');
new ScrollMagic({
element: card
}).on('progress', function (event) {
var progress = event.target.progress;
card.style.opacity = progress;
card.style.transform =
'translateY(' + ((1 - progress) * 40) + 'px)';
});
ScrollMagic 2 And jQuery Legacy Setup
ScrollMagic 2.0.9 is the final v2 release. Its Controller and Scene architecture is useful for existing projects that already depend on v2 plugins, scene pinning, or older ScrollMagic examples.
The v2 core does not require jQuery. The optional jquery.ScrollMagic.js plugin requires jQuery 1.11 or newer. It accepts jQuery objects and selectors where ScrollMagic expects DOM elements and exposes ScrollMagic through $.ScrollMagic.
Install ScrollMagic 2
npm install scrollmagic
A browser project can also load the v2 core from cdnjs.
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.9/ScrollMagic.min.js"></script>
Legacy v2 Plugins
animation.gsap.min.js: Connects v2 scenes to GSAP tweens and timelines.animation.velocity.min.js: Connects v2 scenes to Velocity animations.debug.addIndicators.min.js: Displays scene trigger and duration indicators during development.jquery.ScrollMagic.min.js: Adds jQuery object and selector handling to v2.
Basic ScrollMagic 2 Scene
var controller = new ScrollMagic.Controller();
var scene = new ScrollMagic.Scene({
triggerElement: '#legacy-section',
duration: 300,
triggerHook: 'onCenter'
})
.setPin('#legacy-panel')
.addTo(controller);
ScrollMagic 2 To ScrollMagic 3 Reference
| ScrollMagic 2 | ScrollMagic 3 |
|---|---|
Controller + Scene |
One ScrollMagic instance for each tracked element. |
triggerElement |
element. |
triggerHook, offset, duration |
elementStart, elementEnd, containerStart, and containerEnd. |
| Scene lifecycle and progress events | enter, leave, and progress on the instance. |
setPin() |
CSS position: sticky. |
animation.gsap.js |
Animation code reads ScrollMagic state or progress directly. |
jquery.ScrollMagic.js |
No jQuery plugin in v3. |
debug.addIndicators.js |
No indicator plugin in the v3 core package. |
Alternatives And Related Resources
- 10 Best Parallax Scrolling Effects (2026 Update): jQuery, vanilla JavaScript, and CSS parallax options.
- Performant Scroll-driven Interactions - scrollama.js: IntersectionObserver-based scrollytelling with step events and progress callbacks.
- Modern Vanilla JS Library for Scrollytelling - Scrolleo: ESM scrollytelling with IntersectionObserver and TypeScript definitions.
- Scroll-Driven Animation Library for React and Next.js - Kino: component-based scroll scenes, reveals, parallax, and video scrubbing.
FAQs
Q: Does ScrollMagic require jQuery?
A: No. ScrollMagic 3 has no jQuery dependency, and the ScrollMagic 2 core has been dependency-free since v2. The old jquery.ScrollMagic.js file is an optional v2 integration plugin.
Q: Why does npm install scrollmagic install ScrollMagic 2?
A: The default npm package points to the final v2 release. Install ScrollMagic 3 from the next tag with npm install scrollmagic@next.
Q: Can I use setPin() in ScrollMagic 3?
A: No. ScrollMagic 3 removed the JavaScript pin system. Use CSS position: sticky for pinned sections.
Q: Can ScrollMagic 3 work with GSAP?
A: Yes. ScrollMagic 3 exposes scroll state and progress that animation code can read. It does not include the v2 animation.gsap.js bridge.
Q: My tracked element moved after a layout update. What should I call?
A: Call instance.refresh() after layout changes that move the element but do not resize it. Use ScrollMagic.refreshAll() when several instances need new bounds.
Changelog:
v3.0.0beta (2026-09-03)
- Update ScrollMagic v3
v2.0.9 (2026-02-22)
- Final v2 release
- ScrollMagic v3 is coming soon
v2.0.8 (2020-08-15)
- Added support for GSAP JavaScript animation library 3.
v2.0.7 (2019-05-07)
- Fixed error in Safari when using setPin
- Added missing semi-colon to isMobile regex
- Fixed SVG element detection as Dom Element and related Error on Safari
- Fixed code selection in examples
- Pass Scene as this to duration callback
- Increase fps limit for mobile support(advance) example.
- Added documentation for responsive duration (e.g. "100%")
- Updated Section Wipes (natural) to work for large number of sections.
- Removed warning for pushFollowers in pins with duration 0, unless actively set to true.
- Fixed some spelling stuff.
v2.0.6 (2018-10-20)
- Bugfixes
v2.0.5 (2015-04-30)
- Fixed: a JS error occurred in IE9 see here
- Fixed: cascading pins of absolutely positioned elements didn't work see here
- Fixed: scene state wasn't correct at start position see here
- Fixed: updatePinState was called before scrollOffset update
v2.0.4 (2015-04-08)
- fixed JS error in IE9
v2.0.0 (2015-02-26)
- removal of all dependencies (jQuery & GSAP) – ScrollMagic is now stand-alone.
- new file structure
- new scene event: add fires when scene is added to a controller
- new scene event: remove fires when scene is removed from a controller
- option changes in Scene.addIndicators()
- several performance tweaks
- lots more info and warning messages (in the uncompressed development version)
v1.3.0 (2014-11-13)
- changed AMD loader behavior to export only one object -> {Controller: ScrollMagic, Scene: ScrollScene}
- added Error message for missing dependencies
- fixed bubbling of pseudo-resize event of div containers
- reference bug with AMD loading
v1.2.3 (2014-10-25)
- fixed: reference bug when using asynchronous loading
v1.2.2 (2014-10-21)
- fixed: Error message with wrong loading order
v1.2.0 (2014-10-16)
- AMD loader support
- added warning for tweens being overwritten
- better code for mobile clicks
- updated draw example to camel case to support Firefox
- updated parralax sections example to moving divs instead of background position
- added new references
- added favicon
- scroll momentum increased in Firefox over fixed elements
- parallax example was juggy in Firefox and Safari -> removed reliance of TweenMax ticker in favor of requestAnimationFrame
- bugfix for pinned elements jittering if inside a container, because of the delayed position update in refreshInterval
- bugfix: div resize event bubbled up to window
v1.1.2 (2014-09-16)
- fixed a bug with the scrollTo method
v1.1.1 (2014-09-04)
- Major update.
v1.0.9 (2014-08-19)
- added new feature `ScrollMagic.scrollTo()`
v1.0.8 (2014-05-27)
- Feature: add class for pinned element during pin
v1.0.7 (2014-04-15)
- feature: ScrollScene.startOffset
v1.0.6 (2014-04-05)
- fixed a bug concerning relative sizing of pinned elements
v1.0.5 (2014-03-24)
- updates.
This awesome jQuery plugin is developed by janpaepke. For more Advanced Usages, please check the demo page or visit the official website.











