Jump to content
Search Community

Start an animation based on scroll position?

Lindsayanng test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hello. I am very new to javascript but am a fast learner and can code php, html, and css on an advanced level, just to give you a background.


I've read through a couple js tutorials and videos before jumping in to this and then I also took a look at the basic tutorials on this site to learn a little more about animations in general.


I am putting together a site where I have two kinds of animations. The first is a very basic smooth scroll to an anchor on the same page. The second is the content fly-ins.


I would like to have specific content animate at specific points in the scroll.


I am using the SUPERScrollarama "addon" that uses the GreenSock library, and as far as I can tell, the animation triggers when the element is in the center of the page. Even stranger still, the animation doesn't trigger until after its almost out of view of the screen on an iphone.


Below is the scrollarama javascript file and my little animation snipped that I am using. The animations I am starting out with are just VERY basic until I get my feet wet and figure out specifically how I want things to move in to view.


SUPERSCROLLORAMA - The jQuery plugin for doing scroll animations
by John Polacek (@johnpolacek)

Powered by the Greensock Tweening Platform

Dual licensed under MIT and GPL.
(function($) {
   $.superscrollorama = function(options) {

 var superscrollorama = this;
 var defaults = {isVertical:true};
 superscrollorama.settings = $.extend({}, defaults, options);


 var animObjects = [],
  pinnedObjects = [],
  didScrollCheck = false,
  timeline = new TimelineLite();

 function init() {
  // scroll to top of page
  $('html, body').animate({ scrollTop: 0 }, 0);

  $(window).scroll(function() {
   didScrollCheck = true;
  setInterval(function() {
   if (didScrollCheck) {
 didScrollCheck = false;
  }, 50);

 function checkScrollAnim() {
  var currScrollPoint = superscrollorama.settings.isVertical ? $(window).scrollTop() : $(window).scrollLeft();
  var offsetAdjust = superscrollorama.settings.isVertical ? -$(window).height()/2 : -$(window).width()/2;
  var i, startPoint, endPoint;

  // check all animObjects
  var numAnim = animObjects.length;
  for (i=0; i<numAnim; i++) {
   var animObj = animObjects[i],
 target = animObj.target,
 offset = animObj.offset;

   if (typeof(target) === 'string') {
 startPoint = superscrollorama.settings.isVertical ? $(target).offset().top : $(target).offset().left;
 offset += offsetAdjust;
   } else if (typeof(target) === 'number') {
 startPoint = target;
   } else {
 startPoint = superscrollorama.settings.isVertical ? target.offset().top : target.offset().left;
 offset += offsetAdjust;

   startPoint += offset;
   endPoint = animObj.dur ? startPoint + animObj.dur : startPoint;

   if ((currScrollPoint > startPoint && currScrollPoint < endPoint) && animObj.state !== 'TWEENING') {
 // if it should be TWEENING and isn't..
 animObj.state = 'TWEENING';
 animObj.start = startPoint;
 animObj.end = endPoint;
 animObj.tween.progress((currScrollPoint - animObj.start)/(animObj.end - animObj.start)).pause();
   } else if (currScrollPoint < startPoint && animObj.state !== 'BEFORE') {
 // if it should be at the BEFORE tween state and isn't..
 animObj.state = 'BEFORE';
   } else if (currScrollPoint > endPoint && animObj.state !== 'AFTER') {
 // if it should be at the AFTER tween state and isn't..
 animObj.state = 'AFTER';
   } else if (animObj.state === 'TWEENING') {
 // if it is TWEENING..
 animObj.tween.progress((currScrollPoint - animObj.start)/(animObj.end - animObj.start)).pause();

  // check all pinned elements
  var numPinned = pinnedObjects.length;
  for (i=0; i<numPinned; i++) {
   var pinObj = pinnedObjects[i];
   var el = pinObj.el;

   // should object be pinned?
   if (pinObj.state != 'PINNED') {

 startPoint = pinObj.spacer ?
  superscrollorama.settings.isVertical ? pinObj.spacer.offset().top : pinObj.spacer.offset().left :
  superscrollorama.settings.isVertical ? el.offset().top : el.offset().left;

 startPoint += pinObj.offset;
 endPoint = startPoint + pinObj.dur;

 if (currScrollPoint > startPoint && currScrollPoint < endPoint && pinObj.state !== 'PINNED') {
  // pin it
  pinObj.state = 'PINNED';

  // set original position value for unpinning
  pinObj.origPositionVal = superscrollorama.settings.isVertical ? el.css('top') : el.css('left');
  if (pinObj.origPositionVal === 'auto')
   pinObj.origPositionVal = 0;
   pinObj.origPositionVal = parseInt(pinObj.origPositionVal, 10);

  // change to fixed position
  if (superscrollorama.settings.isVertical)
   el.css('top', 0);
   el.css('left', 0);

  pinObj.pinStart = startPoint;
  pinObj.pinEnd = endPoint;
  if (pinObj.spacer)
   pinObj.spacer.css('height', pinObj.dur + el.outerHeight());
  if (pinObj.onPin)
   // Check to see if object should be unpinned
   } else {

 if (currScrollPoint < pinObj.pinStart || currScrollPoint > pinObj.pinEnd) {
  // unpin it
  pinObj.state = currScrollPoint < pinObj.pinStart ? 'BEFORE' : 'AFTER';
  // revert to original position value
  if (superscrollorama.settings.isVertical)
   el.css('top', pinObj.origPositionVal);
   el.css('left', pinObj.origPositionVal);

  if (pinObj.spacer)
   pinObj.spacer.css('height', currScrollPoint < pinObj.pinStart ? 0 : pinObj.dur);
  if (pinObj.onUnpin)
 else if (pinObj.anim) {
  // do animation
  pinObj.anim.progress((currScrollPoint - pinObj.pinStart)/(pinObj.pinEnd - pinObj.pinStart));

 superscrollorama.addTween = function(target, tween, dur, offset) {


   tween: tween,
   offset: offset || 0,
   dur: dur || 0,

 superscrollorama.pin = function(el, dur, vars) {
  if (typeof(el) === 'string') el = $(el);
  if (vars.anim) vars.anim.pause();

  // create wrapper for pinned elements that aren't absolute or fixed position
  var pinSpacer = null;
  if (el.css('position') === 'relative' || el.css('position') === 'static') {
   pinSpacer = $('<div class="pin-spacer"></div>');

   offset: vars.offset || 0,

 // INIT

 return superscrollorama;



My animations:

<script type="text/javascript" >
$(document).ready(function() {
var controller = $.superscrollorama();

// individual element tween examples
controller.addTween('#fly-it', TweenLite.from( $('#fly-it'), 3.25, {css:{left:'2000px'},  ease:Quad.easeInOut}));
controller.addTween('#spin-it', TweenMax.from( $('#spin-it'), 3.25, {css:{opacity:0, rotation: 360},  ease:Quad.easeInOut}));
controller.addTween('#spin-it', TweenMax.from( $('#spin-it'), 3.25, {css:{scale:3}, ease:Quad.easeInOut}));


Link to comment
Share on other sites

You can add an offset after the tween to adjust when the scrolling begins:


controller.addTween('#fly-it', TweenLite.from( $('#fly-it'), 3.25, {css:{left:'2000px'}, ease:Quad.easeInOut}), 0,200);


controller.addTween('#spin-it', TweenMax.from( $('#spin-it'), 3.25, {css:{opacity:0, rotation: 360}, ease:Quad.easeInOut}), 0, -200)


The '0' parameter is the duration of the tween (0 means it autoplays through) and '200'/'-200' are offsets to the default scroll position in which the animation starts.



Also, note that I'm using TweenMax. This is because animations with a duration use the tween progress property, which is only available on TweenMax tweens.

  • Like 1
Link to comment
Share on other sites

Thanks so much for your help.


I basically just copied your code exactly (all you did was add , 0, -200) because it's easier for me to understand what the code does after seeing it in motion, and now none of the animations work.


code posted below:

// individual element tween examples
controller.addTween('#fly-it', TweenLite.from( $('#fly-it'), 3.25, {css:{left:'2000px'},  ease:Quad.easeInOut}));
controller.addTween('#spin-it', TweenMax.from( $('#spin-it'), 3.25, {css:{opacity:0, rotation: 360},  ease:Quad.easeInOut}), 0, 200));
controller.addTween('#spin-it', TweenMax.from( $('#spin-it'), 3.25, {css:{scale:3}, ease:Quad.easeInOut}), 0, 200));


When you say "duration" of the tween, i'm not entirely sure what that means because I had thought the number defined before the css change was the duration (in this case 3.25). Maybe I am getting my terminology mixed up.


When you offset, are the numbers like 200/-200 in pixels? Or are they somewhat arbitrary?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...