@flare-engine/math 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 +21 -0
- package/README.md +29 -0
- package/dist/index.d.mts +308 -0
- package/dist/index.d.ts +308 -0
- package/dist/index.js +1102 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1008 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +39 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Circle: () => Circle,
|
|
24
|
+
Color: () => Color,
|
|
25
|
+
Mat3: () => Mat3,
|
|
26
|
+
Rect: () => Rect,
|
|
27
|
+
SeededRNG: () => SeededRNG,
|
|
28
|
+
Transform2D: () => Transform2D,
|
|
29
|
+
Vec2: () => Vec2,
|
|
30
|
+
approxEquals: () => approxEquals,
|
|
31
|
+
choose: () => choose,
|
|
32
|
+
circleVsCircle: () => circleVsCircle,
|
|
33
|
+
clamp: () => clamp,
|
|
34
|
+
degToRad: () => degToRad,
|
|
35
|
+
easeInBack: () => easeInBack,
|
|
36
|
+
easeInBounce: () => easeInBounce,
|
|
37
|
+
easeInCirc: () => easeInCirc,
|
|
38
|
+
easeInCubic: () => easeInCubic,
|
|
39
|
+
easeInElastic: () => easeInElastic,
|
|
40
|
+
easeInExpo: () => easeInExpo,
|
|
41
|
+
easeInOutBack: () => easeInOutBack,
|
|
42
|
+
easeInOutBounce: () => easeInOutBounce,
|
|
43
|
+
easeInOutCirc: () => easeInOutCirc,
|
|
44
|
+
easeInOutCubic: () => easeInOutCubic,
|
|
45
|
+
easeInOutElastic: () => easeInOutElastic,
|
|
46
|
+
easeInOutExpo: () => easeInOutExpo,
|
|
47
|
+
easeInOutQuad: () => easeInOutQuad,
|
|
48
|
+
easeInOutQuart: () => easeInOutQuart,
|
|
49
|
+
easeInOutQuint: () => easeInOutQuint,
|
|
50
|
+
easeInOutSine: () => easeInOutSine,
|
|
51
|
+
easeInQuad: () => easeInQuad,
|
|
52
|
+
easeInQuart: () => easeInQuart,
|
|
53
|
+
easeInQuint: () => easeInQuint,
|
|
54
|
+
easeInSine: () => easeInSine,
|
|
55
|
+
easeOutBack: () => easeOutBack,
|
|
56
|
+
easeOutBounce: () => easeOutBounce,
|
|
57
|
+
easeOutCirc: () => easeOutCirc,
|
|
58
|
+
easeOutCubic: () => easeOutCubic,
|
|
59
|
+
easeOutElastic: () => easeOutElastic,
|
|
60
|
+
easeOutExpo: () => easeOutExpo,
|
|
61
|
+
easeOutQuad: () => easeOutQuad,
|
|
62
|
+
easeOutQuart: () => easeOutQuart,
|
|
63
|
+
easeOutQuint: () => easeOutQuint,
|
|
64
|
+
easeOutSine: () => easeOutSine,
|
|
65
|
+
inverseLerp: () => inverseLerp,
|
|
66
|
+
lerp: () => lerp,
|
|
67
|
+
lineVsCircle: () => lineVsCircle,
|
|
68
|
+
lineVsRect: () => lineVsRect,
|
|
69
|
+
linear: () => linear,
|
|
70
|
+
map: () => map,
|
|
71
|
+
pingPong: () => pingPong,
|
|
72
|
+
pointInCircle: () => pointInCircle,
|
|
73
|
+
pointInRect: () => pointInRect,
|
|
74
|
+
radToDeg: () => radToDeg,
|
|
75
|
+
randomFloat: () => randomFloat,
|
|
76
|
+
randomInt: () => randomInt,
|
|
77
|
+
randomPointInCircle: () => randomPointInCircle,
|
|
78
|
+
randomVec2InRect: () => randomVec2InRect,
|
|
79
|
+
rayVsRect: () => rayVsRect,
|
|
80
|
+
rectVsCircle: () => rectVsCircle,
|
|
81
|
+
rectVsRect: () => rectVsRect,
|
|
82
|
+
shuffle: () => shuffle,
|
|
83
|
+
sign: () => sign,
|
|
84
|
+
smoothStep: () => smoothStep,
|
|
85
|
+
springIn: () => springIn,
|
|
86
|
+
springInOut: () => springInOut,
|
|
87
|
+
springOut: () => springOut,
|
|
88
|
+
step: () => step,
|
|
89
|
+
vec2: () => vec2,
|
|
90
|
+
wrap: () => wrap
|
|
91
|
+
});
|
|
92
|
+
module.exports = __toCommonJS(index_exports);
|
|
93
|
+
|
|
94
|
+
// src/scalar.ts
|
|
95
|
+
function clamp(value, min, max) {
|
|
96
|
+
return value < min ? min : value > max ? max : value;
|
|
97
|
+
}
|
|
98
|
+
function lerp(a, b, t) {
|
|
99
|
+
return a + (b - a) * t;
|
|
100
|
+
}
|
|
101
|
+
function inverseLerp(a, b, value) {
|
|
102
|
+
const range = b - a;
|
|
103
|
+
if (range === 0) return 0;
|
|
104
|
+
return (value - a) / range;
|
|
105
|
+
}
|
|
106
|
+
function map(value, inMin, inMax, outMin, outMax) {
|
|
107
|
+
return lerp(outMin, outMax, inverseLerp(inMin, inMax, value));
|
|
108
|
+
}
|
|
109
|
+
var DEG_TO_RAD = Math.PI / 180;
|
|
110
|
+
var RAD_TO_DEG = 180 / Math.PI;
|
|
111
|
+
function degToRad(degrees) {
|
|
112
|
+
return degrees * DEG_TO_RAD;
|
|
113
|
+
}
|
|
114
|
+
function radToDeg(radians) {
|
|
115
|
+
return radians * RAD_TO_DEG;
|
|
116
|
+
}
|
|
117
|
+
function approxEquals(a, b, epsilon = 1e-6) {
|
|
118
|
+
return Math.abs(a - b) <= epsilon;
|
|
119
|
+
}
|
|
120
|
+
function wrap(value, min, max) {
|
|
121
|
+
const range = max - min;
|
|
122
|
+
if (range === 0) return min;
|
|
123
|
+
return min + ((value - min) % range + range) % range;
|
|
124
|
+
}
|
|
125
|
+
function pingPong(t, length) {
|
|
126
|
+
if (length === 0) return 0;
|
|
127
|
+
const tt = wrap(t, 0, length * 2);
|
|
128
|
+
return length - Math.abs(tt - length);
|
|
129
|
+
}
|
|
130
|
+
function smoothStep(edge0, edge1, x) {
|
|
131
|
+
const range = edge1 - edge0;
|
|
132
|
+
if (range === 0) return x >= edge1 ? 1 : 0;
|
|
133
|
+
const t = clamp((x - edge0) / range, 0, 1);
|
|
134
|
+
return t * t * (3 - 2 * t);
|
|
135
|
+
}
|
|
136
|
+
function sign(value) {
|
|
137
|
+
if (Number.isNaN(value)) return 0;
|
|
138
|
+
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/vec2.ts
|
|
142
|
+
function vec2(x = 0, y = 0) {
|
|
143
|
+
return { x, y };
|
|
144
|
+
}
|
|
145
|
+
var Vec2 = {
|
|
146
|
+
/** Returns { 0, 0 }. */
|
|
147
|
+
zero() {
|
|
148
|
+
return { x: 0, y: 0 };
|
|
149
|
+
},
|
|
150
|
+
/** Returns { 1, 1 }. */
|
|
151
|
+
one() {
|
|
152
|
+
return { x: 1, y: 1 };
|
|
153
|
+
},
|
|
154
|
+
/** Returns { 0, -1 }. */
|
|
155
|
+
up() {
|
|
156
|
+
return { x: 0, y: -1 };
|
|
157
|
+
},
|
|
158
|
+
/** Returns { 0, 1 }. */
|
|
159
|
+
down() {
|
|
160
|
+
return { x: 0, y: 1 };
|
|
161
|
+
},
|
|
162
|
+
/** Returns { -1, 0 }. */
|
|
163
|
+
left() {
|
|
164
|
+
return { x: -1, y: 0 };
|
|
165
|
+
},
|
|
166
|
+
/** Returns { 1, 0 }. */
|
|
167
|
+
right() {
|
|
168
|
+
return { x: 1, y: 0 };
|
|
169
|
+
},
|
|
170
|
+
/** Component-wise addition. Writes into out if provided. */
|
|
171
|
+
add(a, b, out) {
|
|
172
|
+
if (out) {
|
|
173
|
+
out.x = a.x + b.x;
|
|
174
|
+
out.y = a.y + b.y;
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
return { x: a.x + b.x, y: a.y + b.y };
|
|
178
|
+
},
|
|
179
|
+
/** Component-wise subtraction a - b. */
|
|
180
|
+
sub(a, b, out) {
|
|
181
|
+
if (out) {
|
|
182
|
+
out.x = a.x - b.x;
|
|
183
|
+
out.y = a.y - b.y;
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
return { x: a.x - b.x, y: a.y - b.y };
|
|
187
|
+
},
|
|
188
|
+
/** Scales a vector by a scalar. */
|
|
189
|
+
scale(v, s, out) {
|
|
190
|
+
if (out) {
|
|
191
|
+
out.x = v.x * s;
|
|
192
|
+
out.y = v.y * s;
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
return { x: v.x * s, y: v.y * s };
|
|
196
|
+
},
|
|
197
|
+
/** Returns a unit vector. Returns zero vector if length is 0. */
|
|
198
|
+
normalize(v, out) {
|
|
199
|
+
const len = Math.sqrt(v.x * v.x + v.y * v.y);
|
|
200
|
+
if (len === 0) {
|
|
201
|
+
if (out) {
|
|
202
|
+
out.x = 0;
|
|
203
|
+
out.y = 0;
|
|
204
|
+
return out;
|
|
205
|
+
}
|
|
206
|
+
return { x: 0, y: 0 };
|
|
207
|
+
}
|
|
208
|
+
const inv = 1 / len;
|
|
209
|
+
if (out) {
|
|
210
|
+
out.x = v.x * inv;
|
|
211
|
+
out.y = v.y * inv;
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
return { x: v.x * inv, y: v.y * inv };
|
|
215
|
+
},
|
|
216
|
+
/** Zero-alloc; writes into `out`. Mandatory `out` so callers avoid temporaries in hot paths. */
|
|
217
|
+
normalizeOut(dx, dy, speed, out) {
|
|
218
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
219
|
+
if (len <= 1e-6) {
|
|
220
|
+
out.x = 0;
|
|
221
|
+
out.y = 0;
|
|
222
|
+
return out;
|
|
223
|
+
}
|
|
224
|
+
const inv = speed / len;
|
|
225
|
+
out.x = dx * inv;
|
|
226
|
+
out.y = dy * inv;
|
|
227
|
+
return out;
|
|
228
|
+
},
|
|
229
|
+
/** Dot product. */
|
|
230
|
+
dot(a, b) {
|
|
231
|
+
return a.x * b.x + a.y * b.y;
|
|
232
|
+
},
|
|
233
|
+
/** 2D cross product (z-component of the 3D cross). */
|
|
234
|
+
cross(a, b) {
|
|
235
|
+
return a.x * b.y - a.y * b.x;
|
|
236
|
+
},
|
|
237
|
+
/** Linearly interpolates between a and b (unclamped). */
|
|
238
|
+
lerp(a, b, t, out) {
|
|
239
|
+
const x = a.x + (b.x - a.x) * t;
|
|
240
|
+
const y = a.y + (b.y - a.y) * t;
|
|
241
|
+
if (out) {
|
|
242
|
+
out.x = x;
|
|
243
|
+
out.y = y;
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
return { x, y };
|
|
247
|
+
},
|
|
248
|
+
/** Spherical linear interpolation for unit vectors. */
|
|
249
|
+
slerp(a, b, t, out) {
|
|
250
|
+
let d = a.x * b.x + a.y * b.y;
|
|
251
|
+
d = d < -1 ? -1 : d > 1 ? 1 : d;
|
|
252
|
+
const theta = Math.acos(d);
|
|
253
|
+
if (theta < 1e-6) {
|
|
254
|
+
return Vec2.lerp(a, b, t, out);
|
|
255
|
+
}
|
|
256
|
+
const sinTheta = Math.sin(theta);
|
|
257
|
+
const wa = Math.sin((1 - t) * theta) / sinTheta;
|
|
258
|
+
const wb = Math.sin(t * theta) / sinTheta;
|
|
259
|
+
const x = a.x * wa + b.x * wb;
|
|
260
|
+
const y = a.y * wa + b.y * wb;
|
|
261
|
+
if (out) {
|
|
262
|
+
out.x = x;
|
|
263
|
+
out.y = y;
|
|
264
|
+
return out;
|
|
265
|
+
}
|
|
266
|
+
return { x, y };
|
|
267
|
+
},
|
|
268
|
+
/** Euclidean distance between two points. */
|
|
269
|
+
distance(a, b) {
|
|
270
|
+
const dx = b.x - a.x;
|
|
271
|
+
const dy = b.y - a.y;
|
|
272
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
273
|
+
},
|
|
274
|
+
/** Squared distance (avoids sqrt). */
|
|
275
|
+
distanceSq(a, b) {
|
|
276
|
+
const dx = b.x - a.x;
|
|
277
|
+
const dy = b.y - a.y;
|
|
278
|
+
return dx * dx + dy * dy;
|
|
279
|
+
},
|
|
280
|
+
/** Length of a vector. */
|
|
281
|
+
length(v) {
|
|
282
|
+
return Math.sqrt(v.x * v.x + v.y * v.y);
|
|
283
|
+
},
|
|
284
|
+
/** Squared length (avoids sqrt). */
|
|
285
|
+
lengthSq(v) {
|
|
286
|
+
return v.x * v.x + v.y * v.y;
|
|
287
|
+
},
|
|
288
|
+
/** Angle of vector in radians (atan2). */
|
|
289
|
+
angle(v) {
|
|
290
|
+
return Math.atan2(v.y, v.x);
|
|
291
|
+
},
|
|
292
|
+
/** Rotates a vector by angle (radians) around origin. */
|
|
293
|
+
rotate(v, angle, out) {
|
|
294
|
+
const c = Math.cos(angle);
|
|
295
|
+
const s = Math.sin(angle);
|
|
296
|
+
const x = v.x * c - v.y * s;
|
|
297
|
+
const y = v.x * s + v.y * c;
|
|
298
|
+
if (out) {
|
|
299
|
+
out.x = x;
|
|
300
|
+
out.y = y;
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
return { x, y };
|
|
304
|
+
},
|
|
305
|
+
/** Component-wise approximate equality. */
|
|
306
|
+
equals(a, b, epsilon = 1e-6) {
|
|
307
|
+
return approxEquals(a.x, b.x, epsilon) && approxEquals(a.y, b.y, epsilon);
|
|
308
|
+
},
|
|
309
|
+
/** Returns a copy of the vector. */
|
|
310
|
+
clone(v) {
|
|
311
|
+
return { x: v.x, y: v.y };
|
|
312
|
+
},
|
|
313
|
+
/** Clamps the length of a vector to maxLength. */
|
|
314
|
+
clampLength(v, maxLength, out) {
|
|
315
|
+
const lenSq = v.x * v.x + v.y * v.y;
|
|
316
|
+
if (lenSq <= maxLength * maxLength) {
|
|
317
|
+
if (out) {
|
|
318
|
+
out.x = v.x;
|
|
319
|
+
out.y = v.y;
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
return { x: v.x, y: v.y };
|
|
323
|
+
}
|
|
324
|
+
const len = Math.sqrt(lenSq);
|
|
325
|
+
const inv = maxLength / len;
|
|
326
|
+
if (out) {
|
|
327
|
+
out.x = v.x * inv;
|
|
328
|
+
out.y = v.y * inv;
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
return { x: v.x * inv, y: v.y * inv };
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/rect.ts
|
|
336
|
+
var Rect = {
|
|
337
|
+
/** Returns true if point is inside rect (inclusive). */
|
|
338
|
+
contains(r, p) {
|
|
339
|
+
return p.x >= r.x && p.x <= r.x + r.width && p.y >= r.y && p.y <= r.y + r.height;
|
|
340
|
+
},
|
|
341
|
+
/** Returns true if two rects overlap (share area). */
|
|
342
|
+
intersects(a, b) {
|
|
343
|
+
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
|
344
|
+
},
|
|
345
|
+
/** Returns the overlapping rect, or null if no overlap. */
|
|
346
|
+
intersection(a, b) {
|
|
347
|
+
const x = Math.max(a.x, b.x);
|
|
348
|
+
const y = Math.max(a.y, b.y);
|
|
349
|
+
const right = Math.min(a.x + a.width, b.x + b.width);
|
|
350
|
+
const bottom = Math.min(a.y + a.height, b.y + b.height);
|
|
351
|
+
if (right <= x || bottom <= y) return null;
|
|
352
|
+
return { x, y, width: right - x, height: bottom - y };
|
|
353
|
+
},
|
|
354
|
+
/** Returns the smallest rect containing both rects. */
|
|
355
|
+
union(a, b) {
|
|
356
|
+
const x = Math.min(a.x, b.x);
|
|
357
|
+
const y = Math.min(a.y, b.y);
|
|
358
|
+
const right = Math.max(a.x + a.width, b.x + b.width);
|
|
359
|
+
const bottom = Math.max(a.y + a.height, b.y + b.height);
|
|
360
|
+
return { x, y, width: right - x, height: bottom - y };
|
|
361
|
+
},
|
|
362
|
+
/** Creates a rect from an array of points (bounding box). */
|
|
363
|
+
fromPoints(points) {
|
|
364
|
+
if (points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };
|
|
365
|
+
let minX = points[0].x;
|
|
366
|
+
let minY = points[0].y;
|
|
367
|
+
let maxX = minX;
|
|
368
|
+
let maxY = minY;
|
|
369
|
+
for (let i = 1; i < points.length; i++) {
|
|
370
|
+
const p = points[i];
|
|
371
|
+
if (p.x < minX) minX = p.x;
|
|
372
|
+
if (p.y < minY) minY = p.y;
|
|
373
|
+
if (p.x > maxX) maxX = p.x;
|
|
374
|
+
if (p.y > maxY) maxY = p.y;
|
|
375
|
+
}
|
|
376
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
377
|
+
},
|
|
378
|
+
/** Returns the center point of the rect. */
|
|
379
|
+
center(r) {
|
|
380
|
+
return { x: r.x + r.width * 0.5, y: r.y + r.height * 0.5 };
|
|
381
|
+
},
|
|
382
|
+
/** Returns a new rect expanded by amount on each side. */
|
|
383
|
+
expand(r, amount) {
|
|
384
|
+
return {
|
|
385
|
+
x: r.x - amount,
|
|
386
|
+
y: r.y - amount,
|
|
387
|
+
width: r.width + amount * 2,
|
|
388
|
+
height: r.height + amount * 2
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/circle.ts
|
|
394
|
+
var Circle = {
|
|
395
|
+
/** Returns true if point is inside or on the circle. */
|
|
396
|
+
contains(c, p) {
|
|
397
|
+
const dx = p.x - c.x;
|
|
398
|
+
const dy = p.y - c.y;
|
|
399
|
+
return dx * dx + dy * dy <= c.radius * c.radius;
|
|
400
|
+
},
|
|
401
|
+
/** Returns true if two circles overlap (share area). */
|
|
402
|
+
intersects(a, b) {
|
|
403
|
+
const dx = b.x - a.x;
|
|
404
|
+
const dy = b.y - a.y;
|
|
405
|
+
const distSq = dx * dx + dy * dy;
|
|
406
|
+
const radSum = a.radius + b.radius;
|
|
407
|
+
return distSq < radSum * radSum;
|
|
408
|
+
},
|
|
409
|
+
/** Returns true if a circle and rect overlap. */
|
|
410
|
+
intersectsRect(c, r) {
|
|
411
|
+
const closestX = c.x < r.x ? r.x : c.x > r.x + r.width ? r.x + r.width : c.x;
|
|
412
|
+
const closestY = c.y < r.y ? r.y : c.y > r.y + r.height ? r.y + r.height : c.y;
|
|
413
|
+
const dx = c.x - closestX;
|
|
414
|
+
const dy = c.y - closestY;
|
|
415
|
+
return dx * dx + dy * dy <= c.radius * c.radius;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// src/transform2d.ts
|
|
420
|
+
var Transform2D = {
|
|
421
|
+
/** Creates an identity transform. */
|
|
422
|
+
identity() {
|
|
423
|
+
return { position: { x: 0, y: 0 }, rotation: 0, scale: { x: 1, y: 1 } };
|
|
424
|
+
},
|
|
425
|
+
/** Creates a transform from components. */
|
|
426
|
+
create(x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1) {
|
|
427
|
+
return {
|
|
428
|
+
position: { x, y },
|
|
429
|
+
rotation,
|
|
430
|
+
scale: { x: scaleX, y: scaleY }
|
|
431
|
+
};
|
|
432
|
+
},
|
|
433
|
+
/** Transforms a local-space point to world-space. */
|
|
434
|
+
localToWorld(t, point) {
|
|
435
|
+
const c = Math.cos(t.rotation);
|
|
436
|
+
const s = Math.sin(t.rotation);
|
|
437
|
+
const sx = point.x * t.scale.x;
|
|
438
|
+
const sy = point.y * t.scale.y;
|
|
439
|
+
return {
|
|
440
|
+
x: sx * c - sy * s + t.position.x,
|
|
441
|
+
y: sx * s + sy * c + t.position.y
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
/** Transforms a world-space point to local-space. */
|
|
445
|
+
worldToLocal(t, point) {
|
|
446
|
+
const dx = point.x - t.position.x;
|
|
447
|
+
const dy = point.y - t.position.y;
|
|
448
|
+
const c = Math.cos(-t.rotation);
|
|
449
|
+
const s = Math.sin(-t.rotation);
|
|
450
|
+
const rx = dx * c - dy * s;
|
|
451
|
+
const ry = dx * s + dy * c;
|
|
452
|
+
return {
|
|
453
|
+
x: t.scale.x !== 0 ? rx / t.scale.x : 0,
|
|
454
|
+
y: t.scale.y !== 0 ? ry / t.scale.y : 0
|
|
455
|
+
};
|
|
456
|
+
},
|
|
457
|
+
/** Returns a copy of the transform. */
|
|
458
|
+
clone(t) {
|
|
459
|
+
return {
|
|
460
|
+
position: { x: t.position.x, y: t.position.y },
|
|
461
|
+
rotation: t.rotation,
|
|
462
|
+
scale: { x: t.scale.x, y: t.scale.y }
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// src/mat3.ts
|
|
468
|
+
var Mat3 = {
|
|
469
|
+
/** Creates a new identity matrix. */
|
|
470
|
+
create() {
|
|
471
|
+
const m = new Float32Array(9);
|
|
472
|
+
m[0] = 1;
|
|
473
|
+
m[4] = 1;
|
|
474
|
+
m[8] = 1;
|
|
475
|
+
return m;
|
|
476
|
+
},
|
|
477
|
+
/** Sets m to identity. */
|
|
478
|
+
identity(m) {
|
|
479
|
+
m[0] = 1;
|
|
480
|
+
m[1] = 0;
|
|
481
|
+
m[2] = 0;
|
|
482
|
+
m[3] = 0;
|
|
483
|
+
m[4] = 1;
|
|
484
|
+
m[5] = 0;
|
|
485
|
+
m[6] = 0;
|
|
486
|
+
m[7] = 0;
|
|
487
|
+
m[8] = 1;
|
|
488
|
+
return m;
|
|
489
|
+
},
|
|
490
|
+
/** Multiplies a * b, writes into out (or allocates). */
|
|
491
|
+
multiply(a, b, out) {
|
|
492
|
+
const a00 = a[0], a01 = a[3], a02 = a[6];
|
|
493
|
+
const a10 = a[1], a11 = a[4], a12 = a[7];
|
|
494
|
+
const a20 = a[2], a21 = a[5], a22 = a[8];
|
|
495
|
+
const b00 = b[0], b01 = b[3], b02 = b[6];
|
|
496
|
+
const b10 = b[1], b11 = b[4], b12 = b[7];
|
|
497
|
+
const b20 = b[2], b21 = b[5], b22 = b[8];
|
|
498
|
+
const o = out ?? new Float32Array(9);
|
|
499
|
+
o[0] = a00 * b00 + a01 * b10 + a02 * b20;
|
|
500
|
+
o[1] = a10 * b00 + a11 * b10 + a12 * b20;
|
|
501
|
+
o[2] = a20 * b00 + a21 * b10 + a22 * b20;
|
|
502
|
+
o[3] = a00 * b01 + a01 * b11 + a02 * b21;
|
|
503
|
+
o[4] = a10 * b01 + a11 * b11 + a12 * b21;
|
|
504
|
+
o[5] = a20 * b01 + a21 * b11 + a22 * b21;
|
|
505
|
+
o[6] = a00 * b02 + a01 * b12 + a02 * b22;
|
|
506
|
+
o[7] = a10 * b02 + a11 * b12 + a12 * b22;
|
|
507
|
+
o[8] = a20 * b02 + a21 * b12 + a22 * b22;
|
|
508
|
+
return o;
|
|
509
|
+
},
|
|
510
|
+
/** Creates a translation matrix. */
|
|
511
|
+
translate(tx, ty, out) {
|
|
512
|
+
const m = out ?? new Float32Array(9);
|
|
513
|
+
m[0] = 1;
|
|
514
|
+
m[1] = 0;
|
|
515
|
+
m[2] = 0;
|
|
516
|
+
m[3] = 0;
|
|
517
|
+
m[4] = 1;
|
|
518
|
+
m[5] = 0;
|
|
519
|
+
m[6] = tx;
|
|
520
|
+
m[7] = ty;
|
|
521
|
+
m[8] = 1;
|
|
522
|
+
return m;
|
|
523
|
+
},
|
|
524
|
+
/** Creates a rotation matrix (radians). */
|
|
525
|
+
rotate(angle, out) {
|
|
526
|
+
const c = Math.cos(angle);
|
|
527
|
+
const s = Math.sin(angle);
|
|
528
|
+
const m = out ?? new Float32Array(9);
|
|
529
|
+
m[0] = c;
|
|
530
|
+
m[1] = s;
|
|
531
|
+
m[2] = 0;
|
|
532
|
+
m[3] = -s;
|
|
533
|
+
m[4] = c;
|
|
534
|
+
m[5] = 0;
|
|
535
|
+
m[6] = 0;
|
|
536
|
+
m[7] = 0;
|
|
537
|
+
m[8] = 1;
|
|
538
|
+
return m;
|
|
539
|
+
},
|
|
540
|
+
/** Creates a scale matrix. */
|
|
541
|
+
scale(sx, sy, out) {
|
|
542
|
+
const m = out ?? new Float32Array(9);
|
|
543
|
+
m[0] = sx;
|
|
544
|
+
m[1] = 0;
|
|
545
|
+
m[2] = 0;
|
|
546
|
+
m[3] = 0;
|
|
547
|
+
m[4] = sy;
|
|
548
|
+
m[5] = 0;
|
|
549
|
+
m[6] = 0;
|
|
550
|
+
m[7] = 0;
|
|
551
|
+
m[8] = 1;
|
|
552
|
+
return m;
|
|
553
|
+
},
|
|
554
|
+
/** Inverts the matrix. Returns null if singular. */
|
|
555
|
+
invert(m, out) {
|
|
556
|
+
const a00 = m[0], a01 = m[3], a02 = m[6];
|
|
557
|
+
const a10 = m[1], a11 = m[4], a12 = m[7];
|
|
558
|
+
const a20 = m[2], a21 = m[5], a22 = m[8];
|
|
559
|
+
const det = a00 * (a11 * a22 - a12 * a21) - a01 * (a10 * a22 - a12 * a20) + a02 * (a10 * a21 - a11 * a20);
|
|
560
|
+
if (Math.abs(det) < 1e-8) return null;
|
|
561
|
+
const invDet = 1 / det;
|
|
562
|
+
const o = out ?? new Float32Array(9);
|
|
563
|
+
o[0] = (a11 * a22 - a12 * a21) * invDet;
|
|
564
|
+
o[1] = (a12 * a20 - a10 * a22) * invDet;
|
|
565
|
+
o[2] = (a10 * a21 - a11 * a20) * invDet;
|
|
566
|
+
o[3] = (a02 * a21 - a01 * a22) * invDet;
|
|
567
|
+
o[4] = (a00 * a22 - a02 * a20) * invDet;
|
|
568
|
+
o[5] = (a01 * a20 - a00 * a21) * invDet;
|
|
569
|
+
o[6] = (a01 * a12 - a02 * a11) * invDet;
|
|
570
|
+
o[7] = (a02 * a10 - a00 * a12) * invDet;
|
|
571
|
+
o[8] = (a00 * a11 - a01 * a10) * invDet;
|
|
572
|
+
return o;
|
|
573
|
+
},
|
|
574
|
+
/** Builds a matrix from a Transform2D (TRS order: translate * rotate * scale). */
|
|
575
|
+
fromTransform(t, out) {
|
|
576
|
+
const c = Math.cos(t.rotation);
|
|
577
|
+
const s = Math.sin(t.rotation);
|
|
578
|
+
const sx = t.scale.x;
|
|
579
|
+
const sy = t.scale.y;
|
|
580
|
+
const m = out ?? new Float32Array(9);
|
|
581
|
+
m[0] = c * sx;
|
|
582
|
+
m[1] = s * sx;
|
|
583
|
+
m[2] = 0;
|
|
584
|
+
m[3] = -s * sy;
|
|
585
|
+
m[4] = c * sy;
|
|
586
|
+
m[5] = 0;
|
|
587
|
+
m[6] = t.position.x;
|
|
588
|
+
m[7] = t.position.y;
|
|
589
|
+
m[8] = 1;
|
|
590
|
+
return m;
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
// src/color.ts
|
|
595
|
+
function srgbToLinear(c) {
|
|
596
|
+
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
597
|
+
}
|
|
598
|
+
function linearToSrgb(c) {
|
|
599
|
+
return c <= 31308e-7 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;
|
|
600
|
+
}
|
|
601
|
+
var Color = {
|
|
602
|
+
WHITE: { r: 1, g: 1, b: 1, a: 1 },
|
|
603
|
+
BLACK: { r: 0, g: 0, b: 0, a: 1 },
|
|
604
|
+
TRANSPARENT: { r: 0, g: 0, b: 0, a: 0 },
|
|
605
|
+
/** Creates a Color from normalized 0-1 components. */
|
|
606
|
+
create(r = 0, g = 0, b = 0, a = 1) {
|
|
607
|
+
return { r, g, b, a };
|
|
608
|
+
},
|
|
609
|
+
/** Parses a hex string (#RGB, #RGBA, #RRGGBB, #RRGGBBAA). */
|
|
610
|
+
fromHex(hex) {
|
|
611
|
+
let h = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
612
|
+
if (h.length === 3) {
|
|
613
|
+
h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
614
|
+
} else if (h.length === 4) {
|
|
615
|
+
h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
|
|
616
|
+
}
|
|
617
|
+
const r = Number.parseInt(h.slice(0, 2), 16) / 255;
|
|
618
|
+
const g = Number.parseInt(h.slice(2, 4), 16) / 255;
|
|
619
|
+
const b = Number.parseInt(h.slice(4, 6), 16) / 255;
|
|
620
|
+
const a = h.length >= 8 ? Number.parseInt(h.slice(6, 8), 16) / 255 : 1;
|
|
621
|
+
return { r, g, b, a };
|
|
622
|
+
},
|
|
623
|
+
/** Converts to hex string #RRGGBB or #RRGGBBAA if alpha < 1. */
|
|
624
|
+
toHex(c) {
|
|
625
|
+
const r = Math.round(clamp(c.r, 0, 1) * 255).toString(16).padStart(2, "0");
|
|
626
|
+
const g = Math.round(clamp(c.g, 0, 1) * 255).toString(16).padStart(2, "0");
|
|
627
|
+
const b = Math.round(clamp(c.b, 0, 1) * 255).toString(16).padStart(2, "0");
|
|
628
|
+
if (c.a < 1) {
|
|
629
|
+
const a = Math.round(clamp(c.a, 0, 1) * 255).toString(16).padStart(2, "0");
|
|
630
|
+
return `#${r}${g}${b}${a}`;
|
|
631
|
+
}
|
|
632
|
+
return `#${r}${g}${b}`;
|
|
633
|
+
},
|
|
634
|
+
/** Linearly interpolates between two colors. */
|
|
635
|
+
lerp(a, b, t) {
|
|
636
|
+
return {
|
|
637
|
+
r: a.r + (b.r - a.r) * t,
|
|
638
|
+
g: a.g + (b.g - a.g) * t,
|
|
639
|
+
b: a.b + (b.b - a.b) * t,
|
|
640
|
+
a: a.a + (b.a - a.a) * t
|
|
641
|
+
};
|
|
642
|
+
},
|
|
643
|
+
/** Component-wise multiplication. */
|
|
644
|
+
multiply(a, b) {
|
|
645
|
+
return {
|
|
646
|
+
r: a.r * b.r,
|
|
647
|
+
g: a.g * b.g,
|
|
648
|
+
b: a.b * b.b,
|
|
649
|
+
a: a.a * b.a
|
|
650
|
+
};
|
|
651
|
+
},
|
|
652
|
+
/**
|
|
653
|
+
* Converts to a Skia-compatible color number (0xAARRGGBB).
|
|
654
|
+
* Compatible with @shopify/react-native-skia Skia.Color() format.
|
|
655
|
+
*/
|
|
656
|
+
toSkColor(c) {
|
|
657
|
+
const r = Math.round(clamp(c.r, 0, 1) * 255) & 255;
|
|
658
|
+
const g = Math.round(clamp(c.g, 0, 1) * 255) & 255;
|
|
659
|
+
const b = Math.round(clamp(c.b, 0, 1) * 255) & 255;
|
|
660
|
+
const a = Math.round(clamp(c.a, 0, 1) * 255) & 255;
|
|
661
|
+
return (a << 24 | r << 16 | g << 8 | b) >>> 0;
|
|
662
|
+
},
|
|
663
|
+
/** Converts sRGB Color to OKLab. Alpha is dropped. */
|
|
664
|
+
toOklab(c) {
|
|
665
|
+
const rl = srgbToLinear(c.r);
|
|
666
|
+
const gl = srgbToLinear(c.g);
|
|
667
|
+
const bl = srgbToLinear(c.b);
|
|
668
|
+
const l = 0.4122214708 * rl + 0.5363325363 * gl + 0.0514459929 * bl;
|
|
669
|
+
const m = 0.2119034982 * rl + 0.6806995451 * gl + 0.1073969566 * bl;
|
|
670
|
+
const s = 0.0883024619 * rl + 0.2817188376 * gl + 0.6299787005 * bl;
|
|
671
|
+
const l_ = Math.cbrt(l);
|
|
672
|
+
const m_ = Math.cbrt(m);
|
|
673
|
+
const s_ = Math.cbrt(s);
|
|
674
|
+
return {
|
|
675
|
+
L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
676
|
+
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
677
|
+
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_
|
|
678
|
+
};
|
|
679
|
+
},
|
|
680
|
+
/**
|
|
681
|
+
* Converts OKLab to sRGB Color. Out-of-gamut results are clamped to [0,1];
|
|
682
|
+
* round-trips are exact only for in-gamut colors.
|
|
683
|
+
*/
|
|
684
|
+
fromOklab(lab, alpha = 1) {
|
|
685
|
+
const l_ = lab.L + 0.3963377774 * lab.a + 0.2158037573 * lab.b;
|
|
686
|
+
const m_ = lab.L - 0.1055613458 * lab.a - 0.0638541728 * lab.b;
|
|
687
|
+
const s_ = lab.L - 0.0894841775 * lab.a - 1.291485548 * lab.b;
|
|
688
|
+
const l = l_ ** 3;
|
|
689
|
+
const m = m_ ** 3;
|
|
690
|
+
const s = s_ ** 3;
|
|
691
|
+
const rl = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
|
|
692
|
+
const gl = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
|
|
693
|
+
const bl = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
|
|
694
|
+
return {
|
|
695
|
+
r: clamp(linearToSrgb(rl), 0, 1),
|
|
696
|
+
g: clamp(linearToSrgb(gl), 0, 1),
|
|
697
|
+
b: clamp(linearToSrgb(bl), 0, 1),
|
|
698
|
+
a: alpha
|
|
699
|
+
};
|
|
700
|
+
},
|
|
701
|
+
/** Converts sRGB Color to OKLCH (polar OKLab). Achromatic colors get h = 0. */
|
|
702
|
+
toOklch(c) {
|
|
703
|
+
const lab = Color.toOklab(c);
|
|
704
|
+
const C = Math.hypot(lab.a, lab.b);
|
|
705
|
+
const h = C < 1e-7 ? 0 : (Math.atan2(lab.b, lab.a) * 180 / Math.PI + 360) % 360;
|
|
706
|
+
return { L: lab.L, C, h };
|
|
707
|
+
},
|
|
708
|
+
/**
|
|
709
|
+
* Converts OKLCH to sRGB Color. Hue is wrapped via ((h%360)+360)%360.
|
|
710
|
+
* Out-of-gamut results are clamped; round-trips exact only in-gamut.
|
|
711
|
+
*/
|
|
712
|
+
fromOklch(lch, alpha = 1) {
|
|
713
|
+
const hWrapped = (lch.h % 360 + 360) % 360;
|
|
714
|
+
const hRad = hWrapped * Math.PI / 180;
|
|
715
|
+
return Color.fromOklab(
|
|
716
|
+
{ L: lch.L, a: lch.C * Math.cos(hRad), b: lch.C * Math.sin(hRad) },
|
|
717
|
+
alpha
|
|
718
|
+
);
|
|
719
|
+
},
|
|
720
|
+
/** Euclidean distance in OKLab space between two sRGB colors. */
|
|
721
|
+
deltaEOk(a, b) {
|
|
722
|
+
return Color.deltaEOkLab(Color.toOklab(a), Color.toOklab(b));
|
|
723
|
+
},
|
|
724
|
+
/** Euclidean distance between two OKLab values. */
|
|
725
|
+
deltaEOkLab(a, b) {
|
|
726
|
+
return Math.hypot(a.L - b.L, a.a - b.a, a.b - b.b);
|
|
727
|
+
},
|
|
728
|
+
/** WCAG 2.x relative luminance. White = 1, black = 0. */
|
|
729
|
+
relativeLuminance(c) {
|
|
730
|
+
return 0.2126 * srgbToLinear(c.r) + 0.7152 * srgbToLinear(c.g) + 0.0722 * srgbToLinear(c.b);
|
|
731
|
+
},
|
|
732
|
+
/** WCAG 2.x contrast ratio. Order-independent; range [1, 21]. */
|
|
733
|
+
contrastRatio(fg, bg) {
|
|
734
|
+
const l1 = Color.relativeLuminance(fg);
|
|
735
|
+
const l2 = Color.relativeLuminance(bg);
|
|
736
|
+
const lMax = Math.max(l1, l2);
|
|
737
|
+
const lMin = Math.min(l1, l2);
|
|
738
|
+
return (lMax + 0.05) / (lMin + 0.05);
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
// src/easings.ts
|
|
743
|
+
var PI = Math.PI;
|
|
744
|
+
var HALF_PI = PI / 2;
|
|
745
|
+
var TAU = PI * 2;
|
|
746
|
+
function linear(t) {
|
|
747
|
+
return t;
|
|
748
|
+
}
|
|
749
|
+
function step(t) {
|
|
750
|
+
return t < 1 ? 0 : 1;
|
|
751
|
+
}
|
|
752
|
+
function easeInQuad(t) {
|
|
753
|
+
return t * t;
|
|
754
|
+
}
|
|
755
|
+
function easeOutQuad(t) {
|
|
756
|
+
return t * (2 - t);
|
|
757
|
+
}
|
|
758
|
+
function easeInOutQuad(t) {
|
|
759
|
+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
760
|
+
}
|
|
761
|
+
function easeInCubic(t) {
|
|
762
|
+
return t * t * t;
|
|
763
|
+
}
|
|
764
|
+
function easeOutCubic(t) {
|
|
765
|
+
const t1 = t - 1;
|
|
766
|
+
return t1 * t1 * t1 + 1;
|
|
767
|
+
}
|
|
768
|
+
function easeInOutCubic(t) {
|
|
769
|
+
return t < 0.5 ? 4 * t * t * t : 1 + (t - 1) * (2 * t - 2) * (2 * t - 2);
|
|
770
|
+
}
|
|
771
|
+
function easeInQuart(t) {
|
|
772
|
+
return t * t * t * t;
|
|
773
|
+
}
|
|
774
|
+
function easeOutQuart(t) {
|
|
775
|
+
const t1 = t - 1;
|
|
776
|
+
return 1 - t1 * t1 * t1 * t1;
|
|
777
|
+
}
|
|
778
|
+
function easeInOutQuart(t) {
|
|
779
|
+
const t1 = t - 1;
|
|
780
|
+
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * t1 * t1 * t1 * t1;
|
|
781
|
+
}
|
|
782
|
+
function easeInQuint(t) {
|
|
783
|
+
return t * t * t * t * t;
|
|
784
|
+
}
|
|
785
|
+
function easeOutQuint(t) {
|
|
786
|
+
const t1 = t - 1;
|
|
787
|
+
return 1 + t1 * t1 * t1 * t1 * t1;
|
|
788
|
+
}
|
|
789
|
+
function easeInOutQuint(t) {
|
|
790
|
+
const t1 = t - 1;
|
|
791
|
+
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * t1 * t1 * t1 * t1 * t1;
|
|
792
|
+
}
|
|
793
|
+
function easeInSine(t) {
|
|
794
|
+
return 1 - Math.cos(t * HALF_PI);
|
|
795
|
+
}
|
|
796
|
+
function easeOutSine(t) {
|
|
797
|
+
return Math.sin(t * HALF_PI);
|
|
798
|
+
}
|
|
799
|
+
function easeInOutSine(t) {
|
|
800
|
+
return 0.5 * (1 - Math.cos(PI * t));
|
|
801
|
+
}
|
|
802
|
+
function easeInExpo(t) {
|
|
803
|
+
return t === 0 ? 0 : 2 ** (10 * (t - 1));
|
|
804
|
+
}
|
|
805
|
+
function easeOutExpo(t) {
|
|
806
|
+
return t === 1 ? 1 : 1 - 2 ** (-10 * t);
|
|
807
|
+
}
|
|
808
|
+
function easeInOutExpo(t) {
|
|
809
|
+
if (t === 0) return 0;
|
|
810
|
+
if (t === 1) return 1;
|
|
811
|
+
return t < 0.5 ? 0.5 * 2 ** (20 * t - 10) : 1 - 0.5 * 2 ** (-20 * t + 10);
|
|
812
|
+
}
|
|
813
|
+
function easeInCirc(t) {
|
|
814
|
+
return 1 - Math.sqrt(1 - t * t);
|
|
815
|
+
}
|
|
816
|
+
function easeOutCirc(t) {
|
|
817
|
+
const t1 = t - 1;
|
|
818
|
+
return Math.sqrt(1 - t1 * t1);
|
|
819
|
+
}
|
|
820
|
+
function easeInOutCirc(t) {
|
|
821
|
+
return t < 0.5 ? 0.5 * (1 - Math.sqrt(1 - 4 * t * t)) : 0.5 * (Math.sqrt(1 - (2 * t - 2) * (2 * t - 2)) + 1);
|
|
822
|
+
}
|
|
823
|
+
var S = 1.70158;
|
|
824
|
+
var S2 = S * 1.525;
|
|
825
|
+
function easeInBack(t) {
|
|
826
|
+
return t * t * ((S + 1) * t - S);
|
|
827
|
+
}
|
|
828
|
+
function easeOutBack(t) {
|
|
829
|
+
const t1 = t - 1;
|
|
830
|
+
return t1 * t1 * ((S + 1) * t1 + S) + 1;
|
|
831
|
+
}
|
|
832
|
+
function easeInOutBack(t) {
|
|
833
|
+
if (t < 0.5) {
|
|
834
|
+
const t22 = 2 * t;
|
|
835
|
+
return 0.5 * (t22 * t22 * ((S2 + 1) * t22 - S2));
|
|
836
|
+
}
|
|
837
|
+
const t2 = 2 * t - 2;
|
|
838
|
+
return 0.5 * (t2 * t2 * ((S2 + 1) * t2 + S2) + 2);
|
|
839
|
+
}
|
|
840
|
+
function easeInElastic(t) {
|
|
841
|
+
if (t === 0 || t === 1) return t;
|
|
842
|
+
return -(2 ** (10 * t - 10)) * Math.sin((t * 10 - 10.75) * (TAU / 3));
|
|
843
|
+
}
|
|
844
|
+
function easeOutElastic(t) {
|
|
845
|
+
if (t === 0 || t === 1) return t;
|
|
846
|
+
return 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * (TAU / 3)) + 1;
|
|
847
|
+
}
|
|
848
|
+
function easeInOutElastic(t) {
|
|
849
|
+
if (t === 0 || t === 1) return t;
|
|
850
|
+
const p = TAU / 4.5;
|
|
851
|
+
return t < 0.5 ? -0.5 * 2 ** (20 * t - 10) * Math.sin((20 * t - 11.125) * p) : 0.5 * 2 ** (-20 * t + 10) * Math.sin((20 * t - 11.125) * p) + 1;
|
|
852
|
+
}
|
|
853
|
+
function easeOutBounce(t) {
|
|
854
|
+
if (t < 1 / 2.75) {
|
|
855
|
+
return 7.5625 * t * t;
|
|
856
|
+
}
|
|
857
|
+
if (t < 2 / 2.75) {
|
|
858
|
+
const t22 = t - 1.5 / 2.75;
|
|
859
|
+
return 7.5625 * t22 * t22 + 0.75;
|
|
860
|
+
}
|
|
861
|
+
if (t < 2.5 / 2.75) {
|
|
862
|
+
const t22 = t - 2.25 / 2.75;
|
|
863
|
+
return 7.5625 * t22 * t22 + 0.9375;
|
|
864
|
+
}
|
|
865
|
+
const t2 = t - 2.625 / 2.75;
|
|
866
|
+
return 7.5625 * t2 * t2 + 0.984375;
|
|
867
|
+
}
|
|
868
|
+
function easeInBounce(t) {
|
|
869
|
+
return 1 - easeOutBounce(1 - t);
|
|
870
|
+
}
|
|
871
|
+
function easeInOutBounce(t) {
|
|
872
|
+
return t < 0.5 ? 0.5 * easeInBounce(t * 2) : 0.5 * easeOutBounce(t * 2 - 1) + 0.5;
|
|
873
|
+
}
|
|
874
|
+
function springIn(t) {
|
|
875
|
+
return t * t * ((1.70158 + 1) * t - 1.70158);
|
|
876
|
+
}
|
|
877
|
+
function springOut(t) {
|
|
878
|
+
const t1 = t - 1;
|
|
879
|
+
return t1 * t1 * ((1.70158 + 1) * t1 + 1.70158) + 1;
|
|
880
|
+
}
|
|
881
|
+
function springInOut(t) {
|
|
882
|
+
if (t < 0.5) {
|
|
883
|
+
const t22 = 2 * t;
|
|
884
|
+
return 0.5 * t22 * t22 * ((S2 + 1) * t22 - S2);
|
|
885
|
+
}
|
|
886
|
+
const t2 = 2 * t - 2;
|
|
887
|
+
return 0.5 * (t2 * t2 * ((S2 + 1) * t2 + S2) + 2);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// src/random.ts
|
|
891
|
+
var SeededRNG = class {
|
|
892
|
+
state;
|
|
893
|
+
constructor(seed) {
|
|
894
|
+
this.state = seed | 0;
|
|
895
|
+
}
|
|
896
|
+
/** Returns a float in [0, 1). */
|
|
897
|
+
next() {
|
|
898
|
+
this.state = this.state + 1831565813 | 0;
|
|
899
|
+
let t = Math.imul(this.state ^ this.state >>> 15, 1 | this.state);
|
|
900
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
901
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
902
|
+
}
|
|
903
|
+
/** Returns a float in [min, max). */
|
|
904
|
+
float(min, max) {
|
|
905
|
+
return min + this.next() * (max - min);
|
|
906
|
+
}
|
|
907
|
+
/** Returns an integer in [min, max] (inclusive). */
|
|
908
|
+
int(min, max) {
|
|
909
|
+
return Math.floor(this.float(min, max + 1));
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
function randomFloat(min, max) {
|
|
913
|
+
return min + Math.random() * (max - min);
|
|
914
|
+
}
|
|
915
|
+
function randomInt(min, max) {
|
|
916
|
+
return Math.floor(randomFloat(min, max + 1));
|
|
917
|
+
}
|
|
918
|
+
function randomVec2InRect(r) {
|
|
919
|
+
return {
|
|
920
|
+
x: r.x + Math.random() * r.width,
|
|
921
|
+
y: r.y + Math.random() * r.height
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
function randomPointInCircle(cx, cy, radius) {
|
|
925
|
+
const r = radius * Math.sqrt(Math.random());
|
|
926
|
+
const angle = Math.random() * Math.PI * 2;
|
|
927
|
+
return {
|
|
928
|
+
x: cx + r * Math.cos(angle),
|
|
929
|
+
y: cy + r * Math.sin(angle)
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
function shuffle(array) {
|
|
933
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
934
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
935
|
+
const tmp = array[i];
|
|
936
|
+
array[i] = array[j];
|
|
937
|
+
array[j] = tmp;
|
|
938
|
+
}
|
|
939
|
+
return array;
|
|
940
|
+
}
|
|
941
|
+
function choose(array) {
|
|
942
|
+
if (array.length === 0) return void 0;
|
|
943
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// src/intersection.ts
|
|
947
|
+
function pointInRect(p, r) {
|
|
948
|
+
return p.x >= r.x && p.x <= r.x + r.width && p.y >= r.y && p.y <= r.y + r.height;
|
|
949
|
+
}
|
|
950
|
+
function pointInCircle(p, c) {
|
|
951
|
+
const dx = p.x - c.x;
|
|
952
|
+
const dy = p.y - c.y;
|
|
953
|
+
return dx * dx + dy * dy <= c.radius * c.radius;
|
|
954
|
+
}
|
|
955
|
+
function rectVsRect(a, b) {
|
|
956
|
+
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
|
957
|
+
}
|
|
958
|
+
function rectVsCircle(r, c) {
|
|
959
|
+
const closestX = c.x < r.x ? r.x : c.x > r.x + r.width ? r.x + r.width : c.x;
|
|
960
|
+
const closestY = c.y < r.y ? r.y : c.y > r.y + r.height ? r.y + r.height : c.y;
|
|
961
|
+
const dx = c.x - closestX;
|
|
962
|
+
const dy = c.y - closestY;
|
|
963
|
+
return dx * dx + dy * dy <= c.radius * c.radius;
|
|
964
|
+
}
|
|
965
|
+
function circleVsCircle(a, b) {
|
|
966
|
+
const dx = b.x - a.x;
|
|
967
|
+
const dy = b.y - a.y;
|
|
968
|
+
const radSum = a.radius + b.radius;
|
|
969
|
+
return dx * dx + dy * dy < radSum * radSum;
|
|
970
|
+
}
|
|
971
|
+
function lineVsRect(x1, y1, x2, y2, r) {
|
|
972
|
+
const dx = x2 - x1;
|
|
973
|
+
const dy = y2 - y1;
|
|
974
|
+
let tMin = 0;
|
|
975
|
+
let tMax = 1;
|
|
976
|
+
const edges = [
|
|
977
|
+
{ p: -dx, q: x1 - r.x },
|
|
978
|
+
{ p: dx, q: r.x + r.width - x1 },
|
|
979
|
+
{ p: -dy, q: y1 - r.y },
|
|
980
|
+
{ p: dy, q: r.y + r.height - y1 }
|
|
981
|
+
];
|
|
982
|
+
for (const { p, q } of edges) {
|
|
983
|
+
if (Math.abs(p) < 1e-12) {
|
|
984
|
+
if (q < 0) return false;
|
|
985
|
+
} else {
|
|
986
|
+
const t = q / p;
|
|
987
|
+
if (p < 0) {
|
|
988
|
+
if (t > tMax) return false;
|
|
989
|
+
if (t > tMin) tMin = t;
|
|
990
|
+
} else {
|
|
991
|
+
if (t < tMin) return false;
|
|
992
|
+
if (t < tMax) tMax = t;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return tMin <= tMax;
|
|
997
|
+
}
|
|
998
|
+
function lineVsCircle(x1, y1, x2, y2, c) {
|
|
999
|
+
const dx = x2 - x1;
|
|
1000
|
+
const dy = y2 - y1;
|
|
1001
|
+
const fx = x1 - c.x;
|
|
1002
|
+
const fy = y1 - c.y;
|
|
1003
|
+
const a = dx * dx + dy * dy;
|
|
1004
|
+
const b = 2 * (fx * dx + fy * dy);
|
|
1005
|
+
const cc = fx * fx + fy * fy - c.radius * c.radius;
|
|
1006
|
+
if (a < 1e-12) {
|
|
1007
|
+
return cc <= 0;
|
|
1008
|
+
}
|
|
1009
|
+
let discriminant = b * b - 4 * a * cc;
|
|
1010
|
+
if (discriminant < 0) return false;
|
|
1011
|
+
discriminant = Math.sqrt(discriminant);
|
|
1012
|
+
const t1 = (-b - discriminant) / (2 * a);
|
|
1013
|
+
const t2 = (-b + discriminant) / (2 * a);
|
|
1014
|
+
if (t1 >= 0 && t1 <= 1) return true;
|
|
1015
|
+
if (t2 >= 0 && t2 <= 1) return true;
|
|
1016
|
+
if (t1 < 0 && t2 > 1) return true;
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
function rayVsRect(originX, originY, dirX, dirY, r) {
|
|
1020
|
+
const invDx = dirX !== 0 ? 1 / dirX : Number.POSITIVE_INFINITY;
|
|
1021
|
+
const invDy = dirY !== 0 ? 1 / dirY : Number.POSITIVE_INFINITY;
|
|
1022
|
+
const tx1 = (r.x - originX) * invDx;
|
|
1023
|
+
const tx2 = (r.x + r.width - originX) * invDx;
|
|
1024
|
+
const ty1 = (r.y - originY) * invDy;
|
|
1025
|
+
const ty2 = (r.y + r.height - originY) * invDy;
|
|
1026
|
+
const tMin = Math.max(Math.min(tx1, tx2), Math.min(ty1, ty2));
|
|
1027
|
+
const tMax = Math.min(Math.max(tx1, tx2), Math.max(ty1, ty2));
|
|
1028
|
+
if (tMax < 0 || tMin > tMax) return null;
|
|
1029
|
+
return tMin >= 0 ? tMin : tMax;
|
|
1030
|
+
}
|
|
1031
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1032
|
+
0 && (module.exports = {
|
|
1033
|
+
Circle,
|
|
1034
|
+
Color,
|
|
1035
|
+
Mat3,
|
|
1036
|
+
Rect,
|
|
1037
|
+
SeededRNG,
|
|
1038
|
+
Transform2D,
|
|
1039
|
+
Vec2,
|
|
1040
|
+
approxEquals,
|
|
1041
|
+
choose,
|
|
1042
|
+
circleVsCircle,
|
|
1043
|
+
clamp,
|
|
1044
|
+
degToRad,
|
|
1045
|
+
easeInBack,
|
|
1046
|
+
easeInBounce,
|
|
1047
|
+
easeInCirc,
|
|
1048
|
+
easeInCubic,
|
|
1049
|
+
easeInElastic,
|
|
1050
|
+
easeInExpo,
|
|
1051
|
+
easeInOutBack,
|
|
1052
|
+
easeInOutBounce,
|
|
1053
|
+
easeInOutCirc,
|
|
1054
|
+
easeInOutCubic,
|
|
1055
|
+
easeInOutElastic,
|
|
1056
|
+
easeInOutExpo,
|
|
1057
|
+
easeInOutQuad,
|
|
1058
|
+
easeInOutQuart,
|
|
1059
|
+
easeInOutQuint,
|
|
1060
|
+
easeInOutSine,
|
|
1061
|
+
easeInQuad,
|
|
1062
|
+
easeInQuart,
|
|
1063
|
+
easeInQuint,
|
|
1064
|
+
easeInSine,
|
|
1065
|
+
easeOutBack,
|
|
1066
|
+
easeOutBounce,
|
|
1067
|
+
easeOutCirc,
|
|
1068
|
+
easeOutCubic,
|
|
1069
|
+
easeOutElastic,
|
|
1070
|
+
easeOutExpo,
|
|
1071
|
+
easeOutQuad,
|
|
1072
|
+
easeOutQuart,
|
|
1073
|
+
easeOutQuint,
|
|
1074
|
+
easeOutSine,
|
|
1075
|
+
inverseLerp,
|
|
1076
|
+
lerp,
|
|
1077
|
+
lineVsCircle,
|
|
1078
|
+
lineVsRect,
|
|
1079
|
+
linear,
|
|
1080
|
+
map,
|
|
1081
|
+
pingPong,
|
|
1082
|
+
pointInCircle,
|
|
1083
|
+
pointInRect,
|
|
1084
|
+
radToDeg,
|
|
1085
|
+
randomFloat,
|
|
1086
|
+
randomInt,
|
|
1087
|
+
randomPointInCircle,
|
|
1088
|
+
randomVec2InRect,
|
|
1089
|
+
rayVsRect,
|
|
1090
|
+
rectVsCircle,
|
|
1091
|
+
rectVsRect,
|
|
1092
|
+
shuffle,
|
|
1093
|
+
sign,
|
|
1094
|
+
smoothStep,
|
|
1095
|
+
springIn,
|
|
1096
|
+
springInOut,
|
|
1097
|
+
springOut,
|
|
1098
|
+
step,
|
|
1099
|
+
vec2,
|
|
1100
|
+
wrap
|
|
1101
|
+
});
|
|
1102
|
+
//# sourceMappingURL=index.js.map
|