@penner/responsive-easing 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,112 +1,160 @@
1
1
  # Responsive Easing
2
2
 
3
- > Context-aware easing functions for smooth, perceptually coherent motion across responsive UIs.
4
-
5
- > [!WARNING] > **🚧 Work in Progress** - This package is currently under active development. The API shown in this README is aspirational and not yet implemented. Please check back later for the actual release!
3
+ Mix and merge easing curves to create motion that feels exactly right.
6
4
 
7
5
  [![npm version](https://img.shields.io/npm/v/@penner/responsive-easing)](https://www.npmjs.com/package/@penner/responsive-easing)
8
6
 
9
- Responsive Easing adapts motion curves to real-world context—distance, time, and velocity—so animations feel smooth and natural across screen sizes, layouts, and motion segments.
7
+ ## Install
10
8
 
11
- ---
9
+ ```bash
10
+ npm install @penner/responsive-easing
11
+ ```
12
12
 
13
- ## ✨ Why Responsive Easing?
13
+ ## Overview
14
14
 
15
- Most easing functions assume a fixed range of motion from 0 to 1. But UI elements don’t always move the same distance or take the same time.
15
+ Responsive Easing opens up new creative possibilities by splitting easing curves into two independent phases:
16
16
 
17
- This leads to:
17
+ - **Head** — the first phase of the curve, easing away from the start
18
+ - **Tail** — the second phase, easing into the destination
18
19
 
19
- - Motion that feels too fast on large screens
20
- - Overshoots that don’t scale properly
21
- - Janky joins between motion segments
22
- - Manual tweaking of durations and curves for each use case
20
+ The `fuse()` function seamlessly joins them at a configurable point, producing a single smooth easing function. Because each phase is independent, you can mix any head with any tail — anticipation into a bounce, a Bézier swoop into a spring, or anything in between — creating curves that would be impossible with a single easing function.
23
21
 
24
- **Responsive Easing solves this** by working in real units: pixels, milliseconds, slopes. It lets you create physically coherent motion that scales with your UI.
22
+ Use the **[Fuse Editor](https://robertpenner.com/fuse)** to visually design curves, tweak parameters in real time, and copy out CSS easing strings or config values for the JS API.
25
23
 
26
- ---
24
+ ## Quick start
27
25
 
28
- ## 🚀 Install
26
+ ```ts
27
+ import { fuse } from '@penner/responsive-easing';
29
28
 
30
- ```bash
31
- npm install @penner/responsive-easing
32
- ```
29
+ // Backwards anticipation into a bouncy landing
30
+ const { easing, easingFn } = fuse({
31
+ head: { kind: 'back', overshoot: 0.2 }, // backwards by 20%
32
+ tail: { kind: 'spring', bounces: 4, decay: 0.95 },
33
+ joinTime: 0.7, // head is 70% of the curve, tail is 30%
34
+ });
33
35
 
34
- Or with Yarn:
36
+ // `easing` is a CSS linear() string - for CSS transitions, animations and web animations
37
+ element.animate(keyframes, { duration: 500, easing });
35
38
 
36
- ```bash
37
- yarn add @penner/@penner/responsive-easing
39
+ // `easingFn` is a mathematical function — for JS-driven animation or direct evaluation
40
+ const y = easingFn(0.5);
38
41
  ```
39
42
 
40
- ---
41
-
42
- ## 🧪 Basic Usage
43
+ The `.easing` property is a CSS `linear()` string, so it also works directly in style assignments:
43
44
 
44
45
  ```ts
45
- import { createResponsiveEasing } from '@penner/responsive-easing';
46
+ element.style.transition = `transform 600ms ${easing}`;
47
+ element.style.animationTimingFunction = easing;
48
+ ```
46
49
 
47
- const easing = createResponsiveEasing({
48
- distance: 400, // in pixels
49
- duration: 600, // in milliseconds
50
- overshoot: true,
51
- });
50
+ ## Easing definitions
52
51
 
53
- const y = easing(0.5); // evaluates easing at halfway point
54
- ```
52
+ Eight easing types, each with its own tunable parameters. Any head can be paired with any tail, giving you a wide palette of motion curves to design with.
55
53
 
56
- Or generate a CSS timing string:
54
+ | Kind | Parameters | Character |
55
+ | ------------ | --------------------------- | -------------------------------------------------------- |
56
+ | `power` | `exponent` | Smooth acceleration (quadratic, cubic, etc.) |
57
+ | `back` | `overshoot` | Anticipation — dips backward before moving forward |
58
+ | `power-back` | `exponent`, `overshoot` | Combined power + back |
59
+ | `bezier` | `x1`, `y1`, `x2`, `y2` | Cubic Bézier (same param space as CSS) |
60
+ | `expo` | `decay` | Exponential decay (tail only) |
61
+ | `spring` | `bounces`, `decay` | Damped oscillation (tail only) |
62
+ | `bounce` | `bounces`, `decay` | Hard-surface rebound (tail only) |
63
+ | `swim` | `strokes`, `effort`, `drag` | Rhythmic propulsion — pulsed force through viscous fluid |
57
64
 
58
- ```ts
59
- import { easingToCssLinear } from '@penner/responsive-easing';
65
+ ## The `fuse()` API
66
+
67
+ `fuse()` takes a plain config object describing head and tail easings and returns an `EasingKit` — a bundle containing the composed easing function, its CSS `linear()` string, and a velocity function.
60
68
 
61
- const linearString = easingToCssLinear(easing);
62
- // → linear(0 0, 0.2 0.1, 0.5 0.7, 1 1)
69
+ ```ts
70
+ function fuse(config: FuseConfig): EasingKit;
71
+
72
+ interface EasingKit {
73
+ easing: CSSEasing; // CSS linear() string for transitions, animations, WAAPI
74
+ easingFn: EasingFn; // (t: number) => number, [0,1] → [0,1]
75
+ velocityFn: VelocityFn; // speed of the easing at any point in time
76
+ meta: Record<string, unknown>;
77
+ }
63
78
  ```
64
79
 
65
- ---
80
+ ### FuseConfig
66
81
 
67
- ## 🧰 Features
82
+ | Property | Type | Default | Description |
83
+ | ---------- | ------------------------- | -------------- | ----------------------------------------------------- |
84
+ | `head` | `AnyEasingDef` | — | Head easing definition (required) |
85
+ | `tail` | `AnyEasingDef` | — | Tail easing definition (required) |
86
+ | `joinTime` | `number` | `0.5` | Where head meets tail, in [0, 1] |
87
+ | `movement` | `'transition' \| 'pulse'` | `'transition'` | Transition goes A→B; pulse goes A→B→A |
88
+ | `mirror` | `boolean` | `false` | Tail = reversed head (symmetric inOut curve) |
89
+ | `maxSpeed` | `number` | — | Cap join velocity; inserts a cruise phase if exceeded |
68
90
 
69
- - ✅ **Distance-aware easing**
70
- - ✅ **Cruise segments** with constant velocity
71
- - ✅ **Responsive overshoot / bounce**
72
- - ✅ **Velocity-matched joins**
73
- - ✅ **Composable easing parts** (intro, cruise, outro)
74
- - ✅ **Exportable to CSS `linear()` timing functions**
75
- - ✅ Works with any animation system (CSS, JS, Web Animations API, GSAP, Framer Motion)
91
+ ## Examples
76
92
 
77
- ---
93
+ ```ts
94
+ // Smooth power curve (equivalent to cubic ease-in-out when mirrored)
95
+ fuse({
96
+ head: { kind: 'power', exponent: 3 },
97
+ tail: { kind: 'power', exponent: 3 },
98
+ }).easingFn;
99
+
100
+ // Bézier head + bounce tail
101
+ fuse({
102
+ head: { kind: 'bezier', x1: 0.4, y1: 1.6, x2: 0.8, y2: -0.4 },
103
+ tail: { kind: 'bounce', bounces: 3, decay: 0.95 },
104
+ joinTime: 0.3,
105
+ }).easingFn;
106
+
107
+ // Swim head + bounce tail
108
+ fuse({
109
+ head: { kind: 'swim', strokes: 3.3, effort: 0.33, drag: 13 },
110
+ tail: { kind: 'bounce', bounces: 1, decay: 0 },
111
+ }).easingFn;
112
+
113
+ // Symmetric curve via mirror
114
+ fuse({
115
+ head: { kind: 'power-back', exponent: 2, overshoot: 0.1 },
116
+ tail: { kind: 'power', exponent: 2 }, // ignored when mirror=true
117
+ mirror: true,
118
+ }).easingFn;
119
+ ```
78
120
 
79
- ## 📦 Demos
121
+ ## Responsive Easing Modules (REMs)
80
122
 
81
- - [Live playground (CodeSandbox)](TODO)
82
- - [Comparison to traditional easing](TODO)
83
- - [Curve visualizer](TODO)
123
+ Under the hood, each easing definition resolves to an `EasingRem` (Responsive Easing Module) — an object that bundles the easing math with metadata for building UIs like sliders and parameter editors.
84
124
 
85
- ---
125
+ ```ts
126
+ import { PowerBackRem, SwimRem, getEasingRem } from '@penner/responsive-easing';
86
127
 
87
- ## 📚 Documentation
128
+ // Factory creation
129
+ const rem = getEasingRem('power-back', { exponent: 3, overshoot: 0.15 });
88
130
 
89
- - [Getting Started](TODO)
90
- - [API Reference](TODO)
91
- - [Design Principles](TODO)
92
- - [FAQ](TODO)
131
+ // Immutable update
132
+ const updated = rem.with({ overshoot: 0.3 });
93
133
 
94
- ---
134
+ // Evaluate
135
+ const y = rem.easeIn(0.5);
136
+
137
+ // Static knob specs for UI generation
138
+ PowerBackRem.EXPONENT_KNOB; // { key: 'exponent', type: 'number', min: 0.1, max: 10, ... }
139
+ SwimRem.DRAG_KNOB; // { key: 'drag', type: 'number', min: 0.5, max: 30, ... }
140
+ ```
95
141
 
96
- ## 🧠 Philosophy
142
+ Available REMs: `PowerRem`, `BackRem`, `PowerBackRem`, `BezierRem`, `ExpoRem`, `SpringRem`, `BounceRem`, `SwimRem`.
97
143
 
98
- Responsive Easing treats motion as a first-class design element—one that should respond to space and time, just like layout does. If your UI adapts responsively, your motion should too.
144
+ ## Technical notes
99
145
 
100
- ---
146
+ - The fuse config is a plain serializable object — no class instances or functions, just data. Easy to store in a database, share via URL, or pass between workers.
147
+ - Types like `NormalizedTime`, `CSSEasing`, and `EasingFn` are powered by [`@penner/smart-primitive`](https://www.npmjs.com/package/@penner/smart-primitive), which catches unit mix-ups at compile time with zero runtime cost.
148
+ - Each easing definition resolves to an immutable `EasingRem` (Responsive Easing Module) that encapsulates the math, velocity computation, and UI knob metadata for a single easing type. REMs can be created, updated, and evaluated directly for advanced use cases.
101
149
 
102
- ## 💬 Feedback & Contributions
150
+ ## Mathematical notes
103
151
 
104
- Have an idea? Find a bug? Want to shape the future of motion?
152
+ The join between head and tail maintains **C¹ continuity** — both position and velocity (first derivative) match at the join point. This is what makes the transition feel smooth rather than abrupt.
105
153
 
106
- [Open an issue](https://github.com/robertpenner/responsive-easing/issues) or [start a discussion](https://github.com/robertpenner/responsive-easing/discussions).
154
+ Internally, `fuse()` scales each phase (head or tail) to fit its portion of the [0, 1] time range. The head is stretched or compressed to fill the interval `[0, joinTime]`, and the tail fills `[joinTime, 1]`. Velocity at the join point is computed from the head's ending slope, and the tail's amplitude and time scale are adjusted so its starting slope matches — guaranteeing a seamless handoff regardless of which easing types are combined.
107
155
 
108
- ---
156
+ For easing types like `spring`, `bounce`, and `swim` where analytical derivatives aren't available, velocity is computed numerically.
109
157
 
110
- ## 📄 License
158
+ ## License
111
159
 
112
160
  MIT © [Robert Penner](https://github.com/robertpenner)
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const C=require("@penner/smart-primitive"),v=require("@penner/easing"),ot=1.70158,ft=ot+1,nt=e=>ft*e*e*e-ot*e*e,at=e=>3*ft*e*e-2*ot*e,j={id:"bounce",label:"Bounce (hard-surface)",build({joinTime:e,bounces:t,decayPct:a,L:n=nt,Ld:o=at}){if(e<it)return{p:O=>C.clampNormalized(O),v:O=>1,meta:{r:0,finalPct:0}};if(e>Mt)return{p:O=>O>=1?1:n(O),v:O=>O>=1?0:o(O),meta:{r:0,finalPct:0}};const r=Math.ceil(t),s=t-Math.floor(t);let i;if(t<=1)i=C.clampNormalized(1-a/100);else{const h=C.clampNormalized(1-a/100);h===0?i=0:i=Math.pow(h,1/(2*(t-1)))}const u=h=>n(h/e),d=h=>o(h/e)/e,l=d(e),c=Math.abs(-i*l);if(i===0||c===0)return{p:O=>O<=e?u(O):1,v:O=>O<=e?d(O):0,meta:{r:0,finalPct:0,g:0,edges:[e,1]}};const M=1-e,b=Math.floor(t),P=Math.abs(1-i)<1e-6?t:(1-Math.pow(i,b))/(1-i)+s*Math.pow(i,b);let y=2*c/M*P,f=0;const I=50;for(let h=0;h<=I;h++){const w=h/I*e,O=u(w);O<f&&(f=O)}const E=1-f,p=c*c/(2*y);let x=c,V=!1,_=1;if(p>E){x=Math.sqrt(2*y*E),V=!0;const h=Math.abs(1-i)<1e-6?t:(1-Math.pow(i,b))/(1-i)+s*Math.pow(i,b),w=2*x*h/y;_=e+w,_>1&&(_=1)}const S=x,H=Array.from({length:r},(h,w)=>2*S*Math.pow(i,w)/y),k=[e];H.forEach(h=>k.push(k[k.length-1]+h)),V?k[k.length-1]=_:k[k.length-1]=1;const F=h=>-S*Math.pow(i,h),N=h=>{if(h>=_)return 1;let w=k.findIndex((B,z)=>z<k.length-1&&h<=k[z+1]);w<0&&(w=r-1);const O=k[w],$=h-O;return 1+(F(w)*$+.5*y*$*$)},A=h=>{if(h>=_)return 0;let w=k.findIndex((T,B)=>B<k.length-1&&h<=k[B+1]);w<0&&(w=r-1);const O=k[w],$=h-O;return F(w)+y*$},K=h=>h<=e?u(h):N(h),m=h=>h<=e?d(h):A(h),g=r<=1?100:100*(1-a/100);return{p:K,v:m,meta:{r:i,finalPct:g,g:y,edges:k,clamped:V,settleTime:_}}}},_t=12;function Pt({joinTime:e,L:t=nt,Ld:a=at,bridge:n}){const o=_t;n&&n.joinHeight;const r=n?e+n.duration:e,s=1-r;let i;if(n)i=n.joinHeight;else{const x=a(1)*(1-e)+o*e;Math.abs(x)<1e-9?i=.5:i=o*e/x,i=Math.max(.01,Math.min(.999,i))}const u=n?1:i,d=u-1,l=n?n.velocity*s:i*a(1)*(1-e)/e,c=l+o*d,M=p=>{if(p<=0)return u;if(p>=1)return 1;const x=Math.exp(-o*p);return 1+(d+c*p)*x},b=p=>{if(p<=0)return l;if(p>=1)return 0;const x=Math.exp(-o*p);return(c-o*(d+c*p))*x},P=n?n.joinHeight:i,y=p=>P*t(p/e),f=p=>P/e*a(p/e);return{p:p=>{if(p<=0)return 0;if(p>=1)return 1;if(p<=e)return y(p);if(n&&p<=r)return n.joinHeight+n.velocity*(p-e);const x=(p-r)/s;return M(x)},v:p=>{if(p<=0||p>=1)return 0;if(p<=e)return f(p);if(n&&p<=r)return n.velocity;const x=(p-r)/s;return b(x)/s},meta:{r:0,finalPct:0,k:o,B:0,P:i,guard:"critically-damped",useBridge:!!n}}}function It(e,t,a,n){const o=C.clampNormalized(a/100),r=t+.5,s=v.amplitudeRatio(o,r),i=r,u=Math.PI*i,d=v.dampingRate(i,s),l=1-e,c=e<=it*10,M=l>0?u/l:u,b=l>0?d/l:d,P=n(1);let y;if(c)y=0;else{const E=P/e,p=u,x=E*(1-e)+p*e;y=Math.abs(x)<1e-9?.5:p*e/x,y=Math.max(.01,Math.min(.999,y))}const f=c?0:y*P/e,I=t<=1?100:100*(1-a/100);return{P:y,v0:f,r:s,N:i,w:M,g:b,alpha:l,finalPct:I}}function Et({joinTime:e,bounces:t,decayPct:a,L:n=nt,Ld:o=at}){const r=It(e,t,a,o),{r:s,g:i,alpha:u,finalPct:d}=r,l=o(1);let c;if(l>1e-6){const g=Math.min(u/(8*Math.max(t,1)),u*.1),h=e/(e+l*g),O=t>0?.5*e*t*Math.PI/(l*u):.5;c=Math.min(h,O),c=Math.max(.01,Math.min(.999,c))}else c=r.P;const M=c*l/e,b=t>0?u/(2*t+1):u,P=t>0?u*.5:u,y=1e-6;let f;if(M>1e-6){const g=(1-c)/M;f=Math.max(y,Math.min(P,g))}else f=Math.max(y,Math.min(P,b));const I=f>0?2*(1-c-M*f)/(f*f):0,E=g=>.5*I*g*g+M*g+c,p=g=>I*g+M,x=I*f+M,V=u-f,_=V>0?t*Math.PI/V:0,S=_>0?x/_:0,H=g=>1+S*Math.exp(-i*g)*Math.sin(_*g),k=g=>S*Math.exp(-i*g)*(_*Math.cos(_*g)-i*Math.sin(_*g)),F=g=>c*n(g/e),N=g=>c/e*o(g/e),A=e+f;return{p:g=>{if(g<=0)return 0;if(g>=1)return 1;if(g<=e)return F(g);if(g<=A){const w=g-e;return E(w)}const h=g-A;return H(h)},v:g=>{if(g<=0||g>=1)return 0;if(g<=e)return N(g);if(g<=A){const w=g-e;return p(w)}const h=g-A;return k(h)},meta:{r:s,finalPct:d,k:i,B:_,P:c,guard:"quadratic-sine"}}}const Ot=Et,Z={id:"spring",label:"Spring (phase-locked; bounce = half-cycle)",getNaturalStartVelocity({bounces:e,decayPct:t},a,n){const o=e;if(o<=0)return a(1);let r;if(o<=1)r=C.clampNormalized(1-t/100);else{const M=C.clampNormalized(1-t/100);M===0?r=0:r=Math.pow(M,1/(o-1))}if(r===0)return 0;const s=a(1),i=n?.headWeight??1,u=n?.freqWeight??1,d=n?.freqExponent??1,l=n?.baseMultiplier??1,c=Math.pow(o,d);return s*i+l*c*u},build({joinTime:e,bounces:t,decayPct:a,L:n=nt,Ld:o=at,bridge:r}){if(e<it)return{p:h=>C.clampNormalized(h),v:h=>1,meta:{r:0,finalPct:0,k:0,B:0,P:0}};if(e>Mt)return{p:h=>h>=1?1:n(h),v:h=>h>=1?0:o(h),meta:{r:0,finalPct:0,k:0,B:0,P:1}};if(t<=0)return Pt({joinTime:e,L:n,Ld:o,bridge:r});if(!r)return Ot({joinTime:e,bounces:t,decayPct:a,L:n,Ld:o});let s;if(t<=1)s=C.clampNormalized(1-a/100);else{const m=C.clampNormalized(1-a/100);m===0?s=0:s=Math.pow(m,1/(t-1))}const i=r?r.joinHeight:1,u=r?e+r.duration:e;if(s===0){const m=O=>i*n(O/e),g=O=>i/e*o(O/e);return{p:O=>O<=e?m(O):r&&O<=u?r.joinHeight+r.velocity*(O-e):1,v:O=>O<=e?g(O):r&&O<=u?r.velocity:0,meta:{r:0,finalPct:0,k:1/0,B:0,P:i,guard:"no-oscillation",useBridge:!!r}}}const d=1-u,l=t<=0||d<=0?0:t*Math.PI/d,c=s<=0?50:l/Math.PI*-Math.log(s),M=m=>Math.exp(-c*m)*Math.sin(l*m),b=m=>Math.exp(-c*m)*(l*Math.cos(l*m)-c*Math.sin(l*m));let P="";const y=Math.PI/(2*l),f=Math.exp(-c*y),I=f>1e-9?f:1;f<=1e-9&&(P="high-decay-fallback");const E=m=>M(d*m)/I,p=m=>d*b(d*m)/I,x=()=>!r||l===0?0:r.joinHeight/e*o(1)*I/l,V=m=>k+(1-k)*m,_=m=>r?1+x()*E(m):V(m)+(1-k)*E(m),S=m=>r?x()/(1-u)*p(m):(1-k)*(1+p(m))/(1-u),H=()=>{if(r){const m=p(0),g=1-u;return Math.abs(m)<1e-9?i:1-r.velocity*g/m}else{const m=o(1),h=1+p(0);return Math.abs(m*(1-e)+h*e)<1e-9?.5:h*e/(m*(1-e)+h*e)}},k=H(),F=globalThis;typeof F.__SPRING_TEST_HELPERS__=="object"&&(F.__SPRING_TEST_HELPERS__.calculateBridgeAmplitude=x,F.__SPRING_TEST_HELPERS__.calculateNonBridgeBaseline=V,F.__SPRING_TEST_HELPERS__.calculatePulsePosition=_,F.__SPRING_TEST_HELPERS__.calculatePulseVelocity=S,F.__SPRING_TEST_HELPERS__.calculateScalingFactor=H);const N=m=>{if(m<=e)return(r?r.joinHeight:k)*n(m/e);if(r&&m<=u)return r.joinHeight+r.velocity*(m-e);const g=(m-u)/(1-u);return _(g)},A=m=>{if(m<=e)return(r?r.joinHeight:k)/e*o(m/e);if(r&&m<=u)return r.velocity;const g=(m-u)/(1-u);return S(g)},K=t<=1?100:100*(1-a/100);return{p:N,v:A,meta:{r:s,finalPct:K,k:c,B:l,P:k,guard:P||"ok",useBridge:!!r}}}},ct=Z;function xt(e,t,a,n){const o=Math.PI/2,r=T=>Math.abs(T)<222e-17,s=T=>{const B=Math.sign(T),z=T*B;return((((-.021641405*z+.077981383)*z+-.213301322)*z+o)*Math.sqrt(1-z)-o)*B+o},i=T=>{if(Math.abs(T)<1){const B=T*T,z=B*T,bt=z*B;return T+z/6+bt/120}return Math.sinh(T)},u=e-a,d=t-n,l=3*e,c=3*t,M=3*u+1,b=-l-3*u,P=l,y=3*d+1,f=-c-3*d,I=c,E=1/M,p=b*E,x=P*E,V=p/-3*p+x,_=p/3,S=(2*_*_-x)*_,H=Math.sign(V),k=Math.sign(b);let F=1,N=1,A=1,K,m,g;if(r(M)&&r(b))K=1,F=1/P,N=0,m=1,g=0;else if(r(M))K=2,F=k,N=-(P/(2*b)),m=1/b,g=N*N;else if(r(V))K=3,N=-_,m=E,g=-S;else{if(M<0)K=4;else if(V>0)K=5;else if(V<0)K=6,A=k;else throw new Error("Invalid curve type");F=-2*H*A*Math.sqrt(Math.abs(V)/3),N=-_,m=3*H*E/(V*F),g=3*H*(-S/V/F)}const h=y*F*F*F,w=(3*y*N+f)*F*F,O=((3*y*N+2*f)*N+I)*F,$=((y*N+f)*N+I)*N;return T=>{if(T<=0)return 0;if(T>=1)return 1;let B=m*T+g;switch(K){case 1:break;case 2:B=Math.sqrt(Math.max(0,B));break;case 3:B=Math.cbrt(B);break;case 4:B=Math.cos(s(Math.max(-1,Math.min(1,B)))/3-2.094395102393195);break;case 5:B=i(Math.log(B+Math.sqrt(B*B+1))/3);break;case 6:B=B>=1?Math.cosh(Math.log(B+Math.sqrt(B*B-1))/3):Math.cos(s(Math.max(-1,B))/3);break;default:throw new Error("Invalid curve type")}return((h*B+w)*B+O)*B+$}}function tt(e,t,a,n){if(e<0||e>1||a<0||a>1)throw new Error("x1 & x2 must be in [0, 1]");return e===t&&a===n?o=>o:xt(e,t,a,n)}function vt(e,t){if(e<=0)return 0;if(e>=1)return Number.POSITIVE_INFINITY;if(t<=1)return 0;if(t-1<1e-10){const n=e/(1-e);return Math.max(0,n*Math.pow(t-1,2))}const a=Math.pow((t-1)/t,t-1)/t;return Math.pow(e,t)/(1-e)*a}function Q(e,t){if(e<=0||t<=1)return 0;const a=e;let n=0,o=1-1e-9;for(let s=0;s<60;s++){const i=.5*(n+o);vt(i,t)<a?n=i:o=i}const r=.5*(n+o);return r/(1-r)}function pt(e,t,a){const n=t;if(a===0||n<=1)return Math.pow(e,Math.max(n,0));if(n-1<1e-10)return(a+1)*e-a;const r=Math.pow(e,n-1)*((a+1)*e-a);return r===0?0:r}function gt(e,t,a){const n=t;return a===0||n<=1?n*Math.pow(e,n-1):n-1<1e-10?a+1:Math.abs(n-2)<1e-10?2*(a+1)*e-a:e===0&&n>2?0:e===0&&n<=2?n*(a+1)*Math.pow(1e-10,n-1):n*(a+1)*Math.pow(e,n-1)-a*(n-1)*Math.pow(e,n-2)}function kt(e,t){if(t<=0||e<=1)return 0;const a=e,n=Q(t,a);return n<=0?0:(a-1)*n/(a*(n+1))}function St(e){const t=e;if(t<=1)return{u:.5,p:Math.pow(.5,Math.max(t,0))};const a=Math.pow(t,-1/(t-1));return{u:a,p:Math.pow(a,t)}}function Bt(e,t,a=1.01,n=10){if(e<=0||t<=0||t>=1)return null;const o=d=>{const l=Q(e,d);return l<=0?0:(d-1)*l/(d*(l+1))},r=o(a),s=o(n);if(t<=r&&r>0)return a;if(t>=s)return n;let i=a,u=n;for(let d=0;d<50;d++){const l=.5*(i+u),c=o(l);if(Math.abs(c-t)<1e-9)return l;c<t?i=l:u=l}return .5*(i+u)}function Vt(e=.1){const t=v.solveBackStrength(e),a=o=>{const r=1-o;return 1-((t+1)*r*r*r-t*r*r)},n=o=>{const r=1-o;return(t+1)*3*r*r-t*2*r};return{id:"back-out",label:`Back Out (${(e*100).toFixed(0)}%)`,easingFn:a,velocityFn:n,config:{overshoot:e}}}function rt(e=2){const t=Math.max(.1,e);return{id:"power-out",label:`Power Out (t^${t})`,easingFn:a=>{const n=1-a;return 1-Math.pow(n,t)},velocityFn:a=>{const n=1-a;return t*Math.pow(n,t-1)},config:{exponent:t}}}function wt(e=2,t=.1){const a=Math.max(.1,e);if(t<=0||a<=1)return rt(e);const n=Q(t,a),o=s=>{const i=1-s;return n===0||a<=1?1-Math.pow(i,a):a-1<1e-10?1-((n+1)*i-n):1-Math.pow(i,a-1)*((n+1)*i-n)},r=s=>{const i=1-s;return gt(i,a,n)};return{id:"power-back-out",label:`Power Back Out (${(t*100).toFixed(0)}%, n=${a.toFixed(2)})`,easingFn:o,velocityFn:r,config:{exponent:a,overshoot:t,strength:n}}}function Ft(e=.5,t=0,a=1,n=.5){const o=tt(e,t,a,n),r=v.createVelocityFn(o,{step:1e-8,boundarySample:.001});return{id:"bezier-out",label:`Bezier (${e.toFixed(2)}, ${t.toFixed(2)}, ${a.toFixed(2)}, ${n.toFixed(2)})`,easingFn:o,velocityFn:r,config:{x1:e,y1:t,x2:a,y2:n}}}function Nt(e=.95){const t=Math.max(0,Math.min(1,e));if(t===0)return{id:"expo-out",label:"Expo Out (linear)",easingFn:s=>s<=0?0:s>=1?1:s,velocityFn:()=>1,config:{decay:t}};if(t===1)return{id:"expo-out",label:"Expo Out (step)",easingFn:s=>s>0?1:0,velocityFn:()=>0,config:{decay:t}};const a=Math.log1p(-t),n=1/Math.expm1(a),o=v.makeExpoEaseOut(t),r=s=>a*Math.exp(a*s)*n;return{id:"expo-out",label:`Expo Out (${(t*100).toFixed(0)}%)`,easingFn:o,velocityFn:r,config:{decay:t}}}const Ht={back:Vt,power:rt,"power-back":wt,bezier:Ft,expo:Nt};function Kt(e,t){const a=Ht[e];return e==="back"?a(t?.overshoot??.1):e==="power"?a(t?.exponent??2):e==="power-back"?a(t?.exponent??2,t?.overshoot??.1):e==="expo"?a(t?.decay??.95):a(t?.x1??.5,t?.y1??0,t?.x2??1,t?.y2??.5)}function et(e,t,a){let n;Object.defineProperty(e,t,{get:()=>n??=a(),configurable:!0,enumerable:!0})}class Y{params;constructor(t){this.params=Object.freeze({...t}),et(this,"easeInVelocity",()=>v.createVelocityFn(this.easeIn)),et(this,"easeOutVelocity",()=>v.createVelocityFn(this.easeOut))}easeOut=t=>1-this.easeIn(1-t);get easeOutBoundary(){return{start:this.easeInBoundary.end,end:this.easeInBoundary.start}}}class J extends Y{static STROKES_KNOB={key:"strokes",label:"Strokes",type:"number",default:2,min:1,max:10,step:.05,isPrimary:!0};static EFFORT_KNOB={key:"effort",label:"Effort",type:"percent",default:.4,min:.05,max:.95,step:.01};static DRAG_KNOB={key:"drag",label:"Drag",type:"number",default:6,min:.5,max:30,step:.1};kind="swim";metadata={variants:{easeIn:!0,easeOut:!0},modes:{transition:!0,pulse:!1}};knobSpecs=[J.STROKES_KNOB,J.EFFORT_KNOB,J.DRAG_KNOB];easeInBoundary={start:"zero",end:"nonzero"};constructor(t){super(t);const a=v.swim(t);this.easeIn=n=>a(n)}with(t){return new J({...this.params,...t})}static create(t={}){return new J({strokes:t.strokes??2,effort:t.effort??.2,drag:t.drag??6})}}function Tt(e=.1){const t=v.solveBackStrength(e),a=t+1;return{id:"back",label:`Back (${(e*100).toFixed(0)}% overshoot)`,easingFn:n=>n*n*(a*n-t),velocityFn:n=>n*(3*a*n-2*t),config:{overshoot:e,strength:t}}}Tt(.1);function At(e,t,a){const n=Math.max(.001,Math.min(.999,a));return o=>{if(o<=0||o>=1)return 0;if(o<=n){const r=o/n;return e(r)}else{const r=(o-n)/(1-n);return 1-t(r)}}}function zt(e={}){const{bounces:t=4,decay:a=90}=e,n=Math.max(.5,t),o=Math.max(0,1-a/100),r=n<=1?o:o===0?0:Math.pow(o,1/(n-1)),s=n*Math.PI,i=r<=0?50:s/Math.PI*-Math.log(r),u=i/s,d=Math.exp(-i)*(Math.cos(s)+u*Math.sin(s));return l=>l<=0?1:l>=1?0:Math.exp(-i*l)*(Math.cos(s*l)+u*Math.sin(s*l))-d*l}function Dt(e={}){const{bounces:t=4,decay:a=90}=e,n=Math.max(1,Math.round(t)),o=Math.max(0,1-a/100),r=n<=1?Math.sqrt(o):o===0?0:Math.pow(o,1/(2*(n-1)));if(r===0)return c=>c<=0?1:c>=1?0:1-c*c;const s=Math.abs(1-r)<1e-6?1+2*n:1+2*r*(1-Math.pow(r,n))/(1-r),i=2*s*s,u=1/s,d=i*u,l=[0,u];for(let c=1;c<=n;c++){const M=2*Math.pow(r,c)*d/i;l.push(l[l.length-1]+M)}return l[l.length-1]=1,c=>{if(c<=0)return 1;if(c>=1)return 0;if(c<=u)return 1-.5*i*c*c;let M=0;for(let f=1;f<l.length-1;f++)if(c<=l[f+1]){M=f;break}M===0&&(M=l.length-2);const P=Math.pow(r,M)*d,y=c-l[M];return P*y-.5*i*y*y}}function lt(e,t,a){const n=Math.max(.001,Math.min(.999,a));return o=>{if(o<=0||o>=1)return 0;if(o<=n){const r=o/n;return e(r)}else{const r=(o-n)/(1-n);return t(r)}}}function Ct(e,t){return{isValid:!0,point:{x:1-e.x,y:1-e.y}}}function Lt(e,t){return{isValid:!0,point:{x:1-e.x,y:1-e.y}}}class R extends Y{static EXPONENT_KNOB={key:"exponent",label:"Exponent",type:"number",default:2,min:.1,max:10,step:.01,isPrimary:!0};kind="power";metadata={variants:{easeIn:!0,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[R.EXPONENT_KNOB];constructor(t){super(t)}get easeInBoundary(){return{start:this.params.exponent>1?"zero":"nonzero",end:"nonzero"}}easeIn=t=>Math.pow(t,this.params.exponent);easeInVelocity=t=>{const a=this.params.exponent;return a*Math.pow(t,a-1)};easeOutVelocity=t=>this.easeInVelocity(1-t);with(t){return new R({...this.params,...t,exponent:Math.max(.1,t.exponent??this.params.exponent)})}static create(t={}){const a=Math.max(.1,t.exponent??2);return new R({exponent:a})}}const Jt=1e-4,Yt=.9999,$t=0,Gt=1;function qt(e){if(Number.isNaN(e))return{atStart:!1,atEnd:!1};const t=Math.max($t,Math.min(Gt,e));return{atStart:t<=Jt,atEnd:t>=Yt}}function ut(e){const{joinTime:t,headVelocityAtEnd:a,tailVelocityAtStart:n}=e;if(t<=0||t>=1)return{joinHeight:0,isValid:!1,warning:`Invalid joinTime: ${t}. Must be in range (0, 1).`};if(a===0)return{joinHeight:0,isValid:!1,warning:`Invalid headVelocityAtEnd: ${a}. Must be non-zero.`};if(n<=0)return{joinHeight:0,isValid:!1,warning:`Invalid tailVelocityAtStart: ${n}. Must be positive.`};const o=a*(1-t)+t*n;if(Math.abs(o)<1e-10)return{joinHeight:0,isValid:!1,warning:"Denominator too close to zero. Cannot calculate join height."};const r=t*n/o;let s;return r<0?s=`Join height is negative (${r.toFixed(4)}). This may indicate incompatible velocities.`:r>1?a<0?s=`Join height exceeds 1 (${r.toFixed(4)}) due to negative head slope. This creates a natural reflection/dip effect.`:s=`Join height exceeds 1 (${r.toFixed(4)}). This may cause overshoot beyond target.`:a<0&&r<=1&&(s=`Head ends with negative slope (${a.toFixed(4)}). Curve will dip below join height before tail recovers.`),{joinHeight:r,isValid:!0,warning:s}}function yt(e){const{joinTime:t,headVelocityAtEnd:a,pulseNaturalStartVelocity:n,isBounceStrategy:o}=e;if(o)return{isValid:!1,failureReason:"bounce_tail_unsupported"};if(n<=0)return{isValid:!1,failureReason:"invalid_pulse_velocity"};const r=n;let s=r*t/a;s<0&&(s=1),s>=1&&(s=.9999);const u=(1-s)/r;return u<=0?{isValid:!1,failureReason:"invalid_bridge_duration"}:t+u>=1?{isValid:!1,failureReason:"bridge_exceeds_timeline"}:{isValid:!0,bridgeParams:{joinHeight:s,duration:u,velocity:r}}}function Xt(e,t,a){return e!==void 0&&Number.isFinite(e)&&e>0&&t>0&&a>0}function Rt(e,t,a,n){return t?e*a/n:0}function Ut(e,t,a){const n=e;return 1/(1/n+(a-a/n)+(1-a)/t)}function Wt(e){const{joinTime:t,headVelocityAtEnd:a,tailVelocityAtStart:n,maxSpeed:o,naturalJoinHeight:r,naturalJoinHeightIsValid:s}=e;if(Rt(r,s,a,t)<=o)return null;const u=a,d=Ut(u,n,t),l=Math.max(o,Math.max(d,1));let c;if(Math.abs(1/u-1)<1e-9)c=0;else{const E=1/u-1,p=1-1/n,x=1/l-1/n,V=t*E/(1-t),_=p-V;let S;Math.abs(_)<1e-9?S=t:S=(x-V)/_,S=Math.max(t,Math.min(1-.01,S)),c=t*(1-S)/(1-t),c=Math.max(0,Math.min(t,c))}const M=c>0?l*c/u:0,b=c>0?t+(t-c)*(1-t)/t:t+(1-t)*(1-1/(l*(1/n))),P=Math.max(t,Math.min(1-.01,b)),f=M+l*(t-c)+l*(P-t),I=1-P;return f<=0||f>=1||I<=.01?null:{cruiseSpeed:l,tStar:c,tC:P,headHeight:M,tailStartPos:f}}function Zt(e,t,a){const{cruiseSpeed:n,tStar:o,tC:r,headHeight:s,tailStartPos:i}=e,u=1-r;return d=>{if(d<=0)return 0;if(d>=1)return 1;if(o>0&&d<=o){const l=d/o;return s*t(l)}else{if(d<=r)return(o>0?s:0)+n*(d-o);{const l=(d-r)/u;return i+(1-i)*a(l)}}}}function Qt(e){const{joinTime:t,headBounces:a,headDecay:n,tailBounces:o,tailDecay:r,springTailBuilder:s}=e,i=s.build({joinTime:.5,bounces:a,decayPct:n,bridge:void 0}),u=v.reverseEasingFn(i.p),d=y=>u(y*.5),l=y=>i.v(1-y*.5)*.5,c=t,M=y=>y<=0?0:y>=t?t:c*d(y/t),b=y=>y<=0||y>=t?0:c/t*l(y/t);return s.build({joinTime:t,bounces:o,decayPct:r,L:M,Ld:b,bridge:void 0}).p}const jt=10;function te(e){const{joinTime:t,headBounces:a,headDecay:n,tailBounces:o,tailDecay:r}=e;if(t<=0||t>=1)return{easingFn:null};if(a<1||o<1)return{easingFn:null};const s=ct.build({joinTime:.5,bounces:a,decayPct:n,bridge:void 0}),i=ct.build({joinTime:.5,bounces:o,decayPct:r,bridge:void 0}),u=v.reverseEasingFn(s.p),d=_=>u(_*.5),l=jt,c=t,M=c/l,b=(1-c)/l,P=t-M,y=t+b,f=1-y;if(P<=0||M<=0||b<=0||f<=0)return{easingFn:null};const I=2*P,E=2*f,p=d(1),x=i.p(.5);return{easingFn:_=>{if(_<=0)return 0;if(_>=1)return 1;if(_<=P){const S=_/P;return I*d(S)}else if(_<=t){const S=I*p,H=(_-P)/M;return S+(c-S)*H}else if(_<=y){const S=1-E*(1-x),H=(_-t)/b;return c+(S-c)*H}else{const S=(_-y)/f,H=i.p(.5+S*.5);return 1-E*(1-H)}},diagnostics:{joinPosition:c,headBridgeDuration:M,tailBridgeDuration:b,headPulseDuration:P,tailPulseDuration:f,bridgeVelocity:l}}}function ee(){return{easingFn:e=>e,velocityFn:()=>1}}function ne(e,t){const{joinTime:a,pulseTail:n,useBridge:o=!0,bridgeTuning:r}=e;if(a<=0||a>=1)throw new Error(`Invalid joinTime: ${a}. Must be in range (0, 1).`);if(n.bounces<1)throw new Error(`Invalid pulse tail bounces: ${n.bounces}. Must be >= 1.`);const s=ee(),i=1-a,u=t(n.strategy,{head:s.easingFn,headVelocityFn:s.velocityFn,join:i,bounces:n.bounces,decay:n.decay,useBridge:o,bridgeTuning:r});return v.reverseEasingFn(u)}function L(e){return e.params}function ae(e,t,a={}){const{joinTime:n=.5,movement:o="transition",mirror:r=!1,useBridge:s=!0,bridgeTuning:i,allowGeneralizedBackTail:u=!1,maxSpeed:d}=a,l={movement:o,headKind:e.kind,tailKind:t.kind,joinTime:n,mirror:r};return o==="pulse"?re(e,t,n,l):se(e,t,{joinTime:n,mirror:r,useBridge:s,bridgeTuning:i,allowGeneralizedBackTail:u,maxSpeed:d,meta:l})}function re(e,t,a,n){const r=(e.kind==="spring"?R.create({exponent:L(e).bounces??2}):e).easeOut;let s;if(t.kind==="spring"){const{bounces:i,decay:u}=L(t);s=lt(r,zt({bounces:i,decay:u*100}),a)}else if(t.kind==="bounce"){const{bounces:i,decay:u}=L(t);s=lt(r,Dt({bounces:i,decay:u*100}),a)}else s=At(r,t.easeIn,a);return v.easingKit(s,n)}function se(e,t,a){const{joinTime:n,mirror:o}=a,r=qt(n);return r.atStart&&!(t.kind==="spring"||t.kind==="bounce")?v.easingKit(s=>Math.max(0,Math.min(1,s)),a.meta):r.atEnd?v.easingKit(e.easeIn,a.meta):e.kind==="spring"?oe(e,t,a):t.kind==="spring"||t.kind==="bounce"?ie(e,t,a):e.kind==="bezier"&&t.kind==="bezier"?ce(e,t,a):le(e,t,a)}function oe(e,t,a){const{joinTime:n,useBridge:o,bridgeTuning:r}=a,s=L(e),i=s.bounces??4,u=(s.decay??.95)*100;if(t.kind==="spring"){const f=L(t),I=te({joinTime:n,headBounces:i,headDecay:u,tailBounces:f.bounces,tailDecay:f.decay*100});if(I.easingFn)return v.easingKit(I.easingFn,a.meta);const E=Qt({joinTime:n,headBounces:i,headDecay:u,tailBounces:f.bounces,tailDecay:f.decay*100,springTailBuilder:Z});return v.easingKit(E,a.meta)}if(t.kind==="bounce"){const f=L(t),I=ne({joinTime:n,springHead:{decay:f.decay*100},pulseTail:{strategy:j,bounces:f.bounces,decay:f.decay*100},useBridge:o,bridgeTuning:r},(E,p)=>dt(E,p));return v.easingKit(I,a.meta)}const d=a.mirror?v.reverseEasingFn(e.easeIn):t.easeOut,l=a.mirror?f=>e.easeInVelocity(1-f):t.easeOutVelocity,c=v.reverseEasingFn(d),M=f=>l(1-f),b=1-n,P=dt(Z,{head:c,headVelocityFn:M,joinTime:b,bounces:i,decay:u,useBridge:!0,bridgeTuning:r}),y=v.reverseEasingFn(P);return v.easingKit(y,a.meta)}function ie(e,t,a){const{joinTime:n,useBridge:o,bridgeTuning:r}=a,s=L(t),i=s.bounces,u=s.decay*100,d=(t.kind==="spring",t.constructor.tailStrategy),l=e.easeIn,c=e.easeInVelocity;let M;const b=t.kind==="spring";if(o&&!b&&d.getNaturalStartVelocity){const y=d.getNaturalStartVelocity({bounces:i,decayPct:u},c,r),f=yt({joinTime:n,headVelocityAtEnd:c(1),pulseNaturalStartVelocity:y,isBounceStrategy:t.kind==="bounce"});f.isValid&&(M=f.bridgeParams)}const P=d.build({joinTime:n,bounces:i,decayPct:u,L:l,Ld:c,bridge:M});return v.easingKit(P.p,a.meta)}function ce(e,t,a){const{joinTime:n}=a,o=L(e),r=L(t),s=n,i=o.x1*n,u=o.y1*s,d=o.x2*n,l=o.y2*s,c=n,M=s;let b;Math.abs(c-d)<1e-8?b=1e8:b=(M-l)/(c-d);const P=n+r.x1*(1-n),y=s+b*(P-n),f=n+r.x2*(1-n),I=s+r.y2*(1-s),E=i/n,p=u/s,x=d/n,V=l/s,_=tt(E,p,x,V),S=(P-n)/(1-n),H=(y-s)/(1-s),k=(f-n)/(1-n),F=(I-s)/(1-s),N=tt(S,H,k,F),A=K=>{if(K<=0)return 0;if(K>=1)return 1;if(K<=n){const m=K/n;return s*_(m)}else{const m=(K-n)/(1-n);return s+(1-s)*N(m)}};return v.easingKit(A,a.meta)}function le(e,t,a){const{joinTime:n,mirror:o,allowGeneralizedBackTail:r,maxSpeed:s}=a,i=e.easeIn,u=e.easeInVelocity;let d,l;o?(d=v.reverseEasingFn(i),l=I=>u(1-I)):(d=t.easeOut,l=t.easeOutVelocity);const c=u(1),M=l(0);if(Xt(s,c,M)){const I=ut({joinTime:n,headVelocityAtEnd:c,tailVelocityAtStart:M}),E=Wt({joinTime:n,headVelocityAtEnd:c,tailVelocityAtStart:M,maxSpeed:s,naturalJoinHeight:I.joinHeight,naturalJoinHeightIsValid:I.isValid});if(E){const p=Zt(E,i,d);return v.easingKit(p,a.meta)}}let b,P=!1,y=c;if(c<0&&(t.kind==="power"||t.kind==="back"))b=1,P=!0,y=c*(b/n);else{const I=ut({joinTime:n,headVelocityAtEnd:c,tailVelocityAtStart:M});if(!I.isValid)return v.easingKit(p=>Math.max(0,Math.min(1,p)),a.meta);const E=I.joinHeight;b=Math.max(0,Math.min(1,E)),r&&b>=.9999&&(t.kind==="power-back"||t.kind==="back"||t.kind==="power")&&(P=!0,b=1,y=c*(b/n))}const f=I=>{if(I<=0)return 0;if(I>=1)return 1;if(I<=n){const E=I/n;return b*i(E)}else{const E=(I-n)/(1-n);if(P){const p=y*(1-n),x=b,V=p,_=(3*(1-x)-2*V)/(V-(1-x));return(1-V-x)*((_+1)*E*E*E-_*E*E)+V*E+x}else return b+(1-b)*d(E)}};return v.easingKit(f,a.meta)}function dt(e,t){const{head:a=c=>c,headVelocityFn:n=()=>1,joinTime:o=.5,bounces:r=4,decay:s=95,useBridge:i=!0,bridgeTuning:u}=t;let d;if(i&&e.getNaturalStartVelocity){const c=e.getNaturalStartVelocity({bounces:r,decayPct:s},n,u),M=yt({joinTime:o,headVelocityAtEnd:n(1),pulseNaturalStartVelocity:c,isBounceStrategy:e===j});M.isValid&&(d=M.bridgeParams)}return e.build({joinTime:o,bounces:r,decayPct:s,L:a,Ld:n,bridge:d}).p}class U extends Y{static OVERSHOOT_KNOB={key:"overshoot",label:"Overshoot",type:"percent",default:.1,min:0,max:1,step:.01,isPrimary:!0};kind="back";metadata={variants:{easeIn:!0,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[U.OVERSHOOT_KNOB];easeInBoundary={start:"zero",end:"nonzero"};strength;constructor(t){super(t),this.strength=v.solveBackStrength(t.overshoot)}easeIn=t=>v.backEaseIn(t,this.strength);easeInVelocity=t=>v.backEaseInVelocity(t,this.strength);easeOutVelocity=t=>v.backEaseInVelocity(1-t,this.strength);with(t){return new U({...this.params,...t})}static create(t={}){const a=t.overshoot??.1;return new U({overshoot:a})}}class G extends Y{static EXPONENT_KNOB={key:"exponent",label:"Exponent",type:"number",default:3,min:.1,max:10,step:.01,isPrimary:!0};static OVERSHOOT_KNOB={key:"overshoot",label:"Overshoot",type:"percent",default:0,min:0,max:1,step:.01};kind="power-back";metadata={variants:{easeIn:!0,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[G.EXPONENT_KNOB,G.OVERSHOOT_KNOB];strength;constructor(t){super(t),this.strength=Q(t.overshoot,t.exponent)}get easeInBoundary(){return{start:this.params.exponent>2||this.params.overshoot<=0?"zero":"nonzero",end:"nonzero"}}easeIn=t=>pt(t,this.params.exponent,this.strength);easeInVelocity=t=>gt(t,this.params.exponent,this.strength);easeOutVelocity=t=>this.easeInVelocity(1-t);with(t){return new G({...this.params,...t,exponent:Math.max(.1,t.exponent??this.params.exponent)})}static create(t={}){const a=Math.max(.1,t.exponent??3),n=t.overshoot??.3;return new G({exponent:a,overshoot:n})}}class D extends Y{static X1_KNOB={key:"x1",label:"X1",type:"number",default:.42,min:0,max:1,step:.01};static Y1_KNOB={key:"y1",label:"Y1",type:"number",default:0,min:-.5,max:1.5,step:.01};static X2_KNOB={key:"x2",label:"X2",type:"number",default:1,min:0,max:1,step:.01};static Y2_KNOB={key:"y2",label:"Y2",type:"number",default:1,min:-.5,max:1.5,step:.01};kind="bezier";metadata={variants:{easeIn:!0,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[D.X1_KNOB,D.Y1_KNOB,D.X2_KNOB,D.Y2_KNOB];easeInBoundary={start:"nonzero",end:"nonzero"};bezier=tt(this.params.x1,this.params.y1,this.params.x2,this.params.y2);easeIn=t=>this.bezier(t);easeOut=t=>this.bezier(t);constructor(t){super(t);const a=()=>v.createVelocityFn(this.bezier,{boundarySample:.001});et(this,"easeInVelocity",a),et(this,"easeOutVelocity",a)}with(t){return new D({...this.params,...t})}static create(t={}){return new D({x1:t.x1??.42,y1:t.y1??0,x2:t.x2??1,y2:t.y2??1})}}class W extends Y{static DECAY_KNOB={key:"decay",label:"Decay",type:"percent",default:.95,min:.8,max:.999,step:.001,isPrimary:!0};kind="expo";metadata={variants:{easeIn:!1,easeOut:!0},modes:{transition:!0,pulse:!1}};knobSpecs=[W.DECAY_KNOB];easeInBoundary={start:"nonzero",end:"nonzero"};easeOutFn;negK;scale;d;constructor(t){super(t),this.d=Math.max(0,Math.min(1,t.decay)),this.d===0?(this.easeOutFn=a=>Math.max(0,Math.min(1,a)),this.negK=0,this.scale=1):this.d===1?(this.easeOutFn=a=>a>0?1:0,this.negK=-1/0,this.scale=0):(this.negK=Math.log1p(-this.d),this.scale=1/Math.expm1(this.negK),this.easeOutFn=v.makeExpoEaseOut(this.d))}easeIn=t=>1-this.easeOutFn(1-t);easeInVelocity=t=>this.easeOutVelocityImpl(1-t);easeOut=t=>this.easeOutFn(t);easeOutVelocity=t=>this.easeOutVelocityImpl(t);easeOutVelocityImpl(t){return this.d===0?1:this.d===1?0:this.negK*Math.exp(this.negK*t)*this.scale}with(t){return new W({...this.params,...t})}static create(t={}){return new W({decay:t.decay??.95})}}const ue=e=>e,de=e=>1,he=1e-4;class q extends Y{static BOUNCES_KNOB={key:"bounces",label:"Bounces",type:"number",default:4,min:0,max:10,step:1,isPrimary:!0};static DECAY_KNOB={key:"decay",label:"Decay",type:"percent",default:.95,min:0,max:.99,step:.01};kind="spring";metadata={variants:{easeIn:!1,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[q.BOUNCES_KNOB,q.DECAY_KNOB];easeInBoundary={start:"nonzero",end:"nonzero"};builtP;builtV;constructor(t){super(t);const a=Z.build({joinTime:he,bounces:t.bounces,decayPct:t.decay*100,L:ue,Ld:de});this.builtP=a.p,this.builtV=a.v}easeIn=t=>1-this.builtP(1-t);easeInVelocity=t=>this.builtV(1-t);easeOut=t=>this.builtP(t);easeOutVelocity=t=>this.builtV(t);static get tailStrategy(){return Z}with(t){return new q({...this.params,...t})}static create(t={}){return new q({bounces:t.bounces??4,decay:t.decay??.95})}}const fe=e=>e,pe=e=>1,ge=1e-4;class X extends Y{static BOUNCES_KNOB={key:"bounces",label:"Bounces",type:"number",default:4,min:1,max:10,step:1,isPrimary:!0};static DECAY_KNOB={key:"decay",label:"Decay",type:"percent",default:.95,min:0,max:.99,step:.01};kind="bounce";metadata={variants:{easeIn:!1,easeOut:!0},modes:{transition:!0,pulse:!0}};knobSpecs=[X.BOUNCES_KNOB,X.DECAY_KNOB];easeInBoundary={start:"nonzero",end:"nonzero"};builtP;builtV;constructor(t){super(t);const a=j.build({joinTime:ge,bounces:t.bounces,decayPct:t.decay*100,L:fe,Ld:pe});this.builtP=a.p,this.builtV=a.v}easeIn=t=>1-this.builtP(1-t);easeInVelocity=t=>this.builtV(1-t);easeOut=t=>this.builtP(t);easeOutVelocity=t=>this.builtV(t);static get tailStrategy(){return j}with(t){return new X({...this.params,...t})}static create(t={}){return new X({bounces:t.bounces??4,decay:t.decay??.95})}}const ye={power:R,back:U,"power-back":G,bezier:D,expo:W,spring:q,bounce:X,swim:J};function st(e,t){return ye[e].create(t)}function ht(e){const{kind:t,...a}=e;return a}function me(e){const{movement:t="transition",head:a,tail:n,joinTime:o=.5,mirror:r=!1,useBridge:s,bridgeTuning:i,allowGeneralizedBackTail:u,maxSpeed:d}=e,l=st(a.kind,ht(a)),c=st(n.kind,ht(n));return ae(l,c,{movement:t,joinTime:o,mirror:r,useBridge:s,bridgeTuning:i,allowGeneralizedBackTail:u,maxSpeed:d})}const mt=1e-6,it=mt,Mt=1-mt;function Me(e,t,a=!1){return!a&&(t==="power-back"||t==="back"||t==="power")?Math.min(1,e):e}function be(e,t,a=!1){return!a&&t==="power-back"?Math.max(0,e):e}exports.BackRem=U;exports.BezierRem=D;exports.BounceRem=X;exports.ExpoRem=W;exports.PowerBackRem=G;exports.PowerRem=R;exports.SpringRem=q;exports.SwimRem=J;exports.calculateHeadP2FromTailP1=Lt;exports.calculateTailP1FromHeadP2=Ct;exports.clampBezierY1ForHead=be;exports.clampBezierY2ForTail=Me;exports.evalPowerBackIn=pt;exports.findExponentForMinimumPosition=Bt;exports.fuse=me;exports.getEasingRem=st;exports.getLocalMinimumPosition=kt;exports.getPowerCurveCanonicalPoint=St;exports.getTailStrategy=Kt;exports.solvePowerBackStrength=Q;
2
+ //# sourceMappingURL=index.cjs.js.map