Optional
backwardPerforms any necessary operations/computations and then returns keyframes (Keyframes).
Keyframes, either in the form of a PropertyIndexedKeyframes object or—more commonly—an array of Keyframe objects.
const clipFactories = webchalk.createAnimationClipFactories({
customEntranceEffects: {
// -----------------------------------------------------------------
// ----------------------------EXAMPLE 1----------------------------
// -----------------------------------------------------------------
// Let us pretend you made this custom entrance animation effect named 'zoomIn'.
// For this animation, you wrote the forward keyframes generator and
// then verified that the desired rewinding effect is exactly equivalent
// to playing the keyframes produced by forwardKeyframesGenerator() in reverse,
// so you omit backwardKeyframesGenerator.
zoomIn: {
composeEffect(initialScale: number) {
// return ComposedEffect
return {
forwardKeyframesGenerator: () => {
console.log('About to return keyframes!');
// return Keyframes (Keyframe[])
return [
{scale: initialScale, opacity: 0}, // Keyframe 1
{} // Keyframe 2
];
},
// backwardKeyframesGenerator() can be omitted in this case because
// the reversal of the forward keyframes is exactly equivalent.
// It is written below for demonstration purposes but commented out.
// -----------------------------------------------------------------------
// backwardKeyframesGenerator: () => {
// // return Keyframes (Keyframe[])
// return [
// {}, // Keyframe 1
// {scale: initialScale, opacity: 0} // Keyframe 2
// ];
// },
};
}
},
},
customMotionEffects: {
// -----------------------------------------------------------------
// ----------------------------EXAMPLE 2----------------------------
// -----------------------------------------------------------------
// Let us pretend you made this custom animation effect for moving an element rightward.
// For this animation, you wrote the forward keyframes generator and then
// checked to see if the desired rewinding effect could be achieved by just reusing
// forwardKeyframesGenerator() and reversing the result. You realize that this effect is NOT
// a candidate for that shortcut, so you write backwardKeyframesEffect.
translateRight: {
composeEffect(numPixels: number) {
// a helper function you wrote that will exist within a closure scoped to composeEffect()
const createTranslationString = () => {
if (numPixels <= 0) { throw RangeError(`Number of pixels must exceed 0.`) }
const translationString = `${numPixels}px`;
return translationString;
}
// return ComposedEffect
return {
forwardKeyframesGenerator: () => {
// return Keyframes (Keyframe[])
return [
{translate: createTranslationString()} // Keyframe
];
},
// backwardKeyframesGenerator() must be specified because reversing the keyframes produced
// by forwardKeyframesGenerator() would not have the intended effect (because of
// {composite: accumulate}, trying to simply use the reversal of
// {translate: createTranslationString()} from forwardKeyframesGenerator() would actually
// cause the target element to jump an additional numPixels pixels to the right
// before sliding left, which is not the intended rewinding effect).
backwardKeyframesGenerator: () => {
// return Keyframes (Keyframe[])
return [
{translate: '-'+createTranslationString()}, // Keyframe
];
},
};
},
immutableConfig: {
// this means that the translation is added onto the element's position
// instead of replacing it
composite: 'accumulate',
},
effectCompositionFrequency: 'on-first-play-only',
},
}
});
const element = document.querySelector('.some-element');
(async () => {
const ent = clipFactories.Entrance(element, 'zoomIn', [0.2]);
await ent.play();
// ↑ forwardKeyframesGenerator() will run and produce the Keyframe array
// [{scale: initialScale, opacity: 0}, {scale: 1, opacity: 1}].
// That Keyframe array is used for the animation effect as the clip plays forward.
await ent.rewind();
// ↑ Since backwardKeyframesGenerator() was not set, the clip will run forwardKeyframesGenerator()
// again and just use its effect in reverse when rewinding (which would be exactly equivalent
// to specifying backwardKeyframesGenerator() and having it return
// [{}, {scale: initialScale, opacity: 0}]).
// In other words, forwardKeyframesGenerator() will run again to produce the Keyframe array
// [{scale: initialScale, opacity: 0}, {}], then
// the Keyframe array is used for the animation effect but set to go in reverse,
// and the effect is used as the clip rewinds.
const mot = clipFactories.Motion(element, 'translateRight', [756]);
await mot.play();
// ↑ forwardKeyframesGenerator() will run and produce the Keyframes array [{translate: '756px'}].
// That Keyframe array is used for the animation effect as the clip plays.
await mot.rewind();
// ↑ backwawrdFramesGenerator() will run and produce the Keyframe array [{translate: '-756px'}].
// That Keyframe array is used for the animation effect as the clip rewinds.
})();
Optional
forwardPerforms any necessary operations/computations and then returns keyframes (Keyframes).
Keyframes, either in the form of a PropertyIndexedKeyframes object or—more commonly—an array of Keyframe objects.
const clipFactories = webchalk.createAnimationClipFactories({
customEntranceEffects: {
// -----------------------------------------------------------------
// ----------------------------EXAMPLE 1----------------------------
// -----------------------------------------------------------------
// Let us pretend you made this custom entrance animation effect named 'zoomIn'.
// For this animation, you wrote the forward keyframes generator and
// then verified that the desired rewinding effect is exactly equivalent
// to playing the keyframes produced by forwardKeyframesGenerator() in reverse,
// so you omit backwardKeyframesGenerator.
zoomIn: {
composeEffect(initialScale: number) {
// return ComposedEffect
return {
forwardKeyframesGenerator: () => {
console.log('About to return keyframes!');
// return Keyframes (Keyframe[])
return [
{scale: initialScale, opacity: 0}, // Keyframe 1
{} // Keyframe 2
];
},
// backwardKeyframesGenerator() can be omitted in this case because
// the reversal of the forward keyframes is exactly equivalent.
// It is written below for demonstration purposes but commented out.
// -----------------------------------------------------------------------
// backwardKeyframesGenerator: () => {
// // return Keyframes (Keyframe[])
// return [
// {}, // Keyframe 1
// {scale: initialScale, opacity: 0} // Keyframe 2
// ];
// },
};
}
},
},
customMotionEffects: {
// -----------------------------------------------------------------
// ----------------------------EXAMPLE 2----------------------------
// -----------------------------------------------------------------
// Let us pretend you made this custom animation effect for moving an element rightward.
// For this animation, you wrote the forward keyframes generator and then
// checked to see if the desired rewinding effect could be achieved by just reusing
// forwardKeyframesGenerator() and reversing the result. You realize that this effect is NOT
// a candidate for that shortcut, so you write backwardKeyframesEffect.
translateRight: {
composeEffect(numPixels: number) {
// a helper function you wrote that will exist within a closure scoped to composeEffect()
const createTranslationString = () => {
if (numPixels <= 0) { throw RangeError(`Number of pixels must exceed 0.`) }
const translationString = `${numPixels}px`;
return translationString;
}
// return ComposedEffect
return {
forwardKeyframesGenerator: () => {
// return Keyframes (Keyframe[])
return [
{translate: createTranslationString()} // Keyframe
];
},
// backwardKeyframesGenerator() must be specified because reversing the keyframes produced
// by forwardKeyframesGenerator() would not have the intended effect (because of
// {composite: accumulate}, trying to simply use the reversal of
// {translate: createTranslationString()} from forwardKeyframesGenerator() would actually
// cause the target element to jump an additional numPixels pixels to the right
// before sliding left, which is not the intended rewinding effect).
backwardKeyframesGenerator: () => {
// return Keyframes (Keyframe[])
return [
{translate: '-'+createTranslationString()}, // Keyframe
];
},
};
},
immutableConfig: {
// this means that the translation is added onto the element's position
// instead of replacing it
composite: 'accumulate',
},
effectCompositionFrequency: 'on-first-play-only',
},
}
});
const element = document.querySelector('.some-element');
(async () => {
const ent = clipFactories.Entrance(element, 'zoomIn', [0.2]);
await ent.play();
// ↑ forwardKeyframesGenerator() will run and produce the Keyframe array
// [{scale: initialScale, opacity: 0}, {scale: 1, opacity: 1}].
// That Keyframe array is used for the animation effect as the clip plays forward.
await ent.rewind();
// ↑ Since backwardKeyframesGenerator() was not set, the clip will run forwardKeyframesGenerator()
// again and just use its effect in reverse when rewinding (which would be exactly equivalent
// to specifying backwardKeyframesGenerator() and having it return
// [{}, {scale: initialScale, opacity: 0}]).
// In other words, forwardKeyframesGenerator() will run again to produce the Keyframe array
// [{scale: initialScale, opacity: 0}, {}], then
// the Keyframe array is used for the animation effect but set to go in reverse,
// and the effect is used as the clip rewinds.
const mot = clipFactories.Motion(element, 'translateRight', [756]);
await mot.play();
// ↑ forwardKeyframesGenerator() will run and produce the Keyframes array [{translate: '756px'}].
// That Keyframe array is used for the animation effect as the clip plays.
await mot.rewind();
// ↑ backwawrdFramesGenerator() will run and produce the Keyframe array [{translate: '-756px'}].
// That Keyframe array is used for the animation effect as the clip rewinds.
})();
Optional
reverseIf true
, the effect specified by the keyframes generators will be reversed.
Optional
backwardPerforms any necessary operations/computations and then returns a function that will be run on every frame.
A function that presumably mutates the target element in some way (possibly with the help of AnimClip.computeTween) and will automatically be run on every frame. Since it will be run on every frame, it will create the illusion of a smooth animation.
const clipFactories = webchalk.createAnimationClipFactories({
customMotionEffects: {
// a custom animation for scrolling to a specific point on the page.
scrollTo: {
composeEffect(yPosition: number) {
const initialPosition = this.domElem.scrollTop;
// return ComposedEffect
return {
// The mutation is to use the scrollTo() method on the element.
// Thanks to computeTween(), there will be a smooth scroll
// from initialPosition to yPosition
forwardMutatorGenerator: () => {
// return Mutator
return () => {
this.domElem.scrollTo({
top: this.computeTween(initialPosition, yPosition),
behavior: 'instant'
});
};
},
// The forward mutation loop is not invertible because reversing it requires
// re-computing the element's scroll position at the time of rewinding
// (which may have since changed for any number of reasons, including user
// scrolling, size changes, etc.). So we must define backwardMutatorGenerator()
// to do exactly that.
backwardMutatorGenerator: () => {
// return Mutator
return () => {
const currentPosition = this.domElem.scrollTop;
this.domElem.scrollTo({
top: this.computeTween(currentPosition, initialPosition),
behavior: 'instant'
});
};
},
};
}
},
}
});
const element = document.querySelector('.some-element');
const mot = clipFactories.Motion(element, 'scrollTo', [1020]);
mot.play().then(mot.rewind);
Optional
forwardPerforms any necessary operations/computations and then returns a function that will be run on every frame.
A function that presumably mutates the target element in some way (possibly with the help of AnimClip.computeTween) and will automatically be run on every frame. Since it will be run on every frame, it will create the illusion of a smooth animation.
const clipFactories = webchalk.createAnimationClipFactories({
customMotionEffects: {
// a custom animation for scrolling to a specific point on the page.
scrollTo: {
composeEffect(yPosition: number) {
const initialPosition = this.domElem.scrollTop;
// return ComposedEffect
return {
// The mutation is to use the scrollTo() method on the element.
// Thanks to computeTween(), there will be a smooth scroll
// from initialPosition to yPosition
forwardMutatorGenerator: () => {
// return Mutator
return () => {
this.domElem.scrollTo({
top: this.computeTween(initialPosition, yPosition),
behavior: 'instant'
});
};
},
// The forward mutation loop is not invertible because reversing it requires
// re-computing the element's scroll position at the time of rewinding
// (which may have since changed for any number of reasons, including user
// scrolling, size changes, etc.). So we must define backwardMutatorGenerator()
// to do exactly that.
backwardMutatorGenerator: () => {
// return Mutator
return () => {
const currentPosition = this.domElem.scrollTop;
this.domElem.scrollTo({
top: this.computeTween(currentPosition, initialPosition),
behavior: 'instant'
});
};
},
};
}
},
}
});
const element = document.querySelector('.some-element');
const mot = clipFactories.Motion(element, 'scrollTo', [1020]);
mot.play().then(mot.rewind);
Optional
reverseIf true
, the effect specified by the mutator generators will be reversed.
Contains up to 4 callback functions that will be called to produce the effect for an animation clip. Returned by EffectComposer.composeEffect.
See
EffectComposer.composeEffect