-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.math.mjs
More file actions
120 lines (105 loc) · 2.91 KB
/
util.math.mjs
File metadata and controls
120 lines (105 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* @fileoverview Math Utilities - Time conversion, bezier curves, random numbers
* @module util.math
* @version 1.1.0
* @author hnldesign
* @since 2022
*/
export const NAME = 'math';
/**
* Regex for detecting seconds suffix.
* @private
* @constant {RegExp}
*/
const SECONDS_REGEX = /\ds$/;
/**
* Converts CSS time string to milliseconds.
*
* @param {string} s - Time string (e.g., '1s', '500ms', '1.5s')
* @returns {number} Time in milliseconds
*
* @example
* toMS('1s'); // → 1000
* toMS('500ms'); // → 500
* toMS('1.5s'); // → 1500
* toMS('0.25s'); // → 250
*/
export function toMS(s) {
return parseFloat(s) * (SECONDS_REGEX.test(s) ? 1000 : 1);
}
/**
* Calculates Y coordinate on cubic Bezier curve at parameter t.
* Uses Newton-Raphson method for X→t conversion.
*
* @param {number[]} controlPoints - Four control points [x1, y1, x2, y2]
* @param {number} t - Parameter value (0-1)
* @returns {number} Y coordinate at t
*
* @example
* // Ease-in-out curve at halfway point
* cubicBezier([0.42, 0, 0.58, 1], 0.5); // → ~0.5
*
* @example
* // Ease-out curve at 25% through animation
* cubicBezier([0, 0, 0.58, 1], 0.25); // → ~0.44
*/
export function cubicBezier(controlPoints, t) {
const [x1, y1, x2, y2] = controlPoints;
// Bezier basis coefficients
const cx = 3 * x1;
const bx = 3 * (x2 - x1) - cx;
const ax = 1 - cx - bx;
const cy = 3 * y1;
const by = 3 * (y2 - y1) - cy;
const ay = 1 - cy - by;
/**
* Sample X coordinate on curve.
* @private
*/
const sampleX = (t) => ((ax * t + bx) * t + cx) * t;
/**
* Sample Y coordinate on curve.
* @private
*/
const sampleY = (t) => ((ay * t + by) * t + cy) * t;
/**
* Solve for t parameter given X coordinate.
* Uses Newton-Raphson iteration.
* @private
*/
const solveX = (x, epsilon) => {
let t2 = x;
for (let i = 0; i < 8; i++) {
const x2 = sampleX(t2) - x;
if (Math.abs(x2) < epsilon) {
return t2;
}
const d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
if (Math.abs(d2) < 1e-6) {
break;
}
t2 -= x2 / d2;
}
return t2;
};
// Convert t parameter to Y coordinate
const tResolved = solveX(t, 1e-6);
return sampleY(tResolved);
}
/**
* Generates random integer in range [min, max] (inclusive).
*
* @param {number} min - Minimum value (inclusive)
* @param {number} max - Maximum value (inclusive)
* @returns {number} Random integer
*
* @example
* getRandomInt(1, 6); // → Dice roll (1-6)
* getRandomInt(0, 100); // → Percentage (0-100)
* getRandomInt(-10, 10); // → Signed range
*/
export function getRandomInt(min, max) {
const minInt = Math.ceil(min);
const maxInt = Math.floor(max);
return Math.floor(Math.random() * (maxInt - minInt + 1)) + minInt;
}