feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
@@ -0,0 +1,4 @@
export declare const syncDriver: (interval?: number) => (update: (v: number) => void) => {
start: () => void;
stop: () => boolean;
};
+14
View File
@@ -0,0 +1,14 @@
export const syncDriver = (interval = 10) => (update) => {
let isRunning = true;
return {
start: () => {
setTimeout(() => {
update(0);
while (isRunning)
update(interval);
}, 0);
},
stop: () => (isRunning = false),
};
};
//# sourceMappingURL=utils.js.map
@@ -0,0 +1,2 @@
import { Animation } from "../../types";
export declare function animateSync(animation: Animation<number>, timeStep?: number, round?: boolean): number[];
@@ -0,0 +1,13 @@
export function animateSync(animation, timeStep = 200, round = true) {
const output = [];
let step = 0;
let done = false;
while (!done) {
const latest = animation.next(step * timeStep);
output.push(round ? Math.round(latest.value) : latest.value);
done = latest.done;
step++;
}
return output;
}
//# sourceMappingURL=utils.js.map
@@ -0,0 +1,2 @@
import { Animation, DecayOptions } from "../types";
export declare function decay({ velocity, from, power, timeConstant, restDelta, modifyTarget, }: DecayOptions): Animation<number>;
@@ -0,0 +1,18 @@
export function decay({ velocity = 0, from = 0, power = 0.8, timeConstant = 350, restDelta = 0.5, modifyTarget, }) {
const state = { done: false, value: from };
let amplitude = power * velocity;
const ideal = from + amplitude;
const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);
if (target !== ideal)
amplitude = target - from;
return {
next: (t) => {
const delta = -amplitude * Math.exp(-t / timeConstant);
state.done = !(delta > restDelta || delta < -restDelta);
state.value = state.done ? target : target + delta;
return state;
},
flipTarget: () => { },
};
}
//# sourceMappingURL=decay.js.map
@@ -0,0 +1,6 @@
import { Animation, KeyframeOptions } from "../types";
import { Easing } from "../../easing/types";
export declare function defaultEasing(values: any[], easing?: Easing): Easing[];
export declare function defaultOffset(values: any[]): number[];
export declare function convertOffsetToTimes(offset: number[], duration: number): number[];
export declare function keyframes<V>({ from, to, ease, offset, duration, }: KeyframeOptions): Animation<number | string>;
@@ -0,0 +1,37 @@
import { interpolate } from "../../utils/interpolate";
import { easeInOut } from "../../easing";
export function defaultEasing(values, easing) {
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
}
export function defaultOffset(values) {
const numValues = values.length;
return values.map((_value, i) => i !== 0 ? i / (numValues - 1) : 0);
}
export function convertOffsetToTimes(offset, duration) {
return offset.map((o) => o * duration);
}
export function keyframes({ from = 0, to = 1, ease, offset, duration = 300, }) {
const state = { done: false, value: from };
const values = Array.isArray(to) ? to : [from, to];
const times = convertOffsetToTimes(offset && offset.length === values.length
? offset
: defaultOffset(values), duration);
function createInterpolator() {
return interpolate(times, values, {
ease: Array.isArray(ease) ? ease : defaultEasing(values, ease),
});
}
let interpolator = createInterpolator();
return {
next: (t) => {
state.value = interpolator(t);
state.done = t >= duration;
return state;
},
flipTarget: () => {
values.reverse();
interpolator = createInterpolator();
},
};
}
//# sourceMappingURL=keyframes.js.map
@@ -0,0 +1,5 @@
import { SpringOptions, Animation } from "../types";
export declare function spring({ from, to, restSpeed, restDelta, ...options }: SpringOptions): Animation<number>;
export declare namespace spring {
var needsInterpolation: (a: any, b: any) => boolean;
}
@@ -0,0 +1,117 @@
import { __rest } from "tslib";
import { calcAngularFreq, findSpring } from "../utils/find-spring";
const durationKeys = ["duration", "bounce"];
const physicsKeys = ["stiffness", "damping", "mass"];
function isSpringType(options, keys) {
return keys.some((key) => options[key] !== undefined);
}
function getSpringOptions(options) {
let springOptions = Object.assign({ velocity: 0.0, stiffness: 100, damping: 10, mass: 1.0, isResolvedFromDuration: false }, options);
if (!isSpringType(options, physicsKeys) &&
isSpringType(options, durationKeys)) {
const derived = findSpring(options);
springOptions = Object.assign(Object.assign(Object.assign({}, springOptions), derived), { velocity: 0.0, mass: 1.0 });
springOptions.isResolvedFromDuration = true;
}
return springOptions;
}
export function spring(_a) {
var { from = 0.0, to = 1.0, restSpeed = 2, restDelta } = _a, options = __rest(_a, ["from", "to", "restSpeed", "restDelta"]);
const state = { done: false, value: from };
let { stiffness, damping, mass, velocity, duration, isResolvedFromDuration, } = getSpringOptions(options);
let resolveSpring = zero;
let resolveVelocity = zero;
function createSpring() {
const initialVelocity = velocity ? -(velocity / 1000) : 0.0;
const initialDelta = to - from;
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;
if (restDelta === undefined) {
restDelta = Math.min(Math.abs(to - from) / 100, 0.4);
}
if (dampingRatio < 1) {
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
resolveSpring = (t) => {
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
return (to -
envelope *
(((initialVelocity +
dampingRatio * undampedAngularFreq * initialDelta) /
angularFreq) *
Math.sin(angularFreq * t) +
initialDelta * Math.cos(angularFreq * t)));
};
resolveVelocity = (t) => {
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
return (dampingRatio *
undampedAngularFreq *
envelope *
((Math.sin(angularFreq * t) *
(initialVelocity +
dampingRatio *
undampedAngularFreq *
initialDelta)) /
angularFreq +
initialDelta * Math.cos(angularFreq * t)) -
envelope *
(Math.cos(angularFreq * t) *
(initialVelocity +
dampingRatio *
undampedAngularFreq *
initialDelta) -
angularFreq *
initialDelta *
Math.sin(angularFreq * t)));
};
}
else if (dampingRatio === 1) {
resolveSpring = (t) => to -
Math.exp(-undampedAngularFreq * t) *
(initialDelta +
(initialVelocity + undampedAngularFreq * initialDelta) *
t);
}
else {
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
resolveSpring = (t) => {
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
const freqForT = Math.min(dampedAngularFreq * t, 300);
return (to -
(envelope *
((initialVelocity +
dampingRatio * undampedAngularFreq * initialDelta) *
Math.sinh(freqForT) +
dampedAngularFreq *
initialDelta *
Math.cosh(freqForT))) /
dampedAngularFreq);
};
}
}
createSpring();
return {
next: (t) => {
const current = resolveSpring(t);
if (!isResolvedFromDuration) {
const currentVelocity = resolveVelocity(t) * 1000;
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
const isBelowDisplacementThreshold = Math.abs(to - current) <= restDelta;
state.done =
isBelowVelocityThreshold && isBelowDisplacementThreshold;
}
else {
state.done = t >= duration;
}
state.value = state.done ? to : current;
return state;
},
flipTarget: () => {
velocity = -velocity;
[from, to] = [to, from];
createSpring();
},
};
}
spring.needsInterpolation = (a, b) => typeof a === "string" || typeof b === "string";
const zero = (_t) => 0;
//# sourceMappingURL=spring.js.map
+4
View File
@@ -0,0 +1,4 @@
import { AnimationOptions } from "./types";
export declare function animate<V = number>({ from, autoplay, driver, elapsed, repeat: repeatMax, repeatType, repeatDelay, onPlay, onStop, onComplete, onRepeat, onUpdate, ...options }: AnimationOptions<V>): {
stop: () => void;
};
+87
View File
@@ -0,0 +1,87 @@
import { __rest } from "tslib";
import { detectAnimationFromOptions } from "./utils/detect-animation-from-options";
import sync, { cancelSync } from "framesync";
import { interpolate } from "../utils/interpolate";
import { loopElapsed, reverseElapsed, hasRepeatDelayElapsed, } from "./utils/elapsed";
const framesync = (update) => {
const passTimestamp = ({ delta }) => update(delta);
return {
start: () => sync.update(passTimestamp, true),
stop: () => cancelSync.update(passTimestamp),
};
};
export function animate(_a) {
var _b, _c;
var { from, autoplay = true, driver = framesync, elapsed = 0, repeat: repeatMax = 0, repeatType = "loop", repeatDelay = 0, onPlay, onStop, onComplete, onRepeat, onUpdate } = _a, options = __rest(_a, ["from", "autoplay", "driver", "elapsed", "repeat", "repeatType", "repeatDelay", "onPlay", "onStop", "onComplete", "onRepeat", "onUpdate"]);
let { to } = options;
let driverControls;
let repeatCount = 0;
let computedDuration = options.duration;
let latest;
let isComplete = false;
let isForwardPlayback = true;
let interpolateFromNumber;
const animator = detectAnimationFromOptions(options);
if ((_c = (_b = animator).needsInterpolation) === null || _c === void 0 ? void 0 : _c.call(_b, from, to)) {
interpolateFromNumber = interpolate([0, 100], [from, to], {
clamp: false,
});
from = 0;
to = 100;
}
const animation = animator(Object.assign(Object.assign({}, options), { from, to }));
function repeat() {
repeatCount++;
if (repeatType === "reverse") {
isForwardPlayback = repeatCount % 2 === 0;
elapsed = reverseElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback);
}
else {
elapsed = loopElapsed(elapsed, computedDuration, repeatDelay);
if (repeatType === "mirror")
animation.flipTarget();
}
isComplete = false;
onRepeat && onRepeat();
}
function complete() {
driverControls.stop();
onComplete && onComplete();
}
function update(delta) {
if (!isForwardPlayback)
delta = -delta;
elapsed += delta;
if (!isComplete) {
const state = animation.next(Math.max(0, elapsed));
latest = state.value;
if (interpolateFromNumber)
latest = interpolateFromNumber(latest);
isComplete = isForwardPlayback ? state.done : elapsed <= 0;
}
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(latest);
if (isComplete) {
if (repeatCount === 0)
computedDuration !== null && computedDuration !== void 0 ? computedDuration : (computedDuration = elapsed);
if (repeatCount < repeatMax) {
hasRepeatDelayElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback) && repeat();
}
else {
complete();
}
}
}
function play() {
onPlay === null || onPlay === void 0 ? void 0 : onPlay();
driverControls = driver(update);
driverControls.start();
}
autoplay && play();
return {
stop: () => {
onStop === null || onStop === void 0 ? void 0 : onStop();
driverControls.stop();
},
};
}
//# sourceMappingURL=index.js.map
+4
View File
@@ -0,0 +1,4 @@
import { InertiaOptions } from "./types";
export declare function inertia({ from, velocity, min, max, power, timeConstant, bounceStiffness, bounceDamping, restDelta, modifyTarget, driver, onUpdate, onComplete, onStop, }: InertiaOptions): {
stop: () => void;
};
+63
View File
@@ -0,0 +1,63 @@
import { animate } from ".";
import { velocityPerSecond } from "../utils/velocity-per-second";
import { getFrameData } from "framesync";
export function inertia({ from = 0, velocity = 0, min, max, power = 0.8, timeConstant = 750, bounceStiffness = 500, bounceDamping = 10, restDelta = 1, modifyTarget, driver, onUpdate, onComplete, onStop, }) {
let currentAnimation;
function isOutOfBounds(v) {
return (min !== undefined && v < min) || (max !== undefined && v > max);
}
function boundaryNearest(v) {
if (min === undefined)
return max;
if (max === undefined)
return min;
return Math.abs(min - v) < Math.abs(max - v) ? min : max;
}
function startAnimation(options) {
currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.stop();
currentAnimation = animate(Object.assign(Object.assign({}, options), { driver, onUpdate: (v) => {
var _a;
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(v);
(_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, v);
}, onComplete,
onStop }));
}
function startSpring(options) {
startAnimation(Object.assign({ type: "spring", stiffness: bounceStiffness, damping: bounceDamping, restDelta }, options));
}
if (isOutOfBounds(from)) {
startSpring({ from, velocity, to: boundaryNearest(from) });
}
else {
let target = power * velocity + from;
if (typeof modifyTarget !== "undefined")
target = modifyTarget(target);
const boundary = boundaryNearest(target);
const heading = boundary === min ? -1 : 1;
let prev;
let current;
const checkBoundary = (v) => {
prev = current;
current = v;
velocity = velocityPerSecond(v - prev, getFrameData().delta);
if ((heading === 1 && v > boundary) ||
(heading === -1 && v < boundary)) {
startSpring({ from: v, to: boundary, velocity });
}
};
startAnimation({
type: "decay",
from,
velocity,
timeConstant,
power,
restDelta,
modifyTarget,
onUpdate: isOutOfBounds(target) ? checkBoundary : undefined,
});
}
return {
stop: () => currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.stop(),
};
}
//# sourceMappingURL=inertia.js.map
+80
View File
@@ -0,0 +1,80 @@
import { Easing } from "../easing/types";
export interface Animation<V> {
next: (t: number) => {
value: V;
done: boolean;
};
flipTarget: () => void;
}
export interface AnimationState<V> {
value: V;
done: boolean;
}
export interface PlaybackControls {
stop: () => void;
}
declare type Update = (timestamp: number) => void;
export interface DriverControls {
start: () => void;
stop: () => void;
}
export declare type Driver = (update: Update) => DriverControls;
export interface PlaybackOptions<V> {
autoplay?: boolean;
driver?: Driver;
elapsed?: number;
from?: V;
repeat?: number;
repeatType?: "loop" | "reverse" | "mirror";
repeatDelay?: number;
type?: "spring" | "decay" | "keyframes";
onUpdate?: (latest: V) => void;
onPlay?: () => void;
onComplete?: () => void;
onRepeat?: () => void;
onStop?: () => void;
}
export interface KeyframeOptions<V = number> {
to: V | V[];
from?: V;
duration?: number;
ease?: Easing | Easing[];
offset?: number[];
}
export interface DecayOptions {
from?: number;
to?: number;
velocity?: number;
power?: number;
timeConstant?: number;
modifyTarget?: (target: number) => number;
restDelta?: number;
}
export interface PhysicsSpringOptions {
velocity?: number;
stiffness?: number;
damping?: number;
mass?: number;
}
export interface SpringOptions extends PhysicsSpringOptions {
from?: number;
to?: number;
duration?: number;
bounce?: number;
restSpeed?: number;
restDelta?: number;
}
export interface InertiaOptions extends DecayOptions {
bounceStiffness?: number;
bounceDamping?: number;
min?: number;
max?: number;
restSpeed?: number;
restDelta?: number;
driver?: Driver;
onUpdate?: (v: number) => void;
onComplete?: () => void;
onStop?: () => void;
}
export declare type AnimationOptions<V> = PlaybackOptions<V> & (DecayOptions | KeyframeOptions<V> | SpringOptions);
export {};
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=types.js.map
@@ -0,0 +1,9 @@
import { spring } from "../generators/spring";
import { keyframes } from "../generators/keyframes";
import { decay } from "../generators/decay";
interface Options {
to?: any;
type?: "decay" | "keyframes" | "spring";
}
export declare function detectAnimationFromOptions<T extends Options>(config: T): typeof spring | typeof keyframes | typeof decay;
export {};
@@ -0,0 +1,27 @@
import { spring } from "../generators/spring";
import { keyframes } from "../generators/keyframes";
import { decay } from "../generators/decay";
const types = { keyframes, spring, decay };
export function detectAnimationFromOptions(config) {
if (Array.isArray(config.to)) {
return keyframes;
}
else if (types[config.type]) {
return types[config.type];
}
const keys = new Set(Object.keys(config));
if (keys.has("ease") ||
(keys.has("duration") && !keys.has("dampingRatio"))) {
return keyframes;
}
else if (keys.has("dampingRatio") ||
keys.has("stiffness") ||
keys.has("mass") ||
keys.has("damping") ||
keys.has("restSpeed") ||
keys.has("restDelta")) {
return spring;
}
return keyframes;
}
//# sourceMappingURL=detect-animation-from-options.js.map
@@ -0,0 +1,3 @@
export declare function loopElapsed(elapsed: number, duration: number, delay?: number): number;
export declare function reverseElapsed(elapsed: number, duration: number, delay?: number, isForwardPlayback?: boolean): number;
export declare function hasRepeatDelayElapsed(elapsed: number, duration: number, delay: number, isForwardPlayback: boolean): boolean;
+12
View File
@@ -0,0 +1,12 @@
export function loopElapsed(elapsed, duration, delay = 0) {
return elapsed - duration - delay;
}
export function reverseElapsed(elapsed, duration, delay = 0, isForwardPlayback = true) {
return isForwardPlayback
? loopElapsed(duration + -elapsed, duration, delay)
: duration - (elapsed - duration) + delay;
}
export function hasRepeatDelayElapsed(elapsed, duration, delay, isForwardPlayback) {
return isForwardPlayback ? elapsed >= duration + delay : elapsed <= -delay;
}
//# sourceMappingURL=elapsed.js.map
@@ -0,0 +1,11 @@
import { SpringOptions } from "../types";
export declare const minDuration = 0.01;
export declare const maxDuration = 10;
export declare const minDamping = 0.05;
export declare const maxDamping = 1;
export declare function findSpring({ duration, bounce, velocity, mass, }: SpringOptions): {
stiffness: number;
damping: number;
duration: number;
};
export declare function calcAngularFreq(undampedFreq: number, dampingRatio: number): number;
@@ -0,0 +1,77 @@
import { warning } from "hey-listen";
import { clamp } from "../../utils/clamp";
const safeMin = 0.001;
export const minDuration = 0.01;
export const maxDuration = 10.0;
export const minDamping = 0.05;
export const maxDamping = 1;
export function findSpring({ duration = 800, bounce = 0.25, velocity = 0, mass = 1, }) {
let envelope;
let derivative;
warning(duration <= maxDuration * 1000, "Spring duration must be 10 seconds or less");
let dampingRatio = 1 - bounce;
dampingRatio = clamp(minDamping, maxDamping, dampingRatio);
duration = clamp(minDuration, maxDuration, duration / 1000);
if (dampingRatio < 1) {
envelope = (undampedFreq) => {
const exponentialDecay = undampedFreq * dampingRatio;
const delta = exponentialDecay * duration;
const a = exponentialDecay - velocity;
const b = calcAngularFreq(undampedFreq, dampingRatio);
const c = Math.exp(-delta);
return safeMin - (a / b) * c;
};
derivative = (undampedFreq) => {
const exponentialDecay = undampedFreq * dampingRatio;
const delta = exponentialDecay * duration;
const d = delta * velocity + velocity;
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
const f = Math.exp(-delta);
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
return (factor * ((d - e) * f)) / g;
};
}
else {
envelope = (undampedFreq) => {
const a = Math.exp(-undampedFreq * duration);
const b = (undampedFreq - velocity) * duration + 1;
return -safeMin + a * b;
};
derivative = (undampedFreq) => {
const a = Math.exp(-undampedFreq * duration);
const b = (velocity - undampedFreq) * (duration * duration);
return a * b;
};
}
const initialGuess = 5 / duration;
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
duration = duration * 1000;
if (isNaN(undampedFreq)) {
return {
stiffness: 100,
damping: 10,
duration,
};
}
else {
const stiffness = Math.pow(undampedFreq, 2) * mass;
return {
stiffness,
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
duration,
};
}
}
const rootIterations = 12;
function approximateRoot(envelope, derivative, initialGuess) {
let result = initialGuess;
for (let i = 1; i < rootIterations; i++) {
result = result - envelope(result) / derivative(result);
}
return result;
}
export function calcAngularFreq(undampedFreq, dampingRatio) {
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
}
//# sourceMappingURL=find-spring.js.map
+1
View File
@@ -0,0 +1 @@
export declare function cubicBezier(mX1: number, mY1: number, mX2: number, mY2: number): import("./types").Easing;
+72
View File
@@ -0,0 +1,72 @@
import { linear } from ".";
const a = (a1, a2) => 1.0 - 3.0 * a2 + 3.0 * a1;
const b = (a1, a2) => 3.0 * a2 - 6.0 * a1;
const c = (a1) => 3.0 * a1;
const calcBezier = (t, a1, a2) => ((a(a1, a2) * t + b(a1, a2)) * t + c(a1)) * t;
const getSlope = (t, a1, a2) => 3.0 * a(a1, a2) * t * t + 2.0 * b(a1, a2) * t + c(a1);
const subdivisionPrecision = 0.0000001;
const subdivisionMaxIterations = 10;
function binarySubdivide(aX, aA, aB, mX1, mX2) {
let currentX;
let currentT;
let i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
}
else {
aA = currentT;
}
} while (Math.abs(currentX) > subdivisionPrecision &&
++i < subdivisionMaxIterations);
return currentT;
}
const newtonIterations = 8;
const newtonMinSlope = 0.001;
function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
for (let i = 0; i < newtonIterations; ++i) {
const currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
return aGuessT;
}
const currentX = calcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
const kSplineTableSize = 11;
const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
export function cubicBezier(mX1, mY1, mX2, mY2) {
if (mX1 === mY1 && mX2 === mY2)
return linear;
const sampleValues = new Float32Array(kSplineTableSize);
for (let i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
function getTForX(aX) {
let intervalStart = 0.0;
let currentSample = 1;
const lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
const dist = (aX - sampleValues[currentSample]) /
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
const guessForT = intervalStart + dist * kSampleStepSize;
const initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= newtonMinSlope) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
}
else if (initialSlope === 0.0) {
return guessForT;
}
else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
}
//# sourceMappingURL=cubic-bezier.js.map
+15
View File
@@ -0,0 +1,15 @@
import { Easing } from "./types";
export declare const linear: Easing;
export declare const easeIn: Easing;
export declare const easeOut: Easing;
export declare const easeInOut: Easing;
export declare const circIn: Easing;
export declare const circOut: Easing;
export declare const circInOut: Easing;
export declare const backIn: Easing;
export declare const backOut: Easing;
export declare const backInOut: Easing;
export declare const anticipate: Easing;
export declare const bounceOut: (p: number) => number;
export declare const bounceIn: Easing;
export declare const bounceInOut: (p: number) => number;
+36
View File
@@ -0,0 +1,36 @@
import { createExpoIn, reverseEasing, mirrorEasing, createBackIn, createAnticipate, } from "./utils";
const DEFAULT_OVERSHOOT_STRENGTH = 1.525;
const BOUNCE_FIRST_THRESHOLD = 4.0 / 11.0;
const BOUNCE_SECOND_THRESHOLD = 8.0 / 11.0;
const BOUNCE_THIRD_THRESHOLD = 9.0 / 10.0;
export const linear = p => p;
export const easeIn = createExpoIn(2);
export const easeOut = reverseEasing(easeIn);
export const easeInOut = mirrorEasing(easeIn);
export const circIn = p => 1 - Math.sin(Math.acos(p));
export const circOut = reverseEasing(circIn);
export const circInOut = mirrorEasing(circOut);
export const backIn = createBackIn(DEFAULT_OVERSHOOT_STRENGTH);
export const backOut = reverseEasing(backIn);
export const backInOut = mirrorEasing(backIn);
export const anticipate = createAnticipate(DEFAULT_OVERSHOOT_STRENGTH);
const ca = 4356.0 / 361.0;
const cb = 35442.0 / 1805.0;
const cc = 16061.0 / 1805.0;
export const bounceOut = (p) => {
if (p === 1 || p === 0)
return p;
const p2 = p * p;
return p < BOUNCE_FIRST_THRESHOLD
? 7.5625 * p2
: p < BOUNCE_SECOND_THRESHOLD
? 9.075 * p2 - 9.9 * p + 3.4
: p < BOUNCE_THIRD_THRESHOLD
? ca * p2 - cb * p + cc
: 10.8 * p * p - 20.52 * p + 10.72;
};
export const bounceIn = reverseEasing(bounceOut);
export const bounceInOut = (p) => p < 0.5
? 0.5 * (1.0 - bounceOut(1.0 - p * 2.0))
: 0.5 * bounceOut(p * 2.0 - 1.0) + 0.5;
//# sourceMappingURL=index.js.map
+3
View File
@@ -0,0 +1,3 @@
import { Easing } from './types';
export declare type Direction = 'start' | 'end';
export declare const steps: (steps: number, direction?: Direction) => Easing;
+9
View File
@@ -0,0 +1,9 @@
import { clamp } from '../utils/clamp';
export const steps = (steps, direction = 'end') => (progress) => {
progress =
direction === 'end' ? Math.min(progress, 0.999) : Math.max(progress, 0.001);
const expanded = progress * steps;
const rounded = direction === 'end' ? Math.floor(expanded) : Math.ceil(expanded);
return clamp(0, 1, rounded / steps);
};
//# sourceMappingURL=steps.js.map
+2
View File
@@ -0,0 +1,2 @@
export declare type Easing = (v: number) => number;
export declare type EasingModifier = (easing: Easing) => Easing;
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=types.js.map
+6
View File
@@ -0,0 +1,6 @@
import { Easing, EasingModifier } from "./types";
export declare const reverseEasing: EasingModifier;
export declare const mirrorEasing: EasingModifier;
export declare const createExpoIn: (power: number) => Easing;
export declare const createBackIn: (power: number) => Easing;
export declare const createAnticipate: (power: number) => Easing;
+11
View File
@@ -0,0 +1,11 @@
export const reverseEasing = easing => p => 1 - easing(1 - p);
export const mirrorEasing = easing => p => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
export const createExpoIn = (power) => p => Math.pow(p, power);
export const createBackIn = (power) => p => p * p * ((power + 1) * p - power);
export const createAnticipate = (power) => {
const backEasing = createBackIn(power);
return p => (p *= 2) < 1
? 0.5 * backEasing(p)
: 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
};
//# sourceMappingURL=utils.js.map
+34
View File
@@ -0,0 +1,34 @@
export { animate } from "./animations";
export { inertia } from "./animations/inertia";
export { decay } from "./animations/generators/decay";
export { spring } from "./animations/generators/spring";
export { keyframes } from "./animations/generators/keyframes";
export { angle } from "./utils/angle";
export { applyOffset } from "./utils/apply-offset";
export { createAttractor, attract, attractExpo } from "./utils/attract";
export { clamp } from "./utils/clamp";
export { degreesToRadians } from "./utils/degrees-to-radians";
export { distance } from "./utils/distance";
export { interpolate } from "./utils/interpolate";
export { isPoint3D } from "./utils/is-point-3d";
export { isPoint } from "./utils/is-point";
export { mixColor } from "./utils/mix-color";
export { mixComplex } from "./utils/mix-complex";
export { mix } from "./utils/mix";
export { pipe } from "./utils/pipe";
export { pointFromVector } from "./utils/point-from-vector";
export { progress } from "./utils/progress";
export { radiansToDegrees } from "./utils/radians-to-degrees";
export { smoothFrame } from "./utils/smooth-frame";
export { smooth } from "./utils/smooth";
export { snap } from "./utils/snap";
export { toDecimal } from "./utils/to-decimal";
export { velocityPerFrame } from "./utils/velocity-per-frame";
export { velocityPerSecond } from "./utils/velocity-per-second";
export { wrap } from "./utils/wrap";
export { linear, easeIn, easeInOut, easeOut, circIn, circInOut, circOut, backIn, backInOut, backOut, anticipate, bounceIn, bounceInOut, bounceOut, } from "./easing";
export { cubicBezier } from "./easing/cubic-bezier";
export { steps } from "./easing/steps";
export { mirrorEasing, reverseEasing, createExpoIn, createBackIn, createAnticipate, } from "./easing/utils";
export * from "./animations/types";
export * from "./easing/types";
+35
View File
@@ -0,0 +1,35 @@
export { animate } from "./animations";
export { inertia } from "./animations/inertia";
export { decay } from "./animations/generators/decay";
export { spring } from "./animations/generators/spring";
export { keyframes } from "./animations/generators/keyframes";
export { angle } from "./utils/angle";
export { applyOffset } from "./utils/apply-offset";
export { createAttractor, attract, attractExpo } from "./utils/attract";
export { clamp } from "./utils/clamp";
export { degreesToRadians } from "./utils/degrees-to-radians";
export { distance } from "./utils/distance";
export { interpolate } from "./utils/interpolate";
export { isPoint3D } from "./utils/is-point-3d";
export { isPoint } from "./utils/is-point";
export { mixColor } from "./utils/mix-color";
export { mixComplex } from "./utils/mix-complex";
export { mix } from "./utils/mix";
export { pipe } from "./utils/pipe";
export { pointFromVector } from "./utils/point-from-vector";
export { progress } from "./utils/progress";
export { radiansToDegrees } from "./utils/radians-to-degrees";
export { smoothFrame } from "./utils/smooth-frame";
export { smooth } from "./utils/smooth";
export { snap } from "./utils/snap";
export { toDecimal } from "./utils/to-decimal";
export { velocityPerFrame } from "./utils/velocity-per-frame";
export { velocityPerSecond } from "./utils/velocity-per-second";
export { wrap } from "./utils/wrap";
export { linear, easeIn, easeInOut, easeOut, circIn, circInOut, circOut, backIn, backInOut, backOut, anticipate, bounceIn, bounceInOut, bounceOut, } from "./easing";
export { cubicBezier } from "./easing/cubic-bezier";
export { steps } from "./easing/steps";
export { mirrorEasing, reverseEasing, createExpoIn, createBackIn, createAnticipate, } from "./easing/utils";
export * from "./animations/types";
export * from "./easing/types";
//# sourceMappingURL=index.js.map
+8
View File
@@ -0,0 +1,8 @@
export declare type Point2D = {
x: number;
y: number;
};
export declare type Point3D = Point2D & {
z: number;
};
export declare type Point = Point2D | Point3D;
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=types.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point } from '../types';
export declare const angle: (a: Point, b?: Point) => number;
+4
View File
@@ -0,0 +1,4 @@
import { radiansToDegrees } from './radians-to-degrees';
import { zeroPoint } from './inc';
export const angle = (a, b = zeroPoint) => radiansToDegrees(Math.atan2(b.y - a.y, b.x - a.x));
//# sourceMappingURL=angle.js.map
+1
View File
@@ -0,0 +1 @@
export declare const applyOffset: (from: number, to?: number) => (v: number) => number;
+18
View File
@@ -0,0 +1,18 @@
export const applyOffset = (from, to) => {
let hasReceivedFrom = true;
if (to === undefined) {
to = from;
hasReceivedFrom = false;
}
return (v) => {
if (hasReceivedFrom) {
return v - from + to;
}
else {
from = v;
hasReceivedFrom = true;
return to;
}
};
};
//# sourceMappingURL=apply-offset.js.map
+3
View File
@@ -0,0 +1,3 @@
export declare const createAttractor: (alterDisplacement?: Function) => (constant: number, origin: number, v: number) => number;
export declare const attract: (constant: number, origin: number, v: number) => number;
export declare const attractExpo: (constant: number, origin: number, v: number) => number;
+11
View File
@@ -0,0 +1,11 @@
const identity = (v) => v;
export const createAttractor = (alterDisplacement = identity) => (constant, origin, v) => {
const displacement = origin - v;
const springModifiedDisplacement = -(0 - constant + 1) * (0 - alterDisplacement(Math.abs(displacement)));
return displacement <= 0
? origin + springModifiedDisplacement
: origin - springModifiedDisplacement;
};
export const attract = createAttractor();
export const attractExpo = createAttractor(Math.sqrt);
//# sourceMappingURL=attract.js.map
+1
View File
@@ -0,0 +1 @@
export declare const clamp: (min: number, max: number, v: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const clamp = (min, max, v) => Math.min(Math.max(v, min), max);
//# sourceMappingURL=clamp.js.map
@@ -0,0 +1 @@
export declare const degreesToRadians: (degrees: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const degreesToRadians = (degrees) => (degrees * Math.PI) / 180;
//# sourceMappingURL=degrees-to-radians.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point } from "../types";
export declare function distance<P extends Point | number>(a: P, b: P): number;
+16
View File
@@ -0,0 +1,16 @@
import { isPoint } from "./is-point";
import { isPoint3D } from "./is-point-3d";
import { isNum } from "./inc";
const distance1D = (a, b) => Math.abs(a - b);
export function distance(a, b) {
if (isNum(a) && isNum(b)) {
return distance1D(a, b);
}
else if (isPoint(a) && isPoint(b)) {
const xDelta = distance1D(a.x, b.x);
const yDelta = distance1D(a.y, b.y);
const zDelta = isPoint3D(a) && isPoint3D(b) ? distance1D(a.z, b.z) : 0;
return Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2) + Math.pow(zDelta, 2));
}
}
//# sourceMappingURL=distance.js.map
+2
View File
@@ -0,0 +1,2 @@
import { HSLA, RGBA } from "style-value-types";
export declare function hslaToRgba({ hue, saturation, lightness, alpha }: HSLA): RGBA;
+40
View File
@@ -0,0 +1,40 @@
function hueToRgb(p, q, t) {
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t < 1 / 6)
return p + (q - p) * 6 * t;
if (t < 1 / 2)
return q;
if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
export function hslaToRgba({ hue, saturation, lightness, alpha }) {
hue /= 360;
saturation /= 100;
lightness /= 100;
let red = 0;
let green = 0;
let blue = 0;
if (!saturation) {
red = green = blue = lightness;
}
else {
const q = lightness < 0.5
? lightness * (1 + saturation)
: lightness + saturation - lightness * saturation;
const p = 2 * lightness - q;
red = hueToRgb(p, q, hue + 1 / 3);
green = hueToRgb(p, q, hue);
blue = hueToRgb(p, q, hue - 1 / 3);
}
return {
red: Math.round(red * 255),
green: Math.round(green * 255),
blue: Math.round(blue * 255),
alpha,
};
}
//# sourceMappingURL=hsla-to-rgba.js.map
+3
View File
@@ -0,0 +1,3 @@
import { Point } from '../types';
export declare const zeroPoint: Point;
export declare const isNum: (v: any) => v is number;
+7
View File
@@ -0,0 +1,7 @@
export const zeroPoint = {
x: 0,
y: 0,
z: 0
};
export const isNum = (v) => typeof v === 'number';
//# sourceMappingURL=inc.js.map
+11
View File
@@ -0,0 +1,11 @@
import { Easing } from '../easing/types';
declare type MixEasing = Easing | Easing[];
declare type InterpolateOptions<T> = {
clamp?: boolean;
ease?: MixEasing;
mixer?: MixerFactory<T>;
};
declare type Mix<T> = (v: number) => T;
export declare type MixerFactory<T> = (from: T, to: T) => Mix<T>;
export declare function interpolate<T>(input: number[], output: T[], { clamp: isClamp, ease, mixer }?: InterpolateOptions<T>): (v: number) => T;
export {};
+90
View File
@@ -0,0 +1,90 @@
import { progress } from './progress';
import { mix } from './mix';
import { mixColor } from './mix-color';
import { mixComplex, mixArray, mixObject } from './mix-complex';
import { color } from 'style-value-types';
import { clamp } from './clamp';
import { pipe } from './pipe';
import { invariant } from 'hey-listen';
const mixNumber = (from, to) => (p) => mix(from, to, p);
function detectMixerFactory(v) {
if (typeof v === 'number') {
return mixNumber;
}
else if (typeof v === 'string') {
if (color.test(v)) {
return mixColor;
}
else {
return mixComplex;
}
}
else if (Array.isArray(v)) {
return mixArray;
}
else if (typeof v === 'object') {
return mixObject;
}
}
function createMixers(output, ease, customMixer) {
const mixers = [];
const mixerFactory = customMixer || detectMixerFactory(output[0]);
const numMixers = output.length - 1;
for (let i = 0; i < numMixers; i++) {
let mixer = mixerFactory(output[i], output[i + 1]);
if (ease) {
const easingFunction = Array.isArray(ease) ? ease[i] : ease;
mixer = pipe(easingFunction, mixer);
}
mixers.push(mixer);
}
return mixers;
}
function fastInterpolate([from, to], [mixer]) {
return (v) => mixer(progress(from, to, v));
}
function slowInterpolate(input, mixers) {
const inputLength = input.length;
const lastInputIndex = inputLength - 1;
return (v) => {
let mixerIndex = 0;
let foundMixerIndex = false;
if (v <= input[0]) {
foundMixerIndex = true;
}
else if (v >= input[lastInputIndex]) {
mixerIndex = lastInputIndex - 1;
foundMixerIndex = true;
}
if (!foundMixerIndex) {
let i = 1;
for (; i < inputLength; i++) {
if (input[i] > v || i === lastInputIndex) {
break;
}
}
mixerIndex = i - 1;
}
const progressInRange = progress(input[mixerIndex], input[mixerIndex + 1], v);
return mixers[mixerIndex](progressInRange);
};
}
export function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {
const inputLength = input.length;
invariant(inputLength === output.length, 'Both input and output ranges must be the same length');
invariant(!ease || !Array.isArray(ease) || ease.length === inputLength - 1, 'Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.');
if (input[0] > input[inputLength - 1]) {
input = [].concat(input);
output = [].concat(output);
input.reverse();
output.reverse();
}
const mixers = createMixers(output, ease, mixer);
const interpolator = inputLength === 2
? fastInterpolate(input, mixers)
: slowInterpolate(input, mixers);
return isClamp
? (v) => interpolator(clamp(input[0], input[inputLength - 1], v))
: interpolator;
}
//# sourceMappingURL=interpolate.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point, Point3D } from '../types';
export declare const isPoint3D: (point: Point) => point is Point3D;
+3
View File
@@ -0,0 +1,3 @@
import { isPoint } from './is-point';
export const isPoint3D = (point) => isPoint(point) && point.hasOwnProperty('z');
//# sourceMappingURL=is-point-3d.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point } from '../types';
export declare const isPoint: (point: Object) => point is Point;
+2
View File
@@ -0,0 +1,2 @@
export const isPoint = (point) => point.hasOwnProperty('x') && point.hasOwnProperty('y');
//# sourceMappingURL=is-point.js.map
+3
View File
@@ -0,0 +1,3 @@
import { Color } from "style-value-types";
export declare const mixLinearColor: (from: number, to: number, v: number) => number;
export declare const mixColor: (from: Color | string, to: Color | string) => (v: number) => any;
+39
View File
@@ -0,0 +1,39 @@
import { mix } from "./mix";
import { hsla, rgba, hex } from "style-value-types";
import { invariant } from "hey-listen";
import { hslaToRgba } from "./hsla-to-rgba";
export const mixLinearColor = (from, to, v) => {
const fromExpo = from * from;
const toExpo = to * to;
return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo));
};
const colorTypes = [hex, rgba, hsla];
const getColorType = (v) => colorTypes.find((type) => type.test(v));
const notAnimatable = (color) => `'${color}' is not an animatable color. Use the equivalent color code instead.`;
export const mixColor = (from, to) => {
let fromColorType = getColorType(from);
let toColorType = getColorType(to);
invariant(!!fromColorType, notAnimatable(from));
invariant(!!toColorType, notAnimatable(to));
let fromColor = fromColorType.parse(from);
let toColor = toColorType.parse(to);
if (fromColorType === hsla) {
fromColor = hslaToRgba(fromColor);
fromColorType = rgba;
}
if (toColorType === hsla) {
toColor = hslaToRgba(toColor);
toColorType = rgba;
}
const blended = Object.assign({}, fromColor);
return (v) => {
for (const key in blended) {
if (key !== "alpha") {
blended[key] = mixLinearColor(fromColor[key], toColor[key], v);
}
}
blended.alpha = mix(fromColor.alpha, toColor.alpha, v);
return fromColorType.transform(blended);
};
};
//# sourceMappingURL=mix-color.js.map
+12
View File
@@ -0,0 +1,12 @@
import { RGBA, HSLA } from "style-value-types";
declare type MixComplex = (p: number) => string;
declare type BlendableArray = Array<number | RGBA | HSLA | string>;
declare type BlendableObject = {
[key: string]: string | number | RGBA | HSLA;
};
export declare const mixArray: (from: BlendableArray, to: BlendableArray) => (v: number) => (string | number | HSLA | RGBA)[];
export declare const mixObject: (origin: BlendableObject, target: BlendableObject) => (v: number) => {
[x: string]: string | number | HSLA | RGBA;
};
export declare const mixComplex: (origin: string | number, target: string | number) => MixComplex;
export {};
+80
View File
@@ -0,0 +1,80 @@
import { color, complex } from "style-value-types";
import { mix } from "./mix";
import { mixColor } from "./mix-color";
import { isNum } from "./inc";
import { pipe } from "./pipe";
import { warning } from "hey-listen";
function getMixer(origin, target) {
if (isNum(origin)) {
return (v) => mix(origin, target, v);
}
else if (color.test(origin)) {
return mixColor(origin, target);
}
else {
return mixComplex(origin, target);
}
}
export const mixArray = (from, to) => {
const output = [...from];
const numValues = output.length;
const blendValue = from.map((fromThis, i) => getMixer(fromThis, to[i]));
return (v) => {
for (let i = 0; i < numValues; i++) {
output[i] = blendValue[i](v);
}
return output;
};
};
export const mixObject = (origin, target) => {
const output = Object.assign(Object.assign({}, origin), target);
const blendValue = {};
for (const key in output) {
if (origin[key] !== undefined && target[key] !== undefined) {
blendValue[key] = getMixer(origin[key], target[key]);
}
}
return (v) => {
for (const key in blendValue) {
output[key] = blendValue[key](v);
}
return output;
};
};
function analyse(value) {
const parsed = complex.parse(value);
const numValues = parsed.length;
let numNumbers = 0;
let numRGB = 0;
let numHSL = 0;
for (let i = 0; i < numValues; i++) {
if (numNumbers || typeof parsed[i] === "number") {
numNumbers++;
}
else {
if (parsed[i].hue !== undefined) {
numHSL++;
}
else {
numRGB++;
}
}
}
return { parsed, numNumbers, numRGB, numHSL };
}
export const mixComplex = (origin, target) => {
const template = complex.createTransformer(target);
const originStats = analyse(origin);
const targetStats = analyse(target);
const canInterpolate = originStats.numHSL === targetStats.numHSL &&
originStats.numRGB === targetStats.numRGB &&
originStats.numNumbers >= targetStats.numNumbers;
if (canInterpolate) {
return pipe(mixArray(originStats.parsed, targetStats.parsed), template);
}
else {
warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);
return (p) => `${p > 0 ? target : origin}`;
}
};
//# sourceMappingURL=mix-complex.js.map
+1
View File
@@ -0,0 +1 @@
export declare const mix: (from: number, to: number, progress: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const mix = (from, to, progress) => -progress * from + progress * to + from;
//# sourceMappingURL=mix.js.map
+1
View File
@@ -0,0 +1 @@
export declare const pipe: (...transformers: Function[]) => Function;
+3
View File
@@ -0,0 +1,3 @@
const combineFunctions = (a, b) => (v) => b(a(v));
export const pipe = (...transformers) => transformers.reduce(combineFunctions);
//# sourceMappingURL=pipe.js.map
@@ -0,0 +1,5 @@
import { Point2D } from '../types';
export declare const pointFromVector: (origin: Point2D, angle: number, distance: number) => {
x: number;
y: number;
};
+9
View File
@@ -0,0 +1,9 @@
import { degreesToRadians } from './degrees-to-radians';
export const pointFromVector = (origin, angle, distance) => {
angle = degreesToRadians(angle);
return {
x: distance * Math.cos(angle) + origin.x,
y: distance * Math.sin(angle) + origin.y
};
};
//# sourceMappingURL=point-from-vector.js.map
+1
View File
@@ -0,0 +1 @@
export declare const progress: (from: number, to: number, value: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const progress = (from, to, value) => {
const toFromDifference = to - from;
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
};
//# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
export declare const radiansToDegrees: (radians: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const radiansToDegrees = (radians) => (radians * 180) / Math.PI;
//# sourceMappingURL=radians-to-degrees.js.map
+1
View File
@@ -0,0 +1 @@
export declare const smoothFrame: (prevValue: number, nextValue: number, duration: number, smoothing?: number) => number;
+4
View File
@@ -0,0 +1,4 @@
import { toDecimal } from './to-decimal';
export const smoothFrame = (prevValue, nextValue, duration, smoothing = 0) => toDecimal(prevValue +
(duration * (nextValue - prevValue)) / Math.max(smoothing, duration));
//# sourceMappingURL=smooth-frame.js.map
+1
View File
@@ -0,0 +1 @@
export declare const smooth: (strength?: number) => (v: number) => number;
+17
View File
@@ -0,0 +1,17 @@
import { smoothFrame } from './smooth-frame';
import { getFrameData } from 'framesync';
export const smooth = (strength = 50) => {
let previousValue = 0;
let lastUpdated = 0;
return (v) => {
const currentFramestamp = getFrameData().timestamp;
const timeDelta = currentFramestamp !== lastUpdated ? currentFramestamp - lastUpdated : 0;
const newValue = timeDelta
? smoothFrame(previousValue, v, timeDelta, strength)
: previousValue;
lastUpdated = currentFramestamp;
previousValue = newValue;
return newValue;
};
};
//# sourceMappingURL=smooth.js.map
+1
View File
@@ -0,0 +1 @@
export declare const snap: (points: number | number[]) => (v: number) => number;
+24
View File
@@ -0,0 +1,24 @@
export const snap = (points) => {
if (typeof points === 'number') {
return (v) => Math.round(v / points) * points;
}
else {
let i = 0;
const numPoints = points.length;
return (v) => {
let lastDistance = Math.abs(points[0] - v);
for (i = 1; i < numPoints; i++) {
const point = points[i];
const distance = Math.abs(point - v);
if (distance === 0)
return point;
if (distance > lastDistance)
return points[i - 1];
if (i === numPoints - 1)
return point;
lastDistance = distance;
}
};
}
};
//# sourceMappingURL=snap.js.map
+1
View File
@@ -0,0 +1 @@
export declare const toDecimal: (num: number, precision?: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const toDecimal = (num, precision = 2) => {
precision = Math.pow(10, precision);
return Math.round(num * precision) / precision;
};
//# sourceMappingURL=to-decimal.js.map
@@ -0,0 +1 @@
export declare function velocityPerFrame(xps: number, frameDuration: number): number;
+4
View File
@@ -0,0 +1,4 @@
export function velocityPerFrame(xps, frameDuration) {
return xps / (1000 / frameDuration);
}
//# sourceMappingURL=velocity-per-frame.js.map
@@ -0,0 +1 @@
export declare function velocityPerSecond(velocity: number, frameDuration: number): number;
@@ -0,0 +1,4 @@
export function velocityPerSecond(velocity, frameDuration) {
return frameDuration ? velocity * (1000 / frameDuration) : 0;
}
//# sourceMappingURL=velocity-per-second.js.map
+1
View File
@@ -0,0 +1 @@
export declare const wrap: (min: number, max: number, v: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const wrap = (min, max, v) => {
const rangeSize = max - min;
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};
//# sourceMappingURL=wrap.js.map
@@ -0,0 +1,2 @@
export declare function namespace(name: string): string;
export declare function registerCustomProperties(): void;
+41
View File
@@ -0,0 +1,41 @@
const transforms = [
{
name: 'translate',
syntax: 'length-percentage',
initial: '0px'
},
{
name: 'scale',
syntax: 'number',
initial: 1
},
{
name: 'rotate',
syntax: 'angle',
initial: '0deg'
}
];
const axes = ['x', 'y', 'z'];
const customProperties = [];
transforms.forEach(({ name, syntax, initial }) => {
customProperties.push({ name, syntax, initial });
axes.forEach(axis => customProperties.push({
name: `${name}-${axis}`,
syntax,
initial
}));
});
export function namespace(name) {
return `--pm-${name}`;
}
export function registerCustomProperties() {
customProperties.forEach(({ name, syntax, initial }) => {
CSS.registerProperty({
name: namespace(name),
syntax: `<${syntax}>`,
inherits: false,
initialValue: initial
});
});
}
//# sourceMappingURL=custom-properties.js.map
+2
View File
@@ -0,0 +1,2 @@
export declare function whenWorkletReady(): Promise<void>;
export declare function workletReady(): void;
+20
View File
@@ -0,0 +1,20 @@
import { __awaiter } from "tslib";
let isReady = false;
const awaitingReady = [];
export function whenWorkletReady() {
return __awaiter(this, void 0, void 0, function* () {
if (!isReady) {
return new Promise((resolve) => {
awaitingReady.push(resolve);
});
}
});
}
function flushAwaiting() {
awaitingReady.forEach((resolve) => resolve());
}
export function workletReady() {
isReady = true;
flushAwaiting();
}
//# sourceMappingURL=load-worklet.js.map