npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

smooth-tween

v1.0.14

Published

60 fps DOM animations in the browser and mobile devices

Downloads

5

Readme

smooth-tween

A JSON powered, functional parallax scrolling library that uses native scrolling (no iScroll, or custom scrolling required)!

As a consequence, 60fps animations are achievable in both desktop browsers and mobile devices.

A very basic example and code base can be seen here: http://andrew-tam-000.github.io/smooth-tween/

The minimal javascript for the example is here: http://andrew-tam-000.github.io/smooth-tween/js/main.js -- the rest is done with simple CSS and HTML!

Motivation

The motivation for this project was to create an awesome parallax / scroll animation library that doesn't require iScroll ( and thus performs well in mobile browsers ).

Note: To acheive the maximum possible performance, its recommended that you only use the following css properties:

  • transform
    • translate
    • scale
    • rotation
  • opacity

While this may seem very limited, there are tons of tricks and complex animations you can implement with just these properties.

You can read more about this here: http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/

Use Cases

Parallax Scrolling

Bind animations to the mouse scroll event to create stunning parallax effect and full scroll-based websites.

Functional Animations

While the primary use case for this is most likely for parallax scrolling, smooth-tween has been built in a functional way. The user can choose what tool will 'drive' their animations, whether it be scrolling, mouse movement, clicking, etc...

Theory

There exist many parallax scrolling libraries out there, but few are optimized for mobile devices. By utilizing the browser's native scrolling, 'smooth-tween' aims to produce performant scroll based animations.

In order to achieve this, 'smooth-tween' relies on the following DOM structure:

<body>
    <div class='content'>
        All animation content goes here
    </div>
    <div class='scrollable' >
        <div class='scrollable-height-setter'></div>
        This div will actually be empty, other than the height setter!
        It's main purpose is to capture scroll events natively,
        and pass them off to the smooth-tween to do its thing.
    </div>
</body>

In the markup above, the 'content' div will hold all the html for elements that are going to be moving and transitioning. The 'scrollable' div will be an empty div whose main purpose is to listen for scroll events. The height of this div should explicitly be set with javascript.

You might have noticed something with this approach -- if we are really scrolling the 'scrollable' div, it must be positioned on top of the 'content' div; this means that we cannot readily click on items inside of the 'content' div.

The solution I have implemented is based on these responses:

  • http://stackoverflow.com/a/10623558
  • http://www.vinylfox.com/forwarding-mouse-events-through-layers/

Essentially, it leverages the 'document.elementFromPoint' property to forward events to DOM objects below the current layer.

Lastly, keep in mind that this event forwarding approach is applies only for usage with a full-site, scroll-based parallax experience.

Installation

Download the 'smooth-tween' library by doing the following:

npm install --save smooth-tween

JSON Definition

The smoothTween is driven by a JSON file.

This file should describe all the animations that should happen, and when.

List of features:

  • Flexible 'selectors'
  • Lazily evaluated 'start' and 'end' functions
  • Easings
  • Execute multiple animations at once

Annotated Example

[
    // The JSON file should be an array of different tween durations

    {
        // Describes the duration of this animation
        // 'start' and 'end' could refer to the scrollTop of the page
        // or whatever you want -- this is directly related to what
        // is passed to the updateTween method described in the API section
        start: 0
        , end: 800

        // There may be cases where we want the start
        // and end values to be determined lazily.
        // For instance, if we want these values to be
        // dependent on the window height, then we could pass
        // in a function to return the window height
        // , start: function() { return $(window).height()}
        // , end: function() { return $(window).height()}


        // The list of animations to execute
        // for the duration described above
        // As its an array, you can have multiple
        // different animations happening over
        // the same duration
        , animations: [
            {

                // The selector accepts a variety of arguments
                // The suggested usage is to give your DOM elements a
                // "data-js" attribute, and then use this value as
                // the 'selector'.  By default, the parser
                // will assume that any string passed in is
                // a 'data-js' value.
                selector: 'landing__circle-right'

                // It also supports an array of 'data-js' values
                // as well as support of directly passing in
                // jQuery elements and native DOM elements
                // , selector: jQueryElement
                // , selector: DOMElement
                // , selector: ['dataJSDescriptor1', 'dataJSDescriptor2']

                // These are the actual properties
                // that will get tweened during the
                // tween duration
                // You can specify as many properties
                // as you like here
                , properties: {

                    // IMPORTANT: Because the underlying animation handler
                    // is Velocity.js, property names must match the
                    // Velocity.js spec: http://velocityjs.org/#cssSupport
                    translateX: {

                        // 'start' and 'end' refer to the
                        // tween values for the property
                        start: 0
                        , end: 1.3

                        // As with the tween duration, you can also specify
                        // functions for the start/end value of property tweens
                        // , start: function() { return $(window).height() }
                        // , end: function() { return $(window).height() }

                        // By default, all tween values will have
                        // no unit.  You must explicitly pass the unit
                        // ( 'px', '%', 'em', etc... )
                        , unit: 'em'

                        // Lastly, easing is supported!
                        // I am leveraging this library :https://www.npmjs.com/package/eases
                        // Simply supply the camel-cased name of the function,
                        // and the easing will be applied
                        , easing: 'backInOut'
                    }
                }
            }
        ]
    }
]

Clean Example ( no annotations )

[
    {
        start: () => percentHeightToPx(0)
        , end: () => percentHeightToPx(25)
        , animations: [
            {
                selector: 'landing__circle-left'
                , properties: {
                    opacity: {
                        start: 1
                        , end: 0
                    }
                }
            }
            , {
                selector: 'landing__circle-right'
                , properties: {
                    opacity: {
                        start: 1
                        , end: 0
                    }
                }
            }
            , {
                selector: 'background__slide--title'
                , properties: {
                    zIndex: {
                        start: 4
                        , end: 1
                    }
                }
            }
        ]
    }
    , {
        start: () => percentHeightToPx(0)
        , end: () => percentHeightToPx(CIRCLE_START)
        , animations: [
            {
                selector: [
                    'landing__background-left-name'
                    , 'landing__background-right-name'
                    , 'landing__left-name'
                    , 'landing__right-name'
                ]
                , properties: {
                    translateX: {
                        start: 0
                        , end: -.75
                        , unit: 'em'
                    }
                }
            }
            , {
                selector: [
                    'landing__background-left-developer'
                    , 'landing__background-right-developer'
                    , 'landing__left-developer'
                    , 'landing__right-developer'
                ]
                , properties: {
                    translateX: {
                        start: 0
                        , end: 1.3
                        , unit: 'em'
                    }
                }
            }
        ]
    }
]

API

SmoothTween(animationData [ Object ])

The Tweener constructor that gets loaded in accepts only one argument -- your JSON definition.

import SmoothTween from 'smooth-tween';
let tweenInstance = SmoothTween(animationData);

SmoothTween.updateTween(tweenValue [ Number | String ])

'updateTween' must be called in order to tell 'smoothTween' what the next value to tween is.

scrollLayer.on('scroll', (e) => {
    let scrollTop = scrollLayer.scrollTop();
    tweenInstance.updateTween(scrollTop);
})

SmoothTween.recalculateStaticJson()

Users can specify JSON definitions with lazily evaluated functions.

This method evaluates those functions and constructs the static JSON.

This is helpful if the functions are dependent on window size ( sometimes we like to translate things '100%' but the pixel of that will change when the window is resized )

$(window).on('resize', () => {
    var staticJson = tweenInstance.recalculateStaticJson();
    var maxHeight = getMaxHeight_withAnimation_withWindowHeight( staticJson, $(window).height());
    scrollHeight.height( maxHeight );

    function getMaxHeight_withAnimation_withWindowHeight(staticAnimation, windowHeight) {
        // Pull out the 'end' values
        let end = _.map(staticAnimation, anim => anim.end);

        // We need to add on one more screen height
        let max = Math.max.apply(Math, end);

        return max + windowHeight;
    }

});

Example Usage

Parallax Site

HTML

...
<body>
    <div data-js='scroll-layer'>
        <div data-js='scroll-height'></div>
    </div>
    <div data-js='scroll-content'>
        <div class='background__slide--circle'></div>
        <div class='circle__text'></div>
    </div>
</body>
...

CSS

There is a minimum amount of neccesary CSS to get started.

html, body {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
}


[data-js="scroll-layer"],
[data-js="scroll-content"] {
    position: absolute;
    height: 100%;
    width: 100%;
    top: 0;
}

[data-js="scroll-layer"] {
    overflow-y: auto;

    // Allows smooth scrolling on IOS
    -webkit-overflow-scrolling: touch;
}


[data-js="scroll-height"] {
    // This height shoudl be set via javascript
    // It determines how far a user
    // should be able to scroll the page
    height: 1000%;
}

JavaScript

var animationData = [
    {
        start: 100
        , end: 200
        , animations: [
            {
                selector: 'background__slide--circle'
                , properties: {
                    translateY: {
                        start: 100
                        , end: 0
                        , unit: '%'
                    }
                }
            }
            , {
                selector: 'circle__text'
                , properties: {
                    translateY: {
                        start: 50
                        , end: 0
                        , unit: 'px'
                    }
                }
            }
        ]
    }
];

import smoothTween from 'smooth-tween';

// This div will solely be responsible for keeping track
// of the scroll height.
let scrollLayer = $("[data-js='scroll-layer]");

// This div will set the height of the scrollLayer ( and make it scrollable )
let scrollHeight = $("[data-js='scroll-height]");

// Using our JSON definition, construct the actual smoothTween instance
let tweenInstance = smoothTween(animationData);

// Pass the tween value to the smoothTween instance so that it can render the next animation
scrollLayer.on('scroll', (e) => {
    let scrollTop = scrollLayer.scrollTop();
    tweenInstance.updateTween(scrollTop);
})