@godot-scene-web/effects 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tomás Fox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ import { n as godotEaseSample, t as createEaseSampler } from "../index-CeKMJryT.js";
2
+ export { createEaseSampler, godotEaseSample };
@@ -0,0 +1,2 @@
1
+ import { n as godotEaseSample, t as createEaseSampler } from "../easing-BH-VRsXl.js";
2
+ export { createEaseSampler, godotEaseSample };
@@ -0,0 +1,237 @@
1
+ //#region src/easing/numeric.ts
2
+ const NORMALIZED_NAME_CACHE_LIMIT = 64;
3
+ const normalizedNames = /* @__PURE__ */ new Map();
4
+ function outInOf(halves) {
5
+ return (t) => t < .5 ? .5 * halves.out(t * 2) : .5 + .5 * halves.in(t * 2 - 1);
6
+ }
7
+ function inOutOf(halves) {
8
+ return (t) => t < .5 ? .5 * halves.in(t * 2) : .5 + .5 * halves.out(t * 2 - 1);
9
+ }
10
+ function family(f) {
11
+ return {
12
+ in: f.in,
13
+ out: f.out,
14
+ inOut: f.inOut,
15
+ outIn: outInOf(f)
16
+ };
17
+ }
18
+ const LINEAR = (() => {
19
+ const identity = (t) => t;
20
+ return {
21
+ in: identity,
22
+ out: identity,
23
+ inOut: identity,
24
+ outIn: identity
25
+ };
26
+ })();
27
+ const HALF_PI = Math.PI / 2;
28
+ const SINE = family({
29
+ in: (t) => 1 - Math.cos(t * HALF_PI),
30
+ out: (t) => Math.sin(t * HALF_PI),
31
+ inOut: (t) => -.5 * (Math.cos(Math.PI * t) - 1)
32
+ });
33
+ const QUINT = family({
34
+ in: (t) => t ** 5,
35
+ out: (t) => (t - 1) ** 5 + 1,
36
+ inOut: (t) => {
37
+ const u = t * 2;
38
+ return u < 1 ? .5 * u ** 5 : .5 * ((u - 2) ** 5 + 2);
39
+ }
40
+ });
41
+ const QUART = family({
42
+ in: (t) => t ** 4,
43
+ out: (t) => -((t - 1) ** 4 - 1),
44
+ inOut: (t) => {
45
+ const u = t * 2;
46
+ return u < 1 ? .5 * u ** 4 : -.5 * ((u - 2) ** 4 - 2);
47
+ }
48
+ });
49
+ const QUAD = family({
50
+ in: (t) => t ** 2,
51
+ out: (t) => -t * (t - 2),
52
+ inOut: (t) => {
53
+ const u = t * 2;
54
+ return u < 1 ? .5 * u ** 2 : -.5 * ((u - 1) * (u - 3) - 1);
55
+ }
56
+ });
57
+ const EXPO = family({
58
+ in: (t) => t === 0 ? 0 : 2 ** (10 * (t - 1)) - .001,
59
+ out: (t) => t === 1 ? 1 : 1.001 * (1 - 2 ** (-10 * t)),
60
+ inOut: (t) => {
61
+ if (t === 0) return 0;
62
+ if (t === 1) return 1;
63
+ const u = t * 2;
64
+ return u < 1 ? .5 * 2 ** (10 * (u - 1)) - 5e-4 : .5 * 1.0005 * (2 - 2 ** (-10 * (u - 1)));
65
+ }
66
+ });
67
+ const ELASTIC_PERIOD = .3;
68
+ const ELASTIC_SHIFT = ELASTIC_PERIOD / 4;
69
+ const ELASTIC_INOUT_PERIOD = .3 * 1.5;
70
+ const ELASTIC_INOUT_SHIFT = ELASTIC_INOUT_PERIOD / 4;
71
+ const ELASTIC = family({
72
+ in: (t) => {
73
+ if (t === 0) return 0;
74
+ if (t === 1) return 1;
75
+ const u = t - 1;
76
+ return -(2 ** (10 * u) * Math.sin((u - ELASTIC_SHIFT) * (2 * Math.PI) / ELASTIC_PERIOD));
77
+ },
78
+ out: (t) => {
79
+ if (t === 0) return 0;
80
+ if (t === 1) return 1;
81
+ return 2 ** (-10 * t) * Math.sin((t - ELASTIC_SHIFT) * (2 * Math.PI) / ELASTIC_PERIOD) + 1;
82
+ },
83
+ inOut: (t) => {
84
+ if (t === 0) return 0;
85
+ const u = t * 2;
86
+ if (u === 2) return 1;
87
+ const v = u - 1;
88
+ const phase = Math.sin((v - ELASTIC_INOUT_SHIFT) * (2 * Math.PI) / ELASTIC_INOUT_PERIOD);
89
+ return u < 1 ? -.5 * (2 ** (10 * v) * phase) : 2 ** (-10 * v) * phase * .5 + 1;
90
+ }
91
+ });
92
+ const CUBIC = family({
93
+ in: (t) => t * t * t,
94
+ out: (t) => {
95
+ const u = t - 1;
96
+ return u * u * u + 1;
97
+ },
98
+ inOut: (t) => {
99
+ const u = t * 2;
100
+ if (u < 1) return .5 * u * u * u;
101
+ const v = u - 2;
102
+ return .5 * (v * v * v + 2);
103
+ }
104
+ });
105
+ const CIRC = family({
106
+ in: (t) => -(Math.sqrt(1 - t * t) - 1),
107
+ out: (t) => {
108
+ const u = t - 1;
109
+ return Math.sqrt(1 - u * u);
110
+ },
111
+ inOut: (t) => {
112
+ const u = t * 2;
113
+ if (u < 1) return -.5 * (Math.sqrt(1 - u * u) - 1);
114
+ const v = u - 2;
115
+ return .5 * (Math.sqrt(1 - v * v) + 1);
116
+ }
117
+ });
118
+ const BOUNCE_OUT = (t) => {
119
+ if (t < 1 / 2.75) return 7.5625 * t * t;
120
+ if (t < 2 / 2.75) {
121
+ const u = t - 1.5 / 2.75;
122
+ return 7.5625 * u * u + .75;
123
+ }
124
+ if (t < 2.5 / 2.75) {
125
+ const u = t - 2.25 / 2.75;
126
+ return 7.5625 * u * u + .9375;
127
+ }
128
+ const u = t - 2.625 / 2.75;
129
+ return 7.5625 * u * u + .984375;
130
+ };
131
+ const BOUNCE_HALVES = {
132
+ in: (t) => 1 - BOUNCE_OUT(1 - t),
133
+ out: BOUNCE_OUT
134
+ };
135
+ const BOUNCE = {
136
+ ...BOUNCE_HALVES,
137
+ inOut: inOutOf(BOUNCE_HALVES),
138
+ outIn: outInOf(BOUNCE_HALVES)
139
+ };
140
+ const BACK_OVERSHOOT = 1.70158;
141
+ const BACK_INOUT_OVERSHOOT = 1.70158 * 1.525;
142
+ const BACK = family({
143
+ in: (t) => t * t * (2.70158 * t - BACK_OVERSHOOT),
144
+ out: (t) => {
145
+ const u = t - 1;
146
+ return u * u * (2.70158 * u + BACK_OVERSHOOT) + 1;
147
+ },
148
+ inOut: (t) => {
149
+ const s = BACK_INOUT_OVERSHOOT;
150
+ const u = t * 2;
151
+ if (u < 1) return .5 * (u * u * (3.5949095 * u - s));
152
+ const v = u - 2;
153
+ return .5 * (v * v * (3.5949095 * v + s) + 2);
154
+ }
155
+ });
156
+ const SPRING_OUT = (t) => {
157
+ const s = 1 - t;
158
+ return (Math.sin(t * Math.PI * (.2 + 2.5 * t * t * t)) * s ** 2.2 + t) * (1 + 1.2 * s);
159
+ };
160
+ const SPRING_HALVES = {
161
+ in: (t) => 1 - SPRING_OUT(1 - t),
162
+ out: SPRING_OUT
163
+ };
164
+ const SPRING = {
165
+ ...SPRING_HALVES,
166
+ inOut: inOutOf(SPRING_HALVES),
167
+ outIn: outInOf(SPRING_HALVES)
168
+ };
169
+ const FAMILIES = new Map([
170
+ ["linear", LINEAR],
171
+ ["sine", SINE],
172
+ ["quint", QUINT],
173
+ ["quart", QUART],
174
+ ["quad", QUAD],
175
+ ["expo", EXPO],
176
+ ["elastic", ELASTIC],
177
+ ["cubic", CUBIC],
178
+ ["circ", CIRC],
179
+ ["bounce", BOUNCE],
180
+ ["back", BACK],
181
+ ["spring", SPRING]
182
+ ]);
183
+ function normalizeName(name) {
184
+ if (typeof name !== "string") return "";
185
+ const cached = normalizedNames.get(name);
186
+ if (cached !== void 0) return cached;
187
+ const normalized = name.toLowerCase().replace(/[^a-z]/g, "");
188
+ if (normalizedNames.size < NORMALIZED_NAME_CACHE_LIMIT) normalizedNames.set(name, normalized);
189
+ return normalized;
190
+ }
191
+ /** Select Godot's family/mode column, with the engine's missing/unknown-name defaults. */
192
+ function resolveEaseSampler(ease, trans) {
193
+ const family = FAMILIES.get(normalizeName(trans)) ?? LINEAR;
194
+ const mode = normalizeName(ease);
195
+ return mode === "in" ? family.in : mode === "out" ? family.out : mode === "outin" ? family.outIn : family.inOut;
196
+ }
197
+ function sampleResolvedEase(sample, t) {
198
+ if (!(t > 0)) return 0;
199
+ if (t >= 1) return 1;
200
+ return sample(t);
201
+ }
202
+ /**
203
+ * Resolve a Godot easing family and mode once, returning a sampler for normalized time `t`.
204
+ *
205
+ * The returned function has the same endpoint behavior as `godotEaseSample`: values at or below
206
+ * zero (including NaN) are zero and values at or above one are one. Missing and unknown names use
207
+ * Godot's defaults (linear transition and in-out ease mode).
208
+ */
209
+ function createEaseSampler(ease, trans) {
210
+ const sample = resolveEaseSampler(ease, trans);
211
+ return (t) => sampleResolvedEase(sample, t);
212
+ }
213
+ /**
214
+ * Sample Godot's easing curve at normalized time `t`, returning the normalized progress (0 at the start, 1 at the
215
+ * end, and freely outside that range in between for the overshooting families).
216
+ *
217
+ * `ease` and `trans` are the RAW Godot enum names as they arrive over a live wire, exactly like
218
+ * `godotEasingToCss`: `ease` is "In"/"Out"/"InOut"/"OutIn" and `trans` is "Linear"/"Sine"/"Quint"/"Quart"/"Quad"/
219
+ * "Expo"/"Elastic"/"Cubic"/"Circ"/"Bounce"/"Back"/"Spring". Both are case-insensitive and tolerate separators
220
+ * ("in_out" reads as "InOut"). Unlike the CSS mapping — which has to collapse "OutIn" into the in-out column
221
+ * because CSS cannot express it — every one of Godot's four ease modes is available here.
222
+ *
223
+ * Defaults match Godot's `Tween`: a missing `trans` is TRANS_LINEAR and a missing `ease` is EASE_IN_OUT
224
+ * (`scene/animation/tween.h`). An UNRECOGNISED family also falls back to linear, so an unknown name degrades to
225
+ * "plays at the right speed on average" rather than to a guess with the wrong shape.
226
+ *
227
+ * `t` is clamped to [0, 1] (NaN reads as 0). Returning exactly 1 at t >= 1 is what the engine does, not a
228
+ * convenience: `PropertyTweener::step` assigns `final_val` outright once the elapsed time reaches the duration and
229
+ * never evaluates the equation there (`tween.cpp`). It matters for Expo, whose raw equation would end at 0.999.
230
+ */
231
+ function godotEaseSample(ease, trans, t) {
232
+ return sampleResolvedEase(resolveEaseSampler(ease, trans), t);
233
+ }
234
+ //#endregion
235
+ export { godotEaseSample as n, createEaseSampler as t };
236
+
237
+ //# sourceMappingURL=easing-BH-VRsXl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easing-BH-VRsXl.js","names":[],"sources":["../src/easing/numeric.ts"],"sourcesContent":["// Godot Tween easing → an EXACT numeric sample. The companion to `easing.ts`: that module maps a Godot\n// TransitionType×EaseType onto a CSS timing-function (a fit, and for some families only a fallback), which is what a\n// consumer wants when the browser animates the property itself. This module is for the other half of the problem —\n// when the consumer has to compute the value at time `t` itself (a canvas/WebGL frame, a sampled bake, a parity\n// check against the game) and an approximation is not good enough.\n//\n// The equations are ported 1:1 from the Godot Engine 4.5.1 source file `scene/animation/easing_equations.h`\n// (MIT-licensed; Copyright (c) 2014-present Godot Engine contributors, Copyright (c) 2007-2014 Juan Linietsky,\n// Ariel Manzur — itself derived from Robert Penner's easing equations, Copyright (c) 2001 Robert Penner).\n// `scene/animation/tween.cpp` supplies the dispatch: `Tween::interpolaters[TRANS][EASE]` picks the family/mode\n// function and `run_equation()` calls it as `func(time, 0.0, 1.0, duration)`, i.e. b=0, c=1 — so normalizing to\n// b=0, c=1, d=1 (what this module does) loses nothing: every equation is affine in b and c.\n\n/** One `t → value` curve, normalized to b=0, c=1, d=1. */\ntype EaseSampler = (t: number) => number;\n\n// Live effect renderers sample an easing once for every animated channel on every frame. Raw names\n// come from the wire and are often repeated verbatim, so retain their normalized forms. This is\n// deliberately a simple bounded memo rather than an LRU: names beyond the cap still compute\n// correctly, they simply do not turn untrusted input into unbounded retained memory.\nconst NORMALIZED_NAME_CACHE_LIMIT = 64;\nconst normalizedNames = new Map<string, string>();\n\n/** The four Godot EaseType columns for one TransitionType. */\ninterface EaseFamily {\n in: EaseSampler;\n out: EaseSampler;\n inOut: EaseSampler;\n outIn: EaseSampler;\n}\n\n// Godot's `out_in` is not an equation of its own: it runs `out` over the first half and `in` over the second, each\n// with c/2 (`easing_equations.h`, every family's `out_in`).\nfunction outInOf(halves: { in: EaseSampler; out: EaseSampler }): EaseSampler {\n return (t) =>\n t < 0.5 ? 0.5 * halves.out(t * 2) : 0.5 + 0.5 * halves.in(t * 2 - 1);\n}\n\n// The mirror of the above, used by Bounce and Spring, whose `in_out` is `in` then `out` over the halves rather than\n// a dedicated equation.\nfunction inOutOf(halves: { in: EaseSampler; out: EaseSampler }): EaseSampler {\n return (t) =>\n t < 0.5 ? 0.5 * halves.in(t * 2) : 0.5 + 0.5 * halves.out(t * 2 - 1);\n}\n\nfunction family(f: {\n in: EaseSampler;\n out: EaseSampler;\n inOut: EaseSampler;\n}): EaseFamily {\n return { in: f.in, out: f.out, inOut: f.inOut, outIn: outInOf(f) };\n}\n\n// Linear::in is bound to all four ease columns (\"Linear is the same for each easing\", tween.cpp).\nconst LINEAR: EaseFamily = (() => {\n const identity: EaseSampler = (t) => t;\n return { in: identity, out: identity, inOut: identity, outIn: identity };\n})();\n\nconst HALF_PI = Math.PI / 2;\n\nconst SINE = family({\n in: (t) => 1 - Math.cos(t * HALF_PI),\n out: (t) => Math.sin(t * HALF_PI),\n inOut: (t) => -0.5 * (Math.cos(Math.PI * t) - 1),\n});\n\nconst QUINT = family({\n in: (t) => t ** 5,\n out: (t) => (t - 1) ** 5 + 1,\n inOut: (t) => {\n const u = t * 2;\n return u < 1 ? 0.5 * u ** 5 : 0.5 * ((u - 2) ** 5 + 2);\n },\n});\n\nconst QUART = family({\n in: (t) => t ** 4,\n out: (t) => -((t - 1) ** 4 - 1),\n inOut: (t) => {\n const u = t * 2;\n return u < 1 ? 0.5 * u ** 4 : -0.5 * ((u - 2) ** 4 - 2);\n },\n});\n\nconst QUAD = family({\n in: (t) => t ** 2,\n out: (t) => -t * (t - 2),\n inOut: (t) => {\n const u = t * 2;\n return u < 1 ? 0.5 * u ** 2 : -0.5 * ((u - 1) * (u - 3) - 1);\n },\n});\n\n// Expo carries Godot's (Penner's) small corrections — `- c * 0.001` on the way in, `* 1.001` on the way out — which\n// exist to pull the curve's start/end onto the endpoints. They are kept EXACTLY: `godotEaseSample` is meant to\n// reproduce the game's numbers, including that `Expo::in` really does reach only 0.999 as t approaches d.\nconst EXPO = family({\n in: (t) => (t === 0 ? 0 : 2 ** (10 * (t - 1)) - 0.001),\n out: (t) => (t === 1 ? 1 : 1.001 * (1 - 2 ** (-10 * t))),\n inOut: (t) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n const u = t * 2;\n return u < 1\n ? 0.5 * 2 ** (10 * (u - 1)) - 0.0005\n : 0.5 * 1.0005 * (2 - 2 ** (-10 * (u - 1)));\n },\n});\n\n// Elastic with d=1: p = 0.3 (period), s = p/4 = 0.075 (phase shift); the in-out variant stretches the period to\n// 0.3*1.5 = 0.45, so s = 0.1125.\nconst ELASTIC_PERIOD = 0.3;\nconst ELASTIC_SHIFT = ELASTIC_PERIOD / 4;\nconst ELASTIC_INOUT_PERIOD = 0.3 * 1.5;\nconst ELASTIC_INOUT_SHIFT = ELASTIC_INOUT_PERIOD / 4;\n\nconst ELASTIC = family({\n in: (t) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n const u = t - 1;\n const a = 2 ** (10 * u);\n return -(\n a * Math.sin(((u - ELASTIC_SHIFT) * (2 * Math.PI)) / ELASTIC_PERIOD)\n );\n },\n out: (t) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n return (\n 2 ** (-10 * t) *\n Math.sin(((t - ELASTIC_SHIFT) * (2 * Math.PI)) / ELASTIC_PERIOD) +\n 1\n );\n },\n inOut: (t) => {\n if (t === 0) return 0;\n const u = t * 2;\n if (u === 2) return 1;\n const v = u - 1;\n const phase = Math.sin(\n ((v - ELASTIC_INOUT_SHIFT) * (2 * Math.PI)) / ELASTIC_INOUT_PERIOD,\n );\n return u < 1\n ? -0.5 * (2 ** (10 * v) * phase)\n : 2 ** (-10 * v) * phase * 0.5 + 1;\n },\n});\n\nconst CUBIC = family({\n in: (t) => t * t * t,\n out: (t) => {\n const u = t - 1;\n return u * u * u + 1;\n },\n inOut: (t) => {\n const u = t * 2;\n if (u < 1) return 0.5 * u * u * u;\n const v = u - 2;\n return 0.5 * (v * v * v + 2);\n },\n});\n\nconst CIRC = family({\n in: (t) => -(Math.sqrt(1 - t * t) - 1),\n out: (t) => {\n const u = t - 1;\n return Math.sqrt(1 - u * u);\n },\n inOut: (t) => {\n const u = t * 2;\n if (u < 1) return -0.5 * (Math.sqrt(1 - u * u) - 1);\n const v = u - 2;\n return 0.5 * (Math.sqrt(1 - v * v) + 1);\n },\n});\n\nconst BOUNCE_OUT: EaseSampler = (t) => {\n if (t < 1 / 2.75) return 7.5625 * t * t;\n if (t < 2 / 2.75) {\n const u = t - 1.5 / 2.75;\n return 7.5625 * u * u + 0.75;\n }\n if (t < 2.5 / 2.75) {\n const u = t - 2.25 / 2.75;\n return 7.5625 * u * u + 0.9375;\n }\n const u = t - 2.625 / 2.75;\n return 7.5625 * u * u + 0.984375;\n};\n\n// Bounce::in is defined as `c - out(d - t)`, and Bounce::in_out as in-then-out over the halves (NOT the usual\n// dedicated equation) — same for Spring.\nconst BOUNCE_HALVES = {\n in: (t: number) => 1 - BOUNCE_OUT(1 - t),\n out: BOUNCE_OUT,\n};\nconst BOUNCE: EaseFamily = {\n ...BOUNCE_HALVES,\n inOut: inOutOf(BOUNCE_HALVES),\n outIn: outInOf(BOUNCE_HALVES),\n};\n\nconst BACK_OVERSHOOT = 1.70158;\nconst BACK_INOUT_OVERSHOOT = 1.70158 * 1.525;\n\nconst BACK = family({\n in: (t) => t * t * ((BACK_OVERSHOOT + 1) * t - BACK_OVERSHOOT),\n out: (t) => {\n const u = t - 1;\n return u * u * ((BACK_OVERSHOOT + 1) * u + BACK_OVERSHOOT) + 1;\n },\n inOut: (t) => {\n const s = BACK_INOUT_OVERSHOOT;\n const u = t * 2;\n if (u < 1) return 0.5 * (u * u * ((s + 1) * u - s));\n const v = u - 2;\n return 0.5 * (v * v * ((s + 1) * v + s) + 2);\n },\n});\n\nconst SPRING_OUT: EaseSampler = (t) => {\n const s = 1 - t;\n return (\n (Math.sin(t * Math.PI * (0.2 + 2.5 * t * t * t)) * s ** 2.2 + t) *\n (1 + 1.2 * s)\n );\n};\n\nconst SPRING_HALVES = {\n in: (t: number) => 1 - SPRING_OUT(1 - t),\n out: SPRING_OUT,\n};\nconst SPRING: EaseFamily = {\n ...SPRING_HALVES,\n inOut: inOutOf(SPRING_HALVES),\n outIn: outInOf(SPRING_HALVES),\n};\n\n// Keyed by the lowercased Godot TransitionType name, in the enum's own order (tween.cpp `interpolaters`).\nconst FAMILIES = new Map<string, EaseFamily>([\n [\"linear\", LINEAR],\n [\"sine\", SINE],\n [\"quint\", QUINT],\n [\"quart\", QUART],\n [\"quad\", QUAD],\n [\"expo\", EXPO],\n [\"elastic\", ELASTIC],\n [\"cubic\", CUBIC],\n [\"circ\", CIRC],\n [\"bounce\", BOUNCE],\n [\"back\", BACK],\n [\"spring\", SPRING],\n]);\n\nfunction normalizeName(name: string | undefined): string {\n if (typeof name !== \"string\") return \"\";\n const cached = normalizedNames.get(name);\n if (cached !== undefined) return cached;\n const normalized = name.toLowerCase().replace(/[^a-z]/g, \"\");\n if (normalizedNames.size < NORMALIZED_NAME_CACHE_LIMIT)\n normalizedNames.set(name, normalized);\n return normalized;\n}\n\n/** Select Godot's family/mode column, with the engine's missing/unknown-name defaults. */\nfunction resolveEaseSampler(\n ease: string | undefined,\n trans: string | undefined,\n): EaseSampler {\n const family = FAMILIES.get(normalizeName(trans)) ?? LINEAR;\n const mode = normalizeName(ease);\n return mode === \"in\"\n ? family.in\n : mode === \"out\"\n ? family.out\n : mode === \"outin\"\n ? family.outIn\n : family.inOut;\n}\n\nfunction sampleResolvedEase(sample: EaseSampler, t: number): number {\n if (!(t > 0)) return 0;\n if (t >= 1) return 1;\n return sample(t);\n}\n\n/**\n * Resolve a Godot easing family and mode once, returning a sampler for normalized time `t`.\n *\n * The returned function has the same endpoint behavior as `godotEaseSample`: values at or below\n * zero (including NaN) are zero and values at or above one are one. Missing and unknown names use\n * Godot's defaults (linear transition and in-out ease mode).\n */\nexport function createEaseSampler(\n ease: string | undefined,\n trans: string | undefined,\n): (t: number) => number {\n const sample = resolveEaseSampler(ease, trans);\n return (t) => sampleResolvedEase(sample, t);\n}\n\n/**\n * Sample Godot's easing curve at normalized time `t`, returning the normalized progress (0 at the start, 1 at the\n * end, and freely outside that range in between for the overshooting families).\n *\n * `ease` and `trans` are the RAW Godot enum names as they arrive over a live wire, exactly like\n * `godotEasingToCss`: `ease` is \"In\"/\"Out\"/\"InOut\"/\"OutIn\" and `trans` is \"Linear\"/\"Sine\"/\"Quint\"/\"Quart\"/\"Quad\"/\n * \"Expo\"/\"Elastic\"/\"Cubic\"/\"Circ\"/\"Bounce\"/\"Back\"/\"Spring\". Both are case-insensitive and tolerate separators\n * (\"in_out\" reads as \"InOut\"). Unlike the CSS mapping — which has to collapse \"OutIn\" into the in-out column\n * because CSS cannot express it — every one of Godot's four ease modes is available here.\n *\n * Defaults match Godot's `Tween`: a missing `trans` is TRANS_LINEAR and a missing `ease` is EASE_IN_OUT\n * (`scene/animation/tween.h`). An UNRECOGNISED family also falls back to linear, so an unknown name degrades to\n * \"plays at the right speed on average\" rather than to a guess with the wrong shape.\n *\n * `t` is clamped to [0, 1] (NaN reads as 0). Returning exactly 1 at t >= 1 is what the engine does, not a\n * convenience: `PropertyTweener::step` assigns `final_val` outright once the elapsed time reaches the duration and\n * never evaluates the equation there (`tween.cpp`). It matters for Expo, whose raw equation would end at 0.999.\n */\nexport function godotEaseSample(\n ease: string | undefined,\n trans: string | undefined,\n t: number,\n): number {\n return sampleResolvedEase(resolveEaseSampler(ease, trans), t);\n}\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ //#region src/easing/numeric.d.ts
2
+ /**
3
+ * Resolve a Godot easing family and mode once, returning a sampler for normalized time `t`.
4
+ *
5
+ * The returned function has the same endpoint behavior as `godotEaseSample`: values at or below
6
+ * zero (including NaN) are zero and values at or above one are one. Missing and unknown names use
7
+ * Godot's defaults (linear transition and in-out ease mode).
8
+ */
9
+ declare function createEaseSampler(ease: string | undefined, trans: string | undefined): (t: number) => number;
10
+ /**
11
+ * Sample Godot's easing curve at normalized time `t`, returning the normalized progress (0 at the start, 1 at the
12
+ * end, and freely outside that range in between for the overshooting families).
13
+ *
14
+ * `ease` and `trans` are the RAW Godot enum names as they arrive over a live wire, exactly like
15
+ * `godotEasingToCss`: `ease` is "In"/"Out"/"InOut"/"OutIn" and `trans` is "Linear"/"Sine"/"Quint"/"Quart"/"Quad"/
16
+ * "Expo"/"Elastic"/"Cubic"/"Circ"/"Bounce"/"Back"/"Spring". Both are case-insensitive and tolerate separators
17
+ * ("in_out" reads as "InOut"). Unlike the CSS mapping — which has to collapse "OutIn" into the in-out column
18
+ * because CSS cannot express it — every one of Godot's four ease modes is available here.
19
+ *
20
+ * Defaults match Godot's `Tween`: a missing `trans` is TRANS_LINEAR and a missing `ease` is EASE_IN_OUT
21
+ * (`scene/animation/tween.h`). An UNRECOGNISED family also falls back to linear, so an unknown name degrades to
22
+ * "plays at the right speed on average" rather than to a guess with the wrong shape.
23
+ *
24
+ * `t` is clamped to [0, 1] (NaN reads as 0). Returning exactly 1 at t >= 1 is what the engine does, not a
25
+ * convenience: `PropertyTweener::step` assigns `final_val` outright once the elapsed time reaches the duration and
26
+ * never evaluates the equation there (`tween.cpp`). It matters for Expo, whose raw equation would end at 0.999.
27
+ */
28
+ declare function godotEaseSample(ease: string | undefined, trans: string | undefined, t: number): number;
29
+ //#endregion
30
+ export { godotEaseSample as n, createEaseSampler as t };
31
+ //# sourceMappingURL=index-CeKMJryT.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CeKMJryT.d.ts","names":[],"sources":["../src/easing/numeric.ts"],"mappings":";;AAuSA;;;;;;iBAAgB,iBAAA,CACd,IAAA,sBACA,KAAA,wBACE,CAAA;;AAAS;AAuBb;;;;;;;;AAGW;;;;;;;;iBAHK,eAAA,CACd,IAAA,sBACA,KAAA,sBACA,CAAA"}