@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Grzegorz Otto
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.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @flare-engine/math
2
+
3
+ 2D math primitives for the Flare engine — `Vec2`, `Rect`, `Circle`, `Transform2D`, `Mat3`, `Color`, 32 easing functions, seeded RNG, and intersection tests. Plain-object types with static method namespaces; zero-alloc forms take an `out` parameter to avoid GC pressure in game loops.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ bun add @flare-engine/math
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { vec2, Vec2, Rect, easeOutQuad, SeededRNG } from '@flare-engine/math';
15
+
16
+ const a = vec2(0, 0);
17
+ const b = vec2(10, 0);
18
+ const out = vec2(0, 0);
19
+ Vec2.lerp(a, b, 0.5, out);
20
+
21
+ const rng = new SeededRNG(42);
22
+ const t = easeOutQuad(rng.float());
23
+ ```
24
+
25
+ See [API spec](../../docs/design/api-specs.md#flare-enginemath--5kb-gzip) and [skill reference](../../.github/skills/flare-math/SKILL.md).
26
+
27
+ ## License
28
+
29
+ MIT
@@ -0,0 +1,308 @@
1
+ /** Clamps value between min and max. */
2
+ declare function clamp(value: number, min: number, max: number): number;
3
+ /** Linearly interpolates between a and b by t (unclamped). */
4
+ declare function lerp(a: number, b: number, t: number): number;
5
+ /** Returns the interpolation factor of value between a and b. */
6
+ declare function inverseLerp(a: number, b: number, value: number): number;
7
+ /** Maps value from [inMin, inMax] to [outMin, outMax]. */
8
+ declare function map(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number;
9
+ /** Converts degrees to radians. */
10
+ declare function degToRad(degrees: number): number;
11
+ /** Converts radians to degrees. */
12
+ declare function radToDeg(radians: number): number;
13
+ /** Returns true if a and b are approximately equal within epsilon. */
14
+ declare function approxEquals(a: number, b: number, epsilon?: number): boolean;
15
+ /** Wraps value into [min, max) range. */
16
+ declare function wrap(value: number, min: number, max: number): number;
17
+ /** PingPong — bounces value back and forth in [0, length]. */
18
+ declare function pingPong(t: number, length: number): number;
19
+ /** Hermite smooth interpolation (0→1) with zero first-derivative at edges. */
20
+ declare function smoothStep(edge0: number, edge1: number, x: number): number;
21
+ /** Returns -1, 0, or 1. Unlike Math.sign, returns 0 for NaN. */
22
+ declare function sign(value: number): number;
23
+
24
+ /** Creates a Vec2 plain object. */
25
+ declare function vec2(x?: number, y?: number): Vec2;
26
+ /** Vec2 plain object type — no class, no GC pressure. */
27
+ type Vec2 = {
28
+ x: number;
29
+ y: number;
30
+ };
31
+ declare const Vec2: {
32
+ /** Returns { 0, 0 }. */
33
+ readonly zero: () => Vec2;
34
+ /** Returns { 1, 1 }. */
35
+ readonly one: () => Vec2;
36
+ /** Returns { 0, -1 }. */
37
+ readonly up: () => Vec2;
38
+ /** Returns { 0, 1 }. */
39
+ readonly down: () => Vec2;
40
+ /** Returns { -1, 0 }. */
41
+ readonly left: () => Vec2;
42
+ /** Returns { 1, 0 }. */
43
+ readonly right: () => Vec2;
44
+ /** Component-wise addition. Writes into out if provided. */
45
+ readonly add: (a: Vec2, b: Vec2, out?: Vec2) => Vec2;
46
+ /** Component-wise subtraction a - b. */
47
+ readonly sub: (a: Vec2, b: Vec2, out?: Vec2) => Vec2;
48
+ /** Scales a vector by a scalar. */
49
+ readonly scale: (v: Vec2, s: number, out?: Vec2) => Vec2;
50
+ /** Returns a unit vector. Returns zero vector if length is 0. */
51
+ readonly normalize: (v: Vec2, out?: Vec2) => Vec2;
52
+ /** Zero-alloc; writes into `out`. Mandatory `out` so callers avoid temporaries in hot paths. */
53
+ readonly normalizeOut: (dx: number, dy: number, speed: number, out: Vec2) => Vec2;
54
+ /** Dot product. */
55
+ readonly dot: (a: Vec2, b: Vec2) => number;
56
+ /** 2D cross product (z-component of the 3D cross). */
57
+ readonly cross: (a: Vec2, b: Vec2) => number;
58
+ /** Linearly interpolates between a and b (unclamped). */
59
+ readonly lerp: (a: Vec2, b: Vec2, t: number, out?: Vec2) => Vec2;
60
+ /** Spherical linear interpolation for unit vectors. */
61
+ readonly slerp: (a: Vec2, b: Vec2, t: number, out?: Vec2) => Vec2;
62
+ /** Euclidean distance between two points. */
63
+ readonly distance: (a: Vec2, b: Vec2) => number;
64
+ /** Squared distance (avoids sqrt). */
65
+ readonly distanceSq: (a: Vec2, b: Vec2) => number;
66
+ /** Length of a vector. */
67
+ readonly length: (v: Vec2) => number;
68
+ /** Squared length (avoids sqrt). */
69
+ readonly lengthSq: (v: Vec2) => number;
70
+ /** Angle of vector in radians (atan2). */
71
+ readonly angle: (v: Vec2) => number;
72
+ /** Rotates a vector by angle (radians) around origin. */
73
+ readonly rotate: (v: Vec2, angle: number, out?: Vec2) => Vec2;
74
+ /** Component-wise approximate equality. */
75
+ readonly equals: (a: Vec2, b: Vec2, epsilon?: number) => boolean;
76
+ /** Returns a copy of the vector. */
77
+ readonly clone: (v: Vec2) => Vec2;
78
+ /** Clamps the length of a vector to maxLength. */
79
+ readonly clampLength: (v: Vec2, maxLength: number, out?: Vec2) => Vec2;
80
+ };
81
+
82
+ /** Axis-aligned bounding box. */
83
+ type Rect = {
84
+ x: number;
85
+ y: number;
86
+ width: number;
87
+ height: number;
88
+ };
89
+ declare const Rect: {
90
+ /** Returns true if point is inside rect (inclusive). */
91
+ readonly contains: (r: Rect, p: Vec2) => boolean;
92
+ /** Returns true if two rects overlap (share area). */
93
+ readonly intersects: (a: Rect, b: Rect) => boolean;
94
+ /** Returns the overlapping rect, or null if no overlap. */
95
+ readonly intersection: (a: Rect, b: Rect) => Rect | null;
96
+ /** Returns the smallest rect containing both rects. */
97
+ readonly union: (a: Rect, b: Rect) => Rect;
98
+ /** Creates a rect from an array of points (bounding box). */
99
+ readonly fromPoints: (points: readonly Vec2[]) => Rect;
100
+ /** Returns the center point of the rect. */
101
+ readonly center: (r: Rect) => Vec2;
102
+ /** Returns a new rect expanded by amount on each side. */
103
+ readonly expand: (r: Rect, amount: number) => Rect;
104
+ };
105
+
106
+ /** Circle shape: center position + radius. */
107
+ type Circle = {
108
+ x: number;
109
+ y: number;
110
+ radius: number;
111
+ };
112
+ declare const Circle: {
113
+ /** Returns true if point is inside or on the circle. */
114
+ readonly contains: (c: Circle, p: Vec2) => boolean;
115
+ /** Returns true if two circles overlap (share area). */
116
+ readonly intersects: (a: Circle, b: Circle) => boolean;
117
+ /** Returns true if a circle and rect overlap. */
118
+ readonly intersectsRect: (c: Circle, r: Rect) => boolean;
119
+ };
120
+
121
+ /** 2D transform: position, rotation (radians), and scale. */
122
+ type Transform2D = {
123
+ position: Vec2;
124
+ rotation: number;
125
+ scale: Vec2;
126
+ };
127
+ declare const Transform2D: {
128
+ /** Creates an identity transform. */
129
+ readonly identity: () => Transform2D;
130
+ /** Creates a transform from components. */
131
+ readonly create: (x?: number, y?: number, rotation?: number, scaleX?: number, scaleY?: number) => Transform2D;
132
+ /** Transforms a local-space point to world-space. */
133
+ readonly localToWorld: (t: Transform2D, point: Vec2) => Vec2;
134
+ /** Transforms a world-space point to local-space. */
135
+ readonly worldToLocal: (t: Transform2D, point: Vec2) => Vec2;
136
+ /** Returns a copy of the transform. */
137
+ readonly clone: (t: Transform2D) => Transform2D;
138
+ };
139
+
140
+ /**
141
+ * 3x3 matrix stored in column-major order on Float32Array.
142
+ * Layout: [m00, m10, m20, m01, m11, m21, m02, m12, m22]
143
+ *
144
+ * | m00 m01 m02 | indices: | 0 3 6 |
145
+ * | m10 m11 m12 | | 1 4 7 |
146
+ * | m20 m21 m22 | | 2 5 8 |
147
+ */
148
+ type Mat3 = Float32Array;
149
+ declare const Mat3: {
150
+ /** Creates a new identity matrix. */
151
+ readonly create: () => Mat3;
152
+ /** Sets m to identity. */
153
+ readonly identity: (m: Mat3) => Mat3;
154
+ /** Multiplies a * b, writes into out (or allocates). */
155
+ readonly multiply: (a: Mat3, b: Mat3, out?: Mat3) => Mat3;
156
+ /** Creates a translation matrix. */
157
+ readonly translate: (tx: number, ty: number, out?: Mat3) => Mat3;
158
+ /** Creates a rotation matrix (radians). */
159
+ readonly rotate: (angle: number, out?: Mat3) => Mat3;
160
+ /** Creates a scale matrix. */
161
+ readonly scale: (sx: number, sy: number, out?: Mat3) => Mat3;
162
+ /** Inverts the matrix. Returns null if singular. */
163
+ readonly invert: (m: Mat3, out?: Mat3) => Mat3 | null;
164
+ /** Builds a matrix from a Transform2D (TRS order: translate * rotate * scale). */
165
+ readonly fromTransform: (t: Transform2D, out?: Mat3) => Mat3;
166
+ };
167
+
168
+ /** OKLab perceptual color space (L 0-1, a and b unbounded in practice ±0.5). */
169
+ type Oklab = {
170
+ L: number;
171
+ a: number;
172
+ b: number;
173
+ };
174
+ /** OKLCH polar form of OKLab (L 0-1, C >= 0, h degrees [0,360)). */
175
+ type Oklch = {
176
+ L: number;
177
+ C: number;
178
+ h: number;
179
+ };
180
+ /** RGBA color with components normalized to 0-1. */
181
+ type Color = {
182
+ r: number;
183
+ g: number;
184
+ b: number;
185
+ a: number;
186
+ };
187
+ declare const Color: {
188
+ readonly WHITE: Color;
189
+ readonly BLACK: Color;
190
+ readonly TRANSPARENT: Color;
191
+ /** Creates a Color from normalized 0-1 components. */
192
+ readonly create: (r?: number, g?: number, b?: number, a?: number) => Color;
193
+ /** Parses a hex string (#RGB, #RGBA, #RRGGBB, #RRGGBBAA). */
194
+ readonly fromHex: (hex: string) => Color;
195
+ /** Converts to hex string #RRGGBB or #RRGGBBAA if alpha < 1. */
196
+ readonly toHex: (c: Color) => string;
197
+ /** Linearly interpolates between two colors. */
198
+ readonly lerp: (a: Color, b: Color, t: number) => Color;
199
+ /** Component-wise multiplication. */
200
+ readonly multiply: (a: Color, b: Color) => Color;
201
+ /**
202
+ * Converts to a Skia-compatible color number (0xAARRGGBB).
203
+ * Compatible with @shopify/react-native-skia Skia.Color() format.
204
+ */
205
+ readonly toSkColor: (c: Color) => number;
206
+ /** Converts sRGB Color to OKLab. Alpha is dropped. */
207
+ readonly toOklab: (c: Color) => Oklab;
208
+ /**
209
+ * Converts OKLab to sRGB Color. Out-of-gamut results are clamped to [0,1];
210
+ * round-trips are exact only for in-gamut colors.
211
+ */
212
+ readonly fromOklab: (lab: Oklab, alpha?: number) => Color;
213
+ /** Converts sRGB Color to OKLCH (polar OKLab). Achromatic colors get h = 0. */
214
+ readonly toOklch: (c: Color) => Oklch;
215
+ /**
216
+ * Converts OKLCH to sRGB Color. Hue is wrapped via ((h%360)+360)%360.
217
+ * Out-of-gamut results are clamped; round-trips exact only in-gamut.
218
+ */
219
+ readonly fromOklch: (lch: Oklch, alpha?: number) => Color;
220
+ /** Euclidean distance in OKLab space between two sRGB colors. */
221
+ readonly deltaEOk: (a: Color, b: Color) => number;
222
+ /** Euclidean distance between two OKLab values. */
223
+ readonly deltaEOkLab: (a: Oklab, b: Oklab) => number;
224
+ /** WCAG 2.x relative luminance. White = 1, black = 0. */
225
+ readonly relativeLuminance: (c: Color) => number;
226
+ /** WCAG 2.x contrast ratio. Order-independent; range [1, 21]. */
227
+ readonly contrastRatio: (fg: Color, bg: Color) => number;
228
+ };
229
+
230
+ declare function linear(t: number): number;
231
+ declare function step(t: number): number;
232
+ declare function easeInQuad(t: number): number;
233
+ declare function easeOutQuad(t: number): number;
234
+ declare function easeInOutQuad(t: number): number;
235
+ declare function easeInCubic(t: number): number;
236
+ declare function easeOutCubic(t: number): number;
237
+ declare function easeInOutCubic(t: number): number;
238
+ declare function easeInQuart(t: number): number;
239
+ declare function easeOutQuart(t: number): number;
240
+ declare function easeInOutQuart(t: number): number;
241
+ declare function easeInQuint(t: number): number;
242
+ declare function easeOutQuint(t: number): number;
243
+ declare function easeInOutQuint(t: number): number;
244
+ declare function easeInSine(t: number): number;
245
+ declare function easeOutSine(t: number): number;
246
+ declare function easeInOutSine(t: number): number;
247
+ declare function easeInExpo(t: number): number;
248
+ declare function easeOutExpo(t: number): number;
249
+ declare function easeInOutExpo(t: number): number;
250
+ declare function easeInCirc(t: number): number;
251
+ declare function easeOutCirc(t: number): number;
252
+ declare function easeInOutCirc(t: number): number;
253
+ declare function easeInBack(t: number): number;
254
+ declare function easeOutBack(t: number): number;
255
+ declare function easeInOutBack(t: number): number;
256
+ declare function easeInElastic(t: number): number;
257
+ declare function easeOutElastic(t: number): number;
258
+ declare function easeInOutElastic(t: number): number;
259
+ declare function easeOutBounce(t: number): number;
260
+ declare function easeInBounce(t: number): number;
261
+ declare function easeInOutBounce(t: number): number;
262
+ declare function springIn(t: number): number;
263
+ declare function springOut(t: number): number;
264
+ declare function springInOut(t: number): number;
265
+ type EasingFn = (t: number) => number;
266
+
267
+ /** Seeded PRNG using mulberry32 algorithm. */
268
+ declare class SeededRNG {
269
+ private state;
270
+ constructor(seed: number);
271
+ /** Returns a float in [0, 1). */
272
+ next(): number;
273
+ /** Returns a float in [min, max). */
274
+ float(min: number, max: number): number;
275
+ /** Returns an integer in [min, max] (inclusive). */
276
+ int(min: number, max: number): number;
277
+ }
278
+ /** Returns a random float in [min, max). */
279
+ declare function randomFloat(min: number, max: number): number;
280
+ /** Returns a random integer in [min, max] (inclusive). */
281
+ declare function randomInt(min: number, max: number): number;
282
+ /** Returns a random Vec2 within a rect. */
283
+ declare function randomVec2InRect(r: Rect): Vec2;
284
+ /** Returns a random point inside a circle (uniform distribution). */
285
+ declare function randomPointInCircle(cx: number, cy: number, radius: number): Vec2;
286
+ /** Fisher-Yates shuffle (in-place). Returns the array. */
287
+ declare function shuffle<T>(array: T[]): T[];
288
+ /** Returns a random element from the array. */
289
+ declare function choose<T>(array: readonly T[]): T | undefined;
290
+
291
+ /** Returns true if point is inside rect (inclusive). */
292
+ declare function pointInRect(p: Vec2, r: Rect): boolean;
293
+ /** Returns true if point is inside circle (inclusive). */
294
+ declare function pointInCircle(p: Vec2, c: Circle): boolean;
295
+ /** Returns true if two rects overlap. */
296
+ declare function rectVsRect(a: Rect, b: Rect): boolean;
297
+ /** Returns true if rect and circle overlap. */
298
+ declare function rectVsCircle(r: Rect, c: Circle): boolean;
299
+ /** Returns true if two circles overlap. */
300
+ declare function circleVsCircle(a: Circle, b: Circle): boolean;
301
+ /** Line segment intersection with AABB. Uses Liang-Barsky algorithm. */
302
+ declare function lineVsRect(x1: number, y1: number, x2: number, y2: number, r: Rect): boolean;
303
+ /** Line segment intersection with circle. */
304
+ declare function lineVsCircle(x1: number, y1: number, x2: number, y2: number, c: Circle): boolean;
305
+ /** Ray intersection with AABB. Returns t (distance) or null if no hit. */
306
+ declare function rayVsRect(originX: number, originY: number, dirX: number, dirY: number, r: Rect): number | null;
307
+
308
+ export { Circle, Color, type EasingFn, Mat3, type Oklab, type Oklch, Rect, SeededRNG, Transform2D, Vec2, approxEquals, choose, circleVsCircle, clamp, degToRad, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, inverseLerp, lerp, lineVsCircle, lineVsRect, linear, map, pingPong, pointInCircle, pointInRect, radToDeg, randomFloat, randomInt, randomPointInCircle, randomVec2InRect, rayVsRect, rectVsCircle, rectVsRect, shuffle, sign, smoothStep, springIn, springInOut, springOut, step, vec2, wrap };
@@ -0,0 +1,308 @@
1
+ /** Clamps value between min and max. */
2
+ declare function clamp(value: number, min: number, max: number): number;
3
+ /** Linearly interpolates between a and b by t (unclamped). */
4
+ declare function lerp(a: number, b: number, t: number): number;
5
+ /** Returns the interpolation factor of value between a and b. */
6
+ declare function inverseLerp(a: number, b: number, value: number): number;
7
+ /** Maps value from [inMin, inMax] to [outMin, outMax]. */
8
+ declare function map(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number;
9
+ /** Converts degrees to radians. */
10
+ declare function degToRad(degrees: number): number;
11
+ /** Converts radians to degrees. */
12
+ declare function radToDeg(radians: number): number;
13
+ /** Returns true if a and b are approximately equal within epsilon. */
14
+ declare function approxEquals(a: number, b: number, epsilon?: number): boolean;
15
+ /** Wraps value into [min, max) range. */
16
+ declare function wrap(value: number, min: number, max: number): number;
17
+ /** PingPong — bounces value back and forth in [0, length]. */
18
+ declare function pingPong(t: number, length: number): number;
19
+ /** Hermite smooth interpolation (0→1) with zero first-derivative at edges. */
20
+ declare function smoothStep(edge0: number, edge1: number, x: number): number;
21
+ /** Returns -1, 0, or 1. Unlike Math.sign, returns 0 for NaN. */
22
+ declare function sign(value: number): number;
23
+
24
+ /** Creates a Vec2 plain object. */
25
+ declare function vec2(x?: number, y?: number): Vec2;
26
+ /** Vec2 plain object type — no class, no GC pressure. */
27
+ type Vec2 = {
28
+ x: number;
29
+ y: number;
30
+ };
31
+ declare const Vec2: {
32
+ /** Returns { 0, 0 }. */
33
+ readonly zero: () => Vec2;
34
+ /** Returns { 1, 1 }. */
35
+ readonly one: () => Vec2;
36
+ /** Returns { 0, -1 }. */
37
+ readonly up: () => Vec2;
38
+ /** Returns { 0, 1 }. */
39
+ readonly down: () => Vec2;
40
+ /** Returns { -1, 0 }. */
41
+ readonly left: () => Vec2;
42
+ /** Returns { 1, 0 }. */
43
+ readonly right: () => Vec2;
44
+ /** Component-wise addition. Writes into out if provided. */
45
+ readonly add: (a: Vec2, b: Vec2, out?: Vec2) => Vec2;
46
+ /** Component-wise subtraction a - b. */
47
+ readonly sub: (a: Vec2, b: Vec2, out?: Vec2) => Vec2;
48
+ /** Scales a vector by a scalar. */
49
+ readonly scale: (v: Vec2, s: number, out?: Vec2) => Vec2;
50
+ /** Returns a unit vector. Returns zero vector if length is 0. */
51
+ readonly normalize: (v: Vec2, out?: Vec2) => Vec2;
52
+ /** Zero-alloc; writes into `out`. Mandatory `out` so callers avoid temporaries in hot paths. */
53
+ readonly normalizeOut: (dx: number, dy: number, speed: number, out: Vec2) => Vec2;
54
+ /** Dot product. */
55
+ readonly dot: (a: Vec2, b: Vec2) => number;
56
+ /** 2D cross product (z-component of the 3D cross). */
57
+ readonly cross: (a: Vec2, b: Vec2) => number;
58
+ /** Linearly interpolates between a and b (unclamped). */
59
+ readonly lerp: (a: Vec2, b: Vec2, t: number, out?: Vec2) => Vec2;
60
+ /** Spherical linear interpolation for unit vectors. */
61
+ readonly slerp: (a: Vec2, b: Vec2, t: number, out?: Vec2) => Vec2;
62
+ /** Euclidean distance between two points. */
63
+ readonly distance: (a: Vec2, b: Vec2) => number;
64
+ /** Squared distance (avoids sqrt). */
65
+ readonly distanceSq: (a: Vec2, b: Vec2) => number;
66
+ /** Length of a vector. */
67
+ readonly length: (v: Vec2) => number;
68
+ /** Squared length (avoids sqrt). */
69
+ readonly lengthSq: (v: Vec2) => number;
70
+ /** Angle of vector in radians (atan2). */
71
+ readonly angle: (v: Vec2) => number;
72
+ /** Rotates a vector by angle (radians) around origin. */
73
+ readonly rotate: (v: Vec2, angle: number, out?: Vec2) => Vec2;
74
+ /** Component-wise approximate equality. */
75
+ readonly equals: (a: Vec2, b: Vec2, epsilon?: number) => boolean;
76
+ /** Returns a copy of the vector. */
77
+ readonly clone: (v: Vec2) => Vec2;
78
+ /** Clamps the length of a vector to maxLength. */
79
+ readonly clampLength: (v: Vec2, maxLength: number, out?: Vec2) => Vec2;
80
+ };
81
+
82
+ /** Axis-aligned bounding box. */
83
+ type Rect = {
84
+ x: number;
85
+ y: number;
86
+ width: number;
87
+ height: number;
88
+ };
89
+ declare const Rect: {
90
+ /** Returns true if point is inside rect (inclusive). */
91
+ readonly contains: (r: Rect, p: Vec2) => boolean;
92
+ /** Returns true if two rects overlap (share area). */
93
+ readonly intersects: (a: Rect, b: Rect) => boolean;
94
+ /** Returns the overlapping rect, or null if no overlap. */
95
+ readonly intersection: (a: Rect, b: Rect) => Rect | null;
96
+ /** Returns the smallest rect containing both rects. */
97
+ readonly union: (a: Rect, b: Rect) => Rect;
98
+ /** Creates a rect from an array of points (bounding box). */
99
+ readonly fromPoints: (points: readonly Vec2[]) => Rect;
100
+ /** Returns the center point of the rect. */
101
+ readonly center: (r: Rect) => Vec2;
102
+ /** Returns a new rect expanded by amount on each side. */
103
+ readonly expand: (r: Rect, amount: number) => Rect;
104
+ };
105
+
106
+ /** Circle shape: center position + radius. */
107
+ type Circle = {
108
+ x: number;
109
+ y: number;
110
+ radius: number;
111
+ };
112
+ declare const Circle: {
113
+ /** Returns true if point is inside or on the circle. */
114
+ readonly contains: (c: Circle, p: Vec2) => boolean;
115
+ /** Returns true if two circles overlap (share area). */
116
+ readonly intersects: (a: Circle, b: Circle) => boolean;
117
+ /** Returns true if a circle and rect overlap. */
118
+ readonly intersectsRect: (c: Circle, r: Rect) => boolean;
119
+ };
120
+
121
+ /** 2D transform: position, rotation (radians), and scale. */
122
+ type Transform2D = {
123
+ position: Vec2;
124
+ rotation: number;
125
+ scale: Vec2;
126
+ };
127
+ declare const Transform2D: {
128
+ /** Creates an identity transform. */
129
+ readonly identity: () => Transform2D;
130
+ /** Creates a transform from components. */
131
+ readonly create: (x?: number, y?: number, rotation?: number, scaleX?: number, scaleY?: number) => Transform2D;
132
+ /** Transforms a local-space point to world-space. */
133
+ readonly localToWorld: (t: Transform2D, point: Vec2) => Vec2;
134
+ /** Transforms a world-space point to local-space. */
135
+ readonly worldToLocal: (t: Transform2D, point: Vec2) => Vec2;
136
+ /** Returns a copy of the transform. */
137
+ readonly clone: (t: Transform2D) => Transform2D;
138
+ };
139
+
140
+ /**
141
+ * 3x3 matrix stored in column-major order on Float32Array.
142
+ * Layout: [m00, m10, m20, m01, m11, m21, m02, m12, m22]
143
+ *
144
+ * | m00 m01 m02 | indices: | 0 3 6 |
145
+ * | m10 m11 m12 | | 1 4 7 |
146
+ * | m20 m21 m22 | | 2 5 8 |
147
+ */
148
+ type Mat3 = Float32Array;
149
+ declare const Mat3: {
150
+ /** Creates a new identity matrix. */
151
+ readonly create: () => Mat3;
152
+ /** Sets m to identity. */
153
+ readonly identity: (m: Mat3) => Mat3;
154
+ /** Multiplies a * b, writes into out (or allocates). */
155
+ readonly multiply: (a: Mat3, b: Mat3, out?: Mat3) => Mat3;
156
+ /** Creates a translation matrix. */
157
+ readonly translate: (tx: number, ty: number, out?: Mat3) => Mat3;
158
+ /** Creates a rotation matrix (radians). */
159
+ readonly rotate: (angle: number, out?: Mat3) => Mat3;
160
+ /** Creates a scale matrix. */
161
+ readonly scale: (sx: number, sy: number, out?: Mat3) => Mat3;
162
+ /** Inverts the matrix. Returns null if singular. */
163
+ readonly invert: (m: Mat3, out?: Mat3) => Mat3 | null;
164
+ /** Builds a matrix from a Transform2D (TRS order: translate * rotate * scale). */
165
+ readonly fromTransform: (t: Transform2D, out?: Mat3) => Mat3;
166
+ };
167
+
168
+ /** OKLab perceptual color space (L 0-1, a and b unbounded in practice ±0.5). */
169
+ type Oklab = {
170
+ L: number;
171
+ a: number;
172
+ b: number;
173
+ };
174
+ /** OKLCH polar form of OKLab (L 0-1, C >= 0, h degrees [0,360)). */
175
+ type Oklch = {
176
+ L: number;
177
+ C: number;
178
+ h: number;
179
+ };
180
+ /** RGBA color with components normalized to 0-1. */
181
+ type Color = {
182
+ r: number;
183
+ g: number;
184
+ b: number;
185
+ a: number;
186
+ };
187
+ declare const Color: {
188
+ readonly WHITE: Color;
189
+ readonly BLACK: Color;
190
+ readonly TRANSPARENT: Color;
191
+ /** Creates a Color from normalized 0-1 components. */
192
+ readonly create: (r?: number, g?: number, b?: number, a?: number) => Color;
193
+ /** Parses a hex string (#RGB, #RGBA, #RRGGBB, #RRGGBBAA). */
194
+ readonly fromHex: (hex: string) => Color;
195
+ /** Converts to hex string #RRGGBB or #RRGGBBAA if alpha < 1. */
196
+ readonly toHex: (c: Color) => string;
197
+ /** Linearly interpolates between two colors. */
198
+ readonly lerp: (a: Color, b: Color, t: number) => Color;
199
+ /** Component-wise multiplication. */
200
+ readonly multiply: (a: Color, b: Color) => Color;
201
+ /**
202
+ * Converts to a Skia-compatible color number (0xAARRGGBB).
203
+ * Compatible with @shopify/react-native-skia Skia.Color() format.
204
+ */
205
+ readonly toSkColor: (c: Color) => number;
206
+ /** Converts sRGB Color to OKLab. Alpha is dropped. */
207
+ readonly toOklab: (c: Color) => Oklab;
208
+ /**
209
+ * Converts OKLab to sRGB Color. Out-of-gamut results are clamped to [0,1];
210
+ * round-trips are exact only for in-gamut colors.
211
+ */
212
+ readonly fromOklab: (lab: Oklab, alpha?: number) => Color;
213
+ /** Converts sRGB Color to OKLCH (polar OKLab). Achromatic colors get h = 0. */
214
+ readonly toOklch: (c: Color) => Oklch;
215
+ /**
216
+ * Converts OKLCH to sRGB Color. Hue is wrapped via ((h%360)+360)%360.
217
+ * Out-of-gamut results are clamped; round-trips exact only in-gamut.
218
+ */
219
+ readonly fromOklch: (lch: Oklch, alpha?: number) => Color;
220
+ /** Euclidean distance in OKLab space between two sRGB colors. */
221
+ readonly deltaEOk: (a: Color, b: Color) => number;
222
+ /** Euclidean distance between two OKLab values. */
223
+ readonly deltaEOkLab: (a: Oklab, b: Oklab) => number;
224
+ /** WCAG 2.x relative luminance. White = 1, black = 0. */
225
+ readonly relativeLuminance: (c: Color) => number;
226
+ /** WCAG 2.x contrast ratio. Order-independent; range [1, 21]. */
227
+ readonly contrastRatio: (fg: Color, bg: Color) => number;
228
+ };
229
+
230
+ declare function linear(t: number): number;
231
+ declare function step(t: number): number;
232
+ declare function easeInQuad(t: number): number;
233
+ declare function easeOutQuad(t: number): number;
234
+ declare function easeInOutQuad(t: number): number;
235
+ declare function easeInCubic(t: number): number;
236
+ declare function easeOutCubic(t: number): number;
237
+ declare function easeInOutCubic(t: number): number;
238
+ declare function easeInQuart(t: number): number;
239
+ declare function easeOutQuart(t: number): number;
240
+ declare function easeInOutQuart(t: number): number;
241
+ declare function easeInQuint(t: number): number;
242
+ declare function easeOutQuint(t: number): number;
243
+ declare function easeInOutQuint(t: number): number;
244
+ declare function easeInSine(t: number): number;
245
+ declare function easeOutSine(t: number): number;
246
+ declare function easeInOutSine(t: number): number;
247
+ declare function easeInExpo(t: number): number;
248
+ declare function easeOutExpo(t: number): number;
249
+ declare function easeInOutExpo(t: number): number;
250
+ declare function easeInCirc(t: number): number;
251
+ declare function easeOutCirc(t: number): number;
252
+ declare function easeInOutCirc(t: number): number;
253
+ declare function easeInBack(t: number): number;
254
+ declare function easeOutBack(t: number): number;
255
+ declare function easeInOutBack(t: number): number;
256
+ declare function easeInElastic(t: number): number;
257
+ declare function easeOutElastic(t: number): number;
258
+ declare function easeInOutElastic(t: number): number;
259
+ declare function easeOutBounce(t: number): number;
260
+ declare function easeInBounce(t: number): number;
261
+ declare function easeInOutBounce(t: number): number;
262
+ declare function springIn(t: number): number;
263
+ declare function springOut(t: number): number;
264
+ declare function springInOut(t: number): number;
265
+ type EasingFn = (t: number) => number;
266
+
267
+ /** Seeded PRNG using mulberry32 algorithm. */
268
+ declare class SeededRNG {
269
+ private state;
270
+ constructor(seed: number);
271
+ /** Returns a float in [0, 1). */
272
+ next(): number;
273
+ /** Returns a float in [min, max). */
274
+ float(min: number, max: number): number;
275
+ /** Returns an integer in [min, max] (inclusive). */
276
+ int(min: number, max: number): number;
277
+ }
278
+ /** Returns a random float in [min, max). */
279
+ declare function randomFloat(min: number, max: number): number;
280
+ /** Returns a random integer in [min, max] (inclusive). */
281
+ declare function randomInt(min: number, max: number): number;
282
+ /** Returns a random Vec2 within a rect. */
283
+ declare function randomVec2InRect(r: Rect): Vec2;
284
+ /** Returns a random point inside a circle (uniform distribution). */
285
+ declare function randomPointInCircle(cx: number, cy: number, radius: number): Vec2;
286
+ /** Fisher-Yates shuffle (in-place). Returns the array. */
287
+ declare function shuffle<T>(array: T[]): T[];
288
+ /** Returns a random element from the array. */
289
+ declare function choose<T>(array: readonly T[]): T | undefined;
290
+
291
+ /** Returns true if point is inside rect (inclusive). */
292
+ declare function pointInRect(p: Vec2, r: Rect): boolean;
293
+ /** Returns true if point is inside circle (inclusive). */
294
+ declare function pointInCircle(p: Vec2, c: Circle): boolean;
295
+ /** Returns true if two rects overlap. */
296
+ declare function rectVsRect(a: Rect, b: Rect): boolean;
297
+ /** Returns true if rect and circle overlap. */
298
+ declare function rectVsCircle(r: Rect, c: Circle): boolean;
299
+ /** Returns true if two circles overlap. */
300
+ declare function circleVsCircle(a: Circle, b: Circle): boolean;
301
+ /** Line segment intersection with AABB. Uses Liang-Barsky algorithm. */
302
+ declare function lineVsRect(x1: number, y1: number, x2: number, y2: number, r: Rect): boolean;
303
+ /** Line segment intersection with circle. */
304
+ declare function lineVsCircle(x1: number, y1: number, x2: number, y2: number, c: Circle): boolean;
305
+ /** Ray intersection with AABB. Returns t (distance) or null if no hit. */
306
+ declare function rayVsRect(originX: number, originY: number, dirX: number, dirY: number, r: Rect): number | null;
307
+
308
+ export { Circle, Color, type EasingFn, Mat3, type Oklab, type Oklch, Rect, SeededRNG, Transform2D, Vec2, approxEquals, choose, circleVsCircle, clamp, degToRad, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, inverseLerp, lerp, lineVsCircle, lineVsRect, linear, map, pingPong, pointInCircle, pointInRect, radToDeg, randomFloat, randomInt, randomPointInCircle, randomVec2InRect, rayVsRect, rectVsCircle, rectVsRect, shuffle, sign, smoothStep, springIn, springInOut, springOut, step, vec2, wrap };