/**
* Easing functions for animation segments.
* @module j5e/easing
* @see {@link https://easings.net/en#|easings.net} to help understand easing functions
*
* @example
* <caption>Easing by keyFrame. Move a servo from 0° to 180° with inOutQuad easing and then back to 0° with outBounce</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutQuad, outBunce } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 8000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [ 0, { value: 180, easing: inOutQuad }, {value: 0, easing: outBounce }]
* };
*
* ani.enqueue(wave);
*/
const SI = 1.70158;
const SIO = 1.70158 * 1.525;
const SB = 7.5625;
const HALF = 0.5;
const {
PI,
cos,
sin,
sqrt,
} = Math;
/** Linear
* @param {Number} input value [0, 1]
* @returns {Number}
* @ignore
*/
export function linear(n) {
return n;
};
/** inQuad
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInQuad|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inQuad easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inQuad } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inQuad
* };
*
* ani.enqueue(wave);
*/
export function inQuad(n) {
return n ** 2;
};
/** outQuad
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutQuad|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outQuad easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outQuad } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outQuad }]
* };
*
* ani.enqueue(wave);
*/
export function outQuad(n) {
return n * (2 - n);
};
/** inOutQuad
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutQuad|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutQuad easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutQuad } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutQuad
* };
*
* ani.enqueue(wave);
*/
export function inOutQuad(n) {
n *= 2;
return n < 1 ?
HALF * n * n :
-HALF * (--n * (n - 2) - 1);
};
/** inCube
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInCubic|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inCube easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inCube } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inCube
* };
*
* ani.enqueue(wave);
*/
export function inCube(n) {
return n ** 3;
};
/** outCube
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutCubic|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outCube easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outCube } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outCube }]
* };
*
* ani.enqueue(wave);
*/
export function outCube(n) {
return --n * n * n + 1;
};
/** inOutCube
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutCubic|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutCube easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutCube } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutCube
* };
*
* ani.enqueue(wave);
*/
export function inOutCube(n) {
n *= 2;
return n < 1 ?
HALF * n ** 3 :
HALF * ((n -= 2) * n * n + 2);
};
/** inQuart
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInQuart|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inQuart easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inQuart } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inQuart
* };
*
* ani.enqueue(wave);
*/
export function inQuart(n) {
return n ** 4;
};
/** outQuart
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutQuart|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outQuart easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outQuart } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outQuart }]
* };
*
* ani.enqueue(wave);
*/
export function outQuart(n) {
return 1 - (--n * n ** 3);
};
/** inOutQuart
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutQuart|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutQuart easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutQuart } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutQuart
* };
*
* ani.enqueue(wave);
*/
export function inOutQuart(n) {
n *= 2;
return n < 1 ?
HALF * n ** 4 :
-HALF * ((n -= 2) * n ** 3 - 2);
};
/** inQuint
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInQuint|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inQuint easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inQuint } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inQuint
* };
*
* ani.enqueue(wave);
*/
export function inQuint(n) {
return n ** 5;
};
/** outQuint
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutQuint|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outQuint easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outQuint } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outQuint }]
* };
*
* ani.enqueue(wave);
*/
export function outQuint(n) {
return --n * n ** 4 + 1;
};
/** inOutQuint
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutQuint|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutQuint easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutQuint } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutQuint
* };
*
* ani.enqueue(wave);
*/
export function inOutQuint(n) {
n *= 2;
return n < 1 ?
HALF * n ** 5 :
HALF * ((n -= 2) * n ** 4 + 2);
};
/** inSine
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInSine|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inSine easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inSine } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inSine
* };
*
* ani.enqueue(wave);
*/
export function inSine(n) {
return 1 - cos(n * PI / 2);
};
/** outSine
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutSine|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outSine easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outSine } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outSine }]
* };
*
* ani.enqueue(wave);
*/
export function outSine(n) {
return sin(n * PI / 2);
};
/** inOutSine
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutSine|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutSine easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutSine } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutSine
* };
*
* ani.enqueue(wave);
*/
export function inOutSine(n) {
return HALF * (1 - cos(PI * n));
};
/** inExpo
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInExpo|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inExpo easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inExpo } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inExpo
* };
*
* ani.enqueue(wave);
*/
export function inExpo(n) {
return 0 === n ? 0 : 1024 ** (n - 1);
};
/** outExpo
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutExpo|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outExpo easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outExpo } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outExpo }]
* };
*
* ani.enqueue(wave);
*/
export function outExpo(n) {
return 1 === n ? n : 1 - 2 ** (-10 * n);
};
/** inOutExpo
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutExpo|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutExpo easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutExpo } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutExpo
* };
*
* ani.enqueue(wave);
*/
export function inOutExpo(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return (n *= 2) < 1 ?
HALF * (1024 ** (n - 1)) :
HALF * (-(2 ** (-10 * (n - 1))) + 2);
};
/** inCirc
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInCirc|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inCirc easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inCirc } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inCirc
* };
*
* ani.enqueue(wave);
*/
export function inCirc(n) {
return 1 - sqrt(1 - n * n);
};
/** outCirc
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutCirc|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outCirc easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outCirc } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outCirc }]
* };
*
* ani.enqueue(wave);
*/
export function outCirc(n) {
return sqrt(1 - (--n * n));
};
/** inOutCirc
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutCirc|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutCirc easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutCirc } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutCirc
* };
*
* ani.enqueue(wave);
*/
export function inOutCirc(n) {
n *= 2;
return (n < 1) ?
-HALF * (sqrt(1 - n * n) - 1) :
HALF * (sqrt(1 - (n -= 2) * n) + 1);
};
/** inBack
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInBack|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inBack easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inBack } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inBack
* };
*
* ani.enqueue(wave);
*/
export function inBack(n) {
return n * n * ((SI + 1) * n - SI);
};
/** outBack
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutBack|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outBack easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outBack } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outBack }]
* };
*
* ani.enqueue(wave);
*/
export function outBack(n) {
return --n * n * ((SI + 1) * n + SI) + 1;
};
/** inOutBack
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutBack|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutBack easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutBack } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutBack
* };
*
* ani.enqueue(wave);
*/
export function inOutBack(n) {
return (n *= 2) < 1 ?
HALF * (n * n * ((SIO + 1) * n - SIO)) :
HALF * ((n -= 2) * n * ((SIO + 1) * n + SIO) + 2);
};
/** inBounce
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInBounce|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inBounce easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inBounce } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inBounce
* };
*
* ani.enqueue(wave);
*/
export function inBounce(n) {
return 1 - outBounce(1 - n);
}
/** outBounce
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeOutBounce|easings.net} for details
* @example
* <caption>Ease an animation segment. Move a servo from 0° to 90° with linear easing and then 90° to 180° with outBounce easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { outBounce } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 0.5, 1],
* keyFrames: [0, 90, { value: 180, easing: outBounce }]
* };
*
* ani.enqueue(wave);
*/
export function outBounce(n) {
if (n < (1 / 2.75)) {
return SB * n * n;
} else if (n < (2 / 2.75)) {
return SB * (n -= (1.5 / 2.75)) * n + 0.75;
} else if (n < (2.5 / 2.75)) {
return SB * (n -= (2.25 / 2.75)) * n + 0.9375;
} else {
return SB * (n -= (2.625 / 2.75)) * n + 0.984375;
}
};
/** inOutBounce
* @param {Number} input value [0, 1]
* @returns {Number}
* @see {@link https://easings.net/en#easeInOutBounce|easings.net} for details
* @example
* <caption>Ease the entire animation. Move a servo from 0° to 180° with inOutBounce easing.</caption>
* import Servo from "j5e/servo";
* import Animation from "j5e/animation";
* import { inOutBounce } from "j5e/easing";
*
* const servo = await new Servo(13);
* const ani = await new Animation(servo);
*
* const wave = {
* duration: 4000,
* cuePoints: [0, 1],
* keyFrames: [0, 180],
* easing: inOutBounce
* };
*
* ani.enqueue(wave);
*/
export function inOutBounce(n) {
return n < HALF ?
inBounce(n * 2) * HALF :
outBounce(n * 2 - 1) * HALF + HALF;
};