Skip to content

PeshoVurtoleta/lite-ease

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

3 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

@zakkster/lite-ease

npm version npm bundle size npm downloads npm total downloads TypeScript Dependencies License: MIT

๐ŸŽข What is lite-ease?

@zakkster/lite-ease is the complete set of Robert Penner easing equations as individual, tree-shakeable ES module exports โ€” plus a small, zero-allocation composition layer.

It gives you:

  • ๐ŸŽข 30 easing functions (10 families ร— 3 variants)
  • ๐Ÿงฎ Pure math: (t: number) => number where t โˆˆ [0, 1]
  • ๐Ÿ”— Composable: lerp(a, b, easeOutBounce(t))
  • ๐Ÿ›ก๏ธ clamp01() wrapper for Back/Elastic overshoot
  • ๐Ÿ”„ reverse(ease) creates the inverse curve
  • ๐ŸŽผ v1.1: mirror, chain, blend, scale โ€” zero-GC composition factories
  • ๐Ÿ“– easings lookup map for string-based access
  • 0๏ธโƒฃ Zero dependencies, pure math, no allocation in hot path
  • ๐Ÿชถ < 1 KB minified (entire library)

Part of the @zakkster/lite-* ecosystem โ€” micro-libraries built for deterministic, cache-friendly game development.

๐Ÿš€ Install

npm i @zakkster/lite-ease

๐Ÿ•น๏ธ Quick Start

import { easeOutBounce, easeInOutElastic, clamp01, reverse } from '@zakkster/lite-ease';
import { lerp } from '@zakkster/lite-lerp';

// Compose with any interpolation
const y = lerp(startY, endY, easeOutBounce(t));

// Clamp overshoot (Back/Elastic can exceed 1.0)
const safe = lerp(0, 255, clamp01(easeOutBack(t)));

// Create inverse curve
const myEaseOut = reverse(easeInCubic);

// String-based lookup (useful for configs/JSON)
import { easings } from '@zakkster/lite-ease';
const ease = easings[config.easing]; // 'easeOutBounce' โ†’ function

๐Ÿ“Š Comparison

Library Size Functions Format Install
bezier-easing ~3 KB Custom curves Class npm i bezier-easing
eases ~2 KB 31 CommonJS npm i eases
lite-ease < 1 KB 31 + composition ESM, tree-shakeable npm i @zakkster/lite-ease

โš™๏ธ API

10 Families ร— 3 Variants

Family easeIn easeOut easeInOut
Sine easeInSine easeOutSine easeInOutSine
Quad easeInQuad easeOutQuad easeInOutQuad
Cubic easeInCubic easeOutCubic easeInOutCubic
Quart easeInQuart easeOutQuart easeInOutQuart
Quint easeInQuint easeOutQuint easeInOutQuint
Expo easeInExpo easeOutExpo easeInOutExpo
Circ easeInCirc easeOutCirc easeInOutCirc
Back easeInBack easeOutBack easeInOutBack
Elastic easeInElastic easeOutElastic easeInOutElastic
Bounce easeInBounce easeOutBounce easeInOutBounce

Helpers

  • linear(t) โ€” Identity function
  • clamp01(t) โ€” Clamp to [0, 1]. Back/Elastic overshoot safely.
  • reverse(ease) โ€” Create the inverse: reverse(easeIn) โ‰ˆ easeOut
  • easings โ€” Record<string, EasingFunction> for dynamic lookup

๐ŸŽผ Composition Helpers (v1.1)

Each helper is a factory: it pre-computes any constants and returns a closure that does zero allocation per call. The returned function is what you call in your hot path.

โš ๏ธ Build once, call many. Don't put mirror(...), chain(...), blend(...), or scale(...) inside your requestAnimationFrame loop โ€” that allocates a fresh closure every frame and defeats the design. Build the composed easing in init/module scope, then call the returned function each frame.

mirror(ease, clamp?)

Plays the curve forward in the first half, then backward โ€” a seamless ping-pong (0 โ†’ 1 โ†’ 0).

import { mirror, easeInOutQuad } from '@zakkster/lite-ease';

const pingPong = mirror(easeInOutQuad);
// pingPong(0)   === 0
// pingPong(0.5) โ‰ˆ 1
// pingPong(1)   === 0

clamp: true clamps each half to [0, 1] โ€” useful when wrapping easeOutBack or easeOutElastic to suppress overshoot.

chain(easeA, easeB, clamp?)

Sequential chain: easeA drives t โˆˆ [0, 0.5], easeB drives t โˆˆ [0.5, 1].

import { chain, easeInQuad, easeOutBounce } from '@zakkster/lite-ease';

const windAndDrop = chain(easeInQuad, easeOutBounce);
// First half: smooth wind-up. Second half: bounce settle.

clamp: true is recommended when either curve overshoots โ€” clamps each half to its [0, 0.5] / [0.5, 1] range so overshoot can't bleed across the midpoint.

blend(easeA, easeB, weight)

Linear crossfade between two curves. weight is clamped to [0, 1] once at init and stored โ€” no per-call clamp cost.

import { blend, linear, easeOutElastic } from '@zakkster/lite-ease';

const subtleElastic = blend(linear, easeOutElastic, 0.3);
// 70% linear + 30% elastic โ€” keeps the bounce flavor without the full overshoot.

scale(ease, fromT, toT, clamp?)

Remaps an easing to a sub-segment of the timeline. Outside the segment, output is locked to the boundary value (pre-computed at init). Throws if toT <= fromT.

import { scale, easeOutBounce } from '@zakkster/lite-ease';

const dropAt40Percent = scale(easeOutBounce, 0.4, 0.9);
// dropAt40Percent(t)  โ†’  0  for t <= 0.4
// dropAt40Percent(t)  โ†’  1  for t >= 0.9
// drops/bounces between 0.4 and 0.9 of the master timeline

Ideal for staggered animation sequences where multiple elements share a master t and each starts/ends at a different point.

๐Ÿงช Benchmark

31 easing functions, 1M calls each:
  All functions: < 0.01ms per call (pure arithmetic)
  No allocation, no branching (except Bounce/Elastic)
  Tree-shakeable: unused functions are eliminated by bundlers

Composition helpers (mirror/chain/blend/scale):
  Factory cost paid once at init.
  Returned closure: zero allocation per call, one inner ease() invocation.

๐Ÿ“ฆ TypeScript

Full declarations included in LiteEase.d.ts. The EasingFunction type alias is exported for your own composed easings.

๐Ÿ“š LLM-Friendly Documentation

See llms.txt for AI-optimized metadata and usage examples.

License

MIT

About

30 Penner easing functions as pure (t)=>t. Tree-shakeable, zero-dependency, composable with any lerp.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors