gleit
v1.0.1
Published
super easy interactive html animations.
Downloads
187
Maintainers
Readme
GLEIT
super easy interactive html animations, based on vertical scroll, mouse position, etc. checkout this page for a demo of some cool interactive animations built with GLEIT.
how to install
<script src="https://unpkg.com/gleit"></script>
or
npm i gleit
<script src="node_modules/gleit/dist/gleit.min.js"></script>
how to use
standard way
<p data-gleit='{"0vh": {"rotate": "90deg", "opacity": 1},
"50vh": {"rotate": "0deg", "opacity": 0}}'>hellow</p>
<script>
window.addEventListener('load', function() {
gleit
.animate()
.on(gleit.verticalScroll());
});
</script>
the <p>
element will rotate 90 degrees and fades away as the page scrolls from 0vh
to 50vh
.
bound to mouse motion
<p id="main">hellow</p>
<script>
window.addEventListener('load', function() {
gleit
.animate(document.getElementById('main'), {
'0vw': {translateX: '5vw', scale: 1.5},
'50vw': { scale: 1 },
'100vw': {translateX: '-5vw', scale: 1.5}
})
.on(gleit.mouseMove.client.x);
gleit
.animate(document.getElementById('main'), {
'0vh': {translateY: '5vh', opacity: 0 },
'50vh': { opacity: 1 },
'100vh': {translateY: '-5vh', opacity: 0 }
})
.on(gleit.mouseMove.client.y);
});
</script>
the <p#main>
element will move around, scale up and down and fade in and out as the mouse moves.
multiple animations
<p data-gleit='{"0vh": {"scale": 1}, "50vh": {"scale": 2}}'>hellow</p>
<p>world!</p>
<script>
window.addEventListener('load', function() {
gleit
.animate()
.on(gleit.verticalScroll());
gleit
.animate(document.getElementsByTagName('p'), {
'0vh': {rotate: '0deg'},
'50vh': {rotate: '90deg'}
})
.on(gleit.verticalScroll());
});
</script>
the first <p>
(hellow) scales up and rotates, and the second <p>
(world!) only rotates, as the page scrolls from 0vh
to 50vh
.
bound to element scroll instead of document
<div id="holder" style="height:50vh; overflow: auto">
<div style="height: 100vh">
<p data-gleit='{"0vh": {"scale": 1}, "50vh": {"scale": 2}}'>hellow</p>
</div>
</div>
<script>
window.addEventListener('load', function() {
gleit
.animate()
.on(gleit.verticalScroll(document.getElementById('holder')));
});
</script>
will scale the <p>
element up, but the animation is bound to scrolling of #holder
element instead of body (body doesn't scroll).
bound to a timeline
<p data-gleit='{"0s": {"scale": 1}, "1s": {"scale": 2}}'>hellow</p>
<script>
window.addEventListener('load', function() {
gleit
.animate()
.on(gleit.timeline('2s', { bounce: true }));
});
</script>
how it generally works
gleit.animate(<target(s)>[optional], <frames>[optional]).on(<animation ref>);
first, you create an animation object by calling gleit.animate()
function. you can pass an element or a list of elements (or an HTMLCollection
or a NodeList
) objects to it as the target
elements to be animated, and a description of the frames
in your animation (see examples above). you then use the .on()
function on the animation object to bind it to some animation reference (animation ref for short). an animation ref can be the page's vertical scroll, the x axis of the mouse cursor, etc.
if you do not pass the frames
parameter, the value of data-gleit
attribute on each target element will be used for that target element, and elements without data-gleit
attribute will be skipped. the value of data-gleit
should be the same frames
description, except that it should be in strict JSON format:
<!-- this is wrong because ' character is not JSON standard. -->
<p data-gleit="{'0%': {'rotate': '45deg', 'opacity': 0.5}, '100%': {'rotate': '135deg', 'opacity': 1}}"></p>
<!-- this is wrong because all keys must be escaped in double quotes in JSON -->
<p data-gleit='{"0%": {rotate: "45deg", opacity: 0.5}, "100%": {rotate: "135deg", opacity: 1}}'></p>
<!-- this is wrong because JSON doesn't like .5 -->
<p data-gleit='{"0%": {"rotate": "45deg", "opacity": .5}, "100%": {"rotate": "135deg", "opacity": 1}}'></p>
<!-- CORRECT VERSION -->
<p data-gleit='{"0%": {"rotate": "45deg", "opacity": 0.5}, "100%": {"rotate": "135deg", "opacity": 1}}'></p>
if you do not pass the target
parameter, all elements with data-gleit
attribute set on them will be animated. hence, the following statements essentially do the same thing:
gleit.animate();
gleit.animate(document.querySelectorAll('[data-gleit]'));
what GLEIT does
GLEIT generates an animation tick function with the invokation of gleit.animate()
, and wraps it in the returned animation object. when .on()
is invoked on that animation object, the animation tick function is passed to the animation ref, which should bind it to an event and invoke it on every trigger of that event. for example, gleit.verticalScroll()
will bind the tick function to 'scroll'
event of the window
, gleit.mouseMove.client.x
will bind to 'mousemove'
event of the window
, etc.
the tick function will be passed an object (most probably the animation ref itself) with the following properties:
current
: which is the current value of the animation, like the scroll position, the x of the mouse cursor, etc. the value ofcurrent
should be normalized to start at zero.total
: the maximum value forcurrent
, like the scroll height of the document in case of scrolling, or the width of the window in case of mouse cursor's x axis.window
: a recurrent window for the value of current, for example the height of the window in case of scrolling. if not passed, the value oftotal
will be used.
the ref object passed to tick function might have these values but with other names. for example, when the animation reference is scrolling of a specific element, the element can be passed to the animation tick function as the ref object, however it has scrollTop
, scrollHeight
and clientHeight
instead of current
, total
and window
. in this case, the tick function is constructed with a transform object that maps the values for current
, window
and total
to the corresponding properties in the ref object.
finally, the animation tick function will extrapolate properties described in the frames
parameter based on values of current
, total
and window
, and will set the style
attribute on target elements. multiple GLEIT animations properly work with each other as to not override the values set by the other, so you can safely run multiple animations on a single element, however, the value of style
set by other sources will be completely discarded.
NOTE: the animation tick function will NOT compute the extrapolation or set the style
attribute on the element on the same thread as the event trigger. instead, it will utilize requestAnimationFrame()
right after the event trigger, or will wait 1000/60
milliseconds if requestAnimationFrame()
is not supported.
NOTE: the animation tick function will override the style
attribute on the animated elements. additionally, it will (most probably) set the transform
style attribute on the elements, which means values set for transform
in CSS will be overriden as well.
animation description format
{
"<frame key>": {
"<property>": "<value><unit>" | <value (number)>,
...
},
...
}
the animations are to be described using either the frames
parameter or the data-gleit
attribute on the elements, mapping each frame key to a set of properties. the frame key should be a string of the format "<value><unit[optional]>"
, and the format must be consistent among all set frame keys, so for example the same unit
must be used. the interpretation of the unit
depends on the animation ref, and if present, it must be one of the following:
px
: the raw value of current position of the animation, for example the scroll position, the x axis of the mouse cursor, etc. will be equal to thecurrent
value on the ref object. this unit is for readability and is equal to not setting any unit.%
: will refer to the percentage of the completion of the animation, like the scroll position percentage of the whole scroll height. will be equal tocurrent/total*100
on the ref object.vw
|vh
: will refer to the position of the animation based on the animation window. for example, in case of scrolling, this will mean how many vh's have we scrolled. note that these are not the same as CSSvw
andvh
, as they are IDENTICAL to each other, and also they refer to the window of the animation reference and not the globalwindow
object. so for example, when horizontally scrolling on a specific element, both50vw
and50vh
mean half of the width of that element and not the browser window. will be equal tocurrent/window*100
on the ref object.w
: likevw
orvh
, just not multiplied by 100. so1w = 100vw = 100vh
.ms
: likepx
, added for readability on time-based animations.s
:1s = 1000ms
. added for readability on time-based animations.m
:1m = 60s
. added for readability on time-based animations.
the properties can be one of the following:
translateX
,translateY
scale
: if present,scaleX
andscaleY
values will be ignored.scaleX
,scaleY
rotate
: if present,rotateX
,rotateY
androtateZ
values will be ignored.rotateX
,rotateY
,rotateZ
opacity
the values for these properties should be of the same format you would set in CSS as these will be set in the style attribute of the animated elements in the end:
{
"translateX": "128px",
"translateY": "20vh",
"scale": 2,
"opacity": 0.5,
"rotateZ": "60deg",
...
}
NOTE: the vw
and vh
units on translateX
and translateY
properties are the CSS units, not those used in the frame keys. although most of the time these two will be the same, they are not necessarily always the same and should not be confused.
the value for each property will be extrapolated based on values set in the frames with closest bigger and smaller frame key values with regards to the current animation position. properties are animated independently and only frames that set the value for a property are considered while animating it, so not all properties are required to be specified in all frames. if the current position of the animation is smaller or bigger than the frames specifying a property with smallest or biggest frame keys, the value of the closest frame will be used (so animated values basically cap in case of overflow/underflow).
animation references
the following animation references are shipped by default with GLEIT:
gleit.verticalScroll(<host>[optional])
will bind to the vertical scroll of the host element. if not given, the whole page will be used. the current
value will be the scrollTop
of the host, total
the scrollHeight
and window
the clientHeight
.
gleit.horizontalScroll(<host>[optional])
like gleit.verticalScroll()
, but, ummm, horizontally. the current
value will be scrollLeft
, the total
the scrollWidth
and window
the clientWidth
.
gleit.mouseMove.client.x
| gleit.mouseMove.client.y
will bind to x
| y
axis of the mouse cursor. window
and total
would be the clientWidth
| clientHeight
of the browser.
gleit.mouseMove.page.x
| gleit.mouseMove.page.y
like gleit.mouseMove.client.x
| gliet.mouseMove.client.y
, with the difference being pageX
| pageY
of the cursor will be used instead, and the total
value will also be the scrollWidth
| scrollHeight
of the page.
gleit.timeline(<duration>, <options>[optional])
will bind the animation to a specific timeline. duration
should be the number of milliseconds or of the format "<value><unit>"
with unit
being one of ms
, s
and m
. options
can be either { loop: true }
or { bounce: true }
.
NOTE: this specific animation ref is written mostly as an example for custom animation refs, since all the capabilities it provides are better provided in CSS3. you can check the code here. however, in the off-chance that you would want some interactive animation on an element who also has some time-based animation, you would need to use this since GLEIT would override all transform properties set with CSS3 animations.
custom animation refs
you can create your own custom animation refs and pass them to the .on()
function of animation objects. you can checkout any of the default animation refs here. generally, your ref needs to be something like this:
function myCustomAnimationRef(factory) {
var animationTick = factory(<transform object>[optional]);
//
// other preparations
//
eventHost.addEventListener('<event>', function(event) {
//
// possible preparation of the ref object, based on `event`
//
animationTick(<ref object>);
//
// maybe other calculations ...
//
});
}
gleit.animate().on(myCustomAnimationRef);
so basically, you are given a factory
function that you can use to generate the animationTick
function, and you should specify how and when to call that animationTick
function. you need to pass to it a ref object
, which should have the current
, total
, and optionally the window
properties. your ref object
might have other properties that are not named as such, in which case you can pass a transform
object to the factory
function, specifying your mapping:
var animationTick = factory({
current: '<my current property>',
total: '<my total property>',
window: '<my window property>'
});
and then pass your ref object unmodified to the animationTick
function. if you do not want to pass a transform
, you can simply create the animationTick
function without passing any arguments to the factory
function:
var animationTick = factory();
running tests
clone the repo.
npm i
npm test