Skip to content

ScrollSync

ScrollSync binds animation states and programmatic callbacks to browser scroll progression. The module tracks trigger elements relative to configurable viewport boundaries (start and end), outputting a normalized progress value (0-1) and dispatching discrete directional events.

Integration occurs directly via the scrollSync parameter on any tween configuration, or manually via standalone ScrollSync.create(config) instances.

GLOBAL 0%
FORGE 0%

ANIMX

↓ SCROLL TO EXPLORE

FORGE SEQUENCE INITIATED

END OF SEQUENCE

60 FPS

1. Triggered Sequences

Absent the scrub parameter, ScrollSync executes standard playback controls. The target animation.play() invokes when the scroll position crosses the downward start boundary, and animation.reverse() triggers upon the upward intersection. The once: true configuration terminates the tracker immediately after the initial downward intersection.

The linked animation requires the paused: true configuration property to prevent execution prior to the boundary crossing.

Scroll to Reveal
60 FPS
js
animateFrom(items, {
  y: 100, z: -200, opacity: 0, rotationX: -45, rotationY: 20, scale: 0.8,
  stagger: 0.1, duration: 1.2, ease: 'expo.out',
  paused: true,
  scrollSync: {
    trigger: gridElement,
    bounds:  scrollContainer,
    start:   'top 85%',
    once:    true
  }
});

2. Interpolated Scrubbing

The scrub configuration maps scroll progression proportionally to the animation progress property. Assigning a numerical coefficient to scrub (e.g., 1.5) initializes a secondary interpolation loop utilizing requestAnimationFrame, smoothing the interpolation over the specified duration in seconds.

Scroll to Assemble
60 FPS
js
// Scrubbed Timeline (Only hands are scrubbed!)
const scrubTl = timeline({ paused: true });
scrubTl.animate(secHand, { rotationZ: 360 * 15, duration: 4, ease: 'cubic.inOut' }, 0);
scrubTl.animate(minHand, { rotationZ: 360 * 3, duration: 4, ease: 'cubic.inOut' }, 0);
scrubTl.animate(hourHand, { rotationZ: 360 * 0.25, duration: 4, ease: 'cubic.inOut' }, 0);

ScrollSync.create({
  trigger: sectionElement,
  animation: scrubTl,
  start: 'top bottom',
  end: 'bottom top',
  scrub: 1.5
});

3. Multiphasic Parallax Geometry

Synchronous playback of distinct tweens operating with independent magnitudes within a parent timeline resolves parallax displacement. Setting scrub: true outputs zero-latency frame correspondence.

Explore Depth
60 FPS
js
const tl = timeline({ paused: true });

// 1. Nebula moves slowly down
tl.animate(nebula, { y: 200, scale: 1.5, duration: 1, ease: 'linear' }, 0);
// 2. Stars move down faster
tl.animate(stars, { y: 400, opacity: 0, duration: 1, ease: 'linear' }, 0);
// 3. Text moves UP while rotating
tl.animate(text, { y: -200, scale: 1.2, rotationX: 15, duration: 1, ease: 'linear' }, 0);
// 4. Streaks whip extremely fast past the camera
tl.animate(streaks, { y: -2000, translateZ: 500, duration: 1, ease: 'quad.in' }, 0);

ScrollSync.create({
  trigger: sectionElement,
  start: 'top bottom',
  end: 'bottom top',
  animation: tl,
  scrub: true
});

4. Contextual Element Pinning

The pin: true configuration computes the absolute distance spanning start to end and establishes a spacer element retaining Document flow dimensions. The target element applies position: sticky and anchors to the designated viewport offset across the progression window.

The configuration supports pure-relative coordinate syntax for the end property (e.g., +=1200), computing the scroll distance explicitly independent of intrinsic element height.

Scroll Cinematic Gallery

LUMINA

NEXUS

AETHER

Pin Released - Scrolling Normally
60 FPS
js
const tl = timeline({ paused: true });
tl.animate(track, { x: '-66.666%', ease: 'linear', duration: 1 }, 0);
tl.animate(images, { x: '20%', ease: 'linear', duration: 1 }, 0); // Internal background parallax

ScrollSync.create({
  trigger: container,
  start:   'top 5%', 
  end:     '+=1200', 
  pin:     true,
  animation: tl,
  scrub:   0.8
});

5. System Event Dispatch

Four primary lifecycle observers dispatch execution relative to the active bound crossing. The onUpdate parameter exposes the continuous normalized progress property during the sequence window.

System Status0.0%
ON_ENTER
ON_LEAVE
ENTER_BACK
LEAVE_BACK
↓ INITIATE SEQUENCE
TARGET ZONE
60 FPS
js
ScrollSync.create({
  trigger: triggerElement,
  bounds:  scrollContainer,
  start:   'top 60%',
  end:     'bottom 40%',
  markers: true,

  onEnter:     (self) => flash(indicators.onEnter),
  onLeave:     (self) => flash(indicators.onLeave),
  onEnterBack: (self) => flash(indicators.onEnterBack),
  onLeaveBack: (self) => flash(indicators.onLeaveBack),

  onUpdate: (self, { progress }) => {
    apply(progressBar, { scaleX: progress });
  }
});

Configuration Reference

The constructor initializes properties matching the syntax below.

PropertyTypeDefaultDescription
triggerstring | ElementrequiredElement binding for scroll bounds extraction.
boundsstring | ElementwindowViewport contextualization container.
startstring'top bottom'Origin property. Syntax "{triggerPoint} {viewportPoint}".
endstring'bottom top'Termination property. Supports relative math syntax ('+=800').
animationTween | TimelinenullAssociated timeline payload. Auto-paused when scrub: true.
scrubboolean | numberfalseProgression synchronization metric. Numeric assignments supply inertia.
pinboolean | stringfalseModifies DOM layout rendering relative offset pinning mechanism.
oncebooleanfalseTerminates tracking node after single forward intersection occurrence.
toggleClassstringnullClass application hook during bounded active states.
markersbooleanfalseVisual bounds projection injection into physical DOM.

Absolute and Relative Calculation Offsets

Mathematical calculations interpret properties spanning explicit coordinates to percentage distributions.

OperatorInterpretation
topOffset zero matrix.
centerdimension * 0.5.
bottomdimension.
[number]%Proportionate mathematical offset relative to containing bounding box.
[number]pxAbsolute dimensional spacing.

Compound matrix operations chain natively across declaration strings:

js
start: 'center+=50px bottom-=10%'
end:   '+=800'

Method Registry

The core API provides standardized initialization, destruction, and refresh commands directly through the exported object hierarchy.

MethodRole
refresh()Instructs explicit recalculation across positional vectors based on immediate DOM layout flow. Attached natively to resize hooks.
kill()Discards bounds rendering nodes and invalidates attached tracking listeners.
progressRead-only matrix parameter returning absolute 0-1 sequence value.
isActiveBoolean extraction verifying trigger presence within designated matrix sequence bounds.

Static Execution Properties

ScopeRole
ScrollSync.create(config)Standard registration module.
ScrollSync.getAll()Extracts active execution bounds tracker instances.
ScrollSync.refresh()Triggers mass recalculation sequentially across attached items.
ScrollSync.stopAll()Iterates through and detaches all active bounds monitors.

Protocol Export Module

Initialization through NPM distributions.

js
import { ScrollSync } from 'animx/plugins/ScrollSync'