Skip to content

Instantly share code, notes, and snippets.

@notoriousb1t
Last active March 15, 2018 13:40
Show Gist options
  • Save notoriousb1t/6bfb914a26c0fc96f2000cffd4d7f69e to your computer and use it in GitHub Desktop.
Save notoriousb1t/6bfb914a26c0fc96f2000cffd4d7f69e to your computer and use it in GitHub Desktop.
Just Animate 3 (API ideas)
/**
* This shortcut function returns a timeline that you could build upon.
* a single value is assumed to be the end value
* this autoplays as it is intended to be fire and forget
*/
JA.to('.target', 800, { opacity: 0 })
/**
* Utilities used internally that provide value when using mixers or use()
*/
// sets a property immediately. Depending on the target and prop, this may be a regular object property,
// a style property, an attribute, or a css variable. This is exposed to help with writing custom mixers
JA.set(target, 'opacity', 1);
// gets the value of the property. Depending on the target and prop, this may be a regular object property,
// a style property, an attribute, or a css variable
JA.get(target, 'opacity');
/**
* This covers builder functions for building out keyframes
*/
var t2 = JA.timeline()
// sets the value at the current time
t2.set(obj1, { transformOrigin: 'center center' })
// sets the value at a particular time
t2.set(obj1, { transformOrigin: 'center center' }, 1000)
// add tween to the end of the timeline with to
t2.to(obj1, 800, { propName: 0 })
// animate to 1000ms, each subsequent item can stagger up to 150 up to the 5th item, this is a staggerTo, not a staggerFrom
// each staggered element subtracts from the duration.
t2.to('.item', 1000, {
$staggerStart: 150,
$limit: 5,
transform: 'translateX(20px)'
})
// setting stagger to 'distribute' automatically distributes the items evenly
t2.to('.item', 1000, {
$staggerStart: 'auto',
transform: 'translateX(20px)'
})
t2.play()
// create timeline with JA.to
function fadeOut() {
return JA.to('.target', 1000, { opacity: 0 })
}
var t2 = JA.timeline()
// if the time (0) parameter is not specified, this is added to the end of the timeline
t2.addTimeline(fadeOut(), 0)
/**
* Allow external animations with playState, currentTime, play(), cancel(), and pause()
* to be sync'd and controlled. This specifically targets WAAPI and would replace the "web" prop
*/
var waapiAnimation = el.animate(
[
{ opacity: 0 },
{ opacity: 1 }
],
// recommended fill: both
{ fill: 'both', duration: 1000 }
)
// adds the web animation and pauses it. It is not exported by getKeyframes()
// requires polyfilling getComputedTiming() https://codepen.io/notoriousb1t/pen/da172f01c89d7c8cfd599b28e180927c
t2.addTimeline(waapiAnimation)
var t2 = JA.timeline()
// events can be labels or builtin events like finish
await t2.when('midpoint')
t2.on('midpoint', () => { })
t2.off('midpoint', () => { })
t2.play()
var t1 = JA.timeline({
refs: { /* reference definitions */ },
labels: { /* label definitions */ },
mixers: { /* mixer definitions */ }
})
var t2 = JA.timeline({
// provide a name to register this timeline for devtools and access it globally from JA.timelines.my_timeline.
// If the same name is used twice, the second timeline will overwrite the first.
name: 'my_timeline'
})
// readonly properties
t1.playbackState
// player controls
t1.currentTime = 0
t1.playbackRate = 1
// forcible expands or shrinks the duration.
t1.duration = 2000
// insert the next animation at position 0
t2.start = 0;
// insert the next animation at label: 'midpoint'
t2.setStart('midpoint')
// add 300ms delay at current position, will expand the duration if necessary
t2.start += 300;
// how to register an easing
// set the name on easings with a function that takes in parameters and returns the appropriate easings
// this function is expected to be pure.
JA.easings.power = function(n, type) {
if (type === 'out') {
return o => 1 - Math.pow(o, n)
}
// "in"
return o => Math.pow(o, n)
}
// use powerIn/powerOut with parameters
const t1 = JA.timeline()
t1.to('.item', 1000, { x: 200, $easing: 'power(2, in)' });
t1.to('.item', 1000, { x: 600, $easing: 'power(4, out)' });
t1.play();
/*
* Built-in easings:
* // (required for WAAPI)
* - cubic-bezier(p0,p1,p2,p3),
* - linear
* - ease, ease-in, ease-out, ease-in-out,
* - steps(n,start|end), step-end, step-start,
*
* // (easings that will work for non-WAAPI)
* - bounce(n, in|out|in-out)
* - elastic(amplitude, period, bounces, in|out|in-out)
* - power(n, in|out|in-out)
*/
// seek to a label or time
t2.seek('midpoint')
// starts playing from the currentTime. restarts if playbackState == 'idle'
t2.play()
// plays from the label midpoint to 600ms
t2.play({ from: 'midpoint', to: 600 })
// .cancel() + .play()
t2.restart()
// pauses the currentTime. seeks to start if playbackState == 'idle'
t2.pause()
// cancels all effects on the timeline (should clear properties on all targets to initial value)
t2.cancel()
// seek to the total time of the timeline. This is either 0 or duration depending on animation direction and iterations
t2.finish()
// shorthand for .playbackRate *= -1;
t2.reverse()
/**
* This is advanced functionality meant to make JA extensible. You can tell JA how to handle a specific property or use .use() to write a
a custom handler that handles a group of properties. mixers are processed first, and are not handed to .use()
*/
// create a mixer for the 'd' property
JA.mixers.d = function(a,b) {
// the polymorph interpolate function returns a function that accepts 0 - 1 progression
return polymorph.interpolate([a, b])
}
JA.mixers.myCustomOp = function(a,b) {
return (offset, target, propertyName) {
/* set your value here */;
target[propertyName] = 'foo';
// return nothing here to signal that the set operation was handled
}
}
// middle-ware for powering things like WAAPI
JA.use(function(effect, next) {
const isHandled = effect.target instanceof Element;
if (!isHandled) {
// pass the effect to the next provider
return next(effect);
}
// return animations spawned from this effect
return [{
play() {
},
pause() {
},
set currentTime(time) {
},
set playbackState(state) {
},
playbackRate(rate) {
},
cancel() {
}
}];
});
/* labels are named times, they can be used as events or to seek to position */
t2.labels.midpoint = 200
// const midpoint = t2.labels.midpoint
// delete t2.labels.midpoint
/* refs are the objects being animated. Timelines can resolve css selectors automatically, but use an @ notation to
* refer to these objects.
*/
var t2 = JA.timeline()
t2.refs.mesh = { x: 0 }
// const midpoint = t2.refs.mesh
// delete t2.refs.mesh
// targetting a reference in a keyframe using the @ notation
t2.to('@mesh', 1000, { x: 1000 })
// set a parent element for dom selectors. This is to help integrate with componentized pages
t2.refs.$parent = document.querySelector('.navigation')
/**
* the keyframes, labels, and duration can be exported to JSON or imported to JSON. If the timeline is active (running or paused)
* it will update the targets and animations accordingly. This interface is intended to be used by tooling. It supports partial updates with a parameter
* to replace all
*/
var t2 = JA.timeline()
// get/set keyframes
const keyframes = t2.export()
// replaces whole timeline with these keyframes
t2.import({
"type": "merge",
"duration": 2000, // will be computed automatically if omitted.
"labels": {
"middle": 1000
},
"player": {
"currentTime": 0,
"playbackState": "active",
"playbackRate": 1
},
"targets": {
".item": {
"transform": {
"0": {
"value": "scale(0)",
},
"2000": {
"value": "scale(1)",
"stagger": "distribute",
"limit": 10
}
},
"transform-origin": {
"0": {
"type": "set",
"value": "center center"
}
}
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment