@holoscript/std 7.0.0 → 7.0.1

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.
Files changed (132) hide show
  1. package/README.md +8 -0
  2. package/dist/chunk-DGUM43GV.js +11 -0
  3. package/dist/{chunk-PFX2JM4X.js → chunk-FAMOLKH3.js} +2 -1
  4. package/dist/{chunk-PFX2JM4X.js.map → chunk-FAMOLKH3.js.map} +1 -1
  5. package/dist/{chunk-DZHAVOCH.js → chunk-SOKH6FJ7.js} +31 -6
  6. package/dist/chunk-SOKH6FJ7.js.map +1 -0
  7. package/dist/collections.cjs +1 -0
  8. package/dist/collections.cjs.map +1 -1
  9. package/dist/collections.js +2 -2
  10. package/dist/fs/fs.d.ts.map +1 -1
  11. package/dist/fs/index.cjs +221 -8510
  12. package/dist/fs/index.cjs.map +1 -1
  13. package/dist/fs/index.js +832 -118
  14. package/dist/fs/index.js.map +1 -1
  15. package/dist/fs/sandbox.d.ts +49 -0
  16. package/dist/fs/sandbox.d.ts.map +1 -0
  17. package/dist/index.cjs +3494 -12672
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +0 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +17 -7
  22. package/dist/index.js.map +1 -1
  23. package/dist/math.cjs +18 -3
  24. package/dist/math.cjs.map +1 -1
  25. package/dist/math.js +2 -2
  26. package/dist/string.js +1 -1
  27. package/dist/time.js +1 -1
  28. package/dist/traits/EconomicPrimitives.js +1 -1
  29. package/dist/traits/EconomicTraits.js +1 -1
  30. package/dist/types.d.ts.map +1 -1
  31. package/package.json +19 -9
  32. package/dist/__tests__/EconomicPrimitives.test.d.ts +0 -2
  33. package/dist/__tests__/EconomicPrimitives.test.d.ts.map +0 -1
  34. package/dist/__tests__/EconomicTraits.test.d.ts +0 -2
  35. package/dist/__tests__/EconomicTraits.test.d.ts.map +0 -1
  36. package/dist/__tests__/SimulationLabPrimitives.test.d.ts +0 -2
  37. package/dist/__tests__/SimulationLabPrimitives.test.d.ts.map +0 -1
  38. package/dist/__tests__/collections.test.d.ts +0 -2
  39. package/dist/__tests__/collections.test.d.ts.map +0 -1
  40. package/dist/__tests__/events.test.d.ts +0 -2
  41. package/dist/__tests__/events.test.d.ts.map +0 -1
  42. package/dist/__tests__/index.test.d.ts +0 -2
  43. package/dist/__tests__/index.test.d.ts.map +0 -1
  44. package/dist/__tests__/materials.test.d.ts +0 -2
  45. package/dist/__tests__/materials.test.d.ts.map +0 -1
  46. package/dist/__tests__/math.test.d.ts +0 -2
  47. package/dist/__tests__/math.test.d.ts.map +0 -1
  48. package/dist/__tests__/physics.test.d.ts +0 -2
  49. package/dist/__tests__/physics.test.d.ts.map +0 -1
  50. package/dist/__tests__/spatial.test.d.ts +0 -2
  51. package/dist/__tests__/spatial.test.d.ts.map +0 -1
  52. package/dist/__tests__/standard-library-fundamentals.test.d.ts +0 -2
  53. package/dist/__tests__/standard-library-fundamentals.test.d.ts.map +0 -1
  54. package/dist/__tests__/string-and-time-utilities.test.d.ts +0 -2
  55. package/dist/__tests__/string-and-time-utilities.test.d.ts.map +0 -1
  56. package/dist/__tests__/string-decoupled.test.d.ts +0 -2
  57. package/dist/__tests__/string-decoupled.test.d.ts.map +0 -1
  58. package/dist/__tests__/string.test.d.ts +0 -2
  59. package/dist/__tests__/string.test.d.ts.map +0 -1
  60. package/dist/__tests__/time.test.d.ts +0 -2
  61. package/dist/__tests__/time.test.d.ts.map +0 -1
  62. package/dist/chunk-DZHAVOCH.js.map +0 -1
  63. package/dist/chunk-PR4QN5HX.js +0 -43
  64. package/dist/chunk-XBA4ARST.js +0 -9313
  65. package/dist/chunk-XBA4ARST.js.map +0 -1
  66. package/dist/fs/__tests__/file-watch-system.test.d.ts +0 -2
  67. package/dist/fs/__tests__/file-watch-system.test.d.ts.map +0 -1
  68. package/dist/fs/__tests__/path-utilities.test.d.ts +0 -2
  69. package/dist/fs/__tests__/path-utilities.test.d.ts.map +0 -1
  70. package/dist/fs/__tests__/path.test.d.ts +0 -2
  71. package/dist/fs/__tests__/path.test.d.ts.map +0 -1
  72. package/dist/string.basic.test.d.ts +0 -5
  73. package/dist/string.basic.test.d.ts.map +0 -1
  74. package/dist/string.test.d.ts +0 -5
  75. package/dist/string.test.d.ts.map +0 -1
  76. package/dist/traits/__tests__/ARTraits.test.d.ts +0 -2
  77. package/dist/traits/__tests__/ARTraits.test.d.ts.map +0 -1
  78. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts +0 -2
  79. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts.map +0 -1
  80. package/dist/traits/__tests__/EconomicTraits.test.d.ts +0 -2
  81. package/dist/traits/__tests__/EconomicTraits.test.d.ts.map +0 -1
  82. package/error-utf8.log +0 -6
  83. package/error.log +0 -0
  84. package/src/__tests__/EconomicPrimitives.test.ts +0 -690
  85. package/src/__tests__/EconomicTraits.test.ts +0 -425
  86. package/src/__tests__/SimulationLabPrimitives.test.ts +0 -415
  87. package/src/__tests__/collections.test.ts +0 -182
  88. package/src/__tests__/events.test.ts +0 -135
  89. package/src/__tests__/index.test.ts +0 -14
  90. package/src/__tests__/materials.test.ts +0 -84
  91. package/src/__tests__/math.test.ts +0 -246
  92. package/src/__tests__/physics.test.ts +0 -83
  93. package/src/__tests__/spatial.test.ts +0 -333
  94. package/src/__tests__/standard-library-fundamentals.test.ts +0 -1318
  95. package/src/__tests__/string-and-time-utilities.test.ts +0 -1070
  96. package/src/__tests__/string-decoupled.test.ts +0 -13
  97. package/src/__tests__/string.test.ts +0 -164
  98. package/src/__tests__/time.test.ts +0 -110
  99. package/src/collections.ts +0 -850
  100. package/src/events.ts +0 -88
  101. package/src/fs/__tests__/file-watch-system.test.ts +0 -675
  102. package/src/fs/__tests__/path-utilities.test.ts +0 -375
  103. package/src/fs/__tests__/path.test.ts +0 -287
  104. package/src/fs/fs.ts +0 -692
  105. package/src/fs/index.ts +0 -194
  106. package/src/fs/path.ts +0 -310
  107. package/src/fs/watch.ts +0 -413
  108. package/src/index.ts +0 -476
  109. package/src/materials.ts +0 -109
  110. package/src/math.ts +0 -674
  111. package/src/physics.ts +0 -141
  112. package/src/spatial.ts +0 -320
  113. package/src/string.basic.test.ts +0 -14
  114. package/src/string.test.ts +0 -335
  115. package/src/string.ts +0 -531
  116. package/src/time.ts +0 -621
  117. package/src/traits/ARTraits.ts +0 -103
  118. package/src/traits/EconomicPrimitives.ts +0 -755
  119. package/src/traits/EconomicTraits.ts +0 -552
  120. package/src/traits/IoTTraits.ts +0 -102
  121. package/src/traits/SimulationLabPrimitives.ts +0 -650
  122. package/src/traits/SimulationLabTraits.ts +0 -191
  123. package/src/traits/VRRTraits.ts +0 -326
  124. package/src/traits/__tests__/ARTraits.test.ts +0 -8
  125. package/src/traits/__tests__/EconomicPrimitives.test.ts +0 -14
  126. package/src/traits/__tests__/EconomicTraits.test.ts +0 -16
  127. package/src/types.ts +0 -418
  128. package/std_error.log +0 -5
  129. package/tsconfig.json +0 -18
  130. package/tsup.config.ts +0 -20
  131. package/vitest.config.ts +0 -10
  132. /package/dist/{chunk-PR4QN5HX.js.map → chunk-DGUM43GV.js.map} +0 -0
package/src/math.ts DELETED
@@ -1,674 +0,0 @@
1
- /**
2
- * Math utilities for HoloScript
3
- *
4
- * Vector math, quaternion operations, interpolation, and noise functions.
5
- */
6
-
7
- import type { Vec2, Vec3, Quat, EulerAngles, AABB } from './types.js';
8
- import { vec3, quat } from './types.js';
9
-
10
- // =============================================================================
11
- // CONSTANTS
12
- // =============================================================================
13
-
14
- export const PI = Math.PI;
15
- export const TAU = Math.PI * 2;
16
- export const HALF_PI = Math.PI / 2;
17
- export const DEG_TO_RAD = Math.PI / 180;
18
- export const RAD_TO_DEG = 180 / Math.PI;
19
- export const EPSILON = 1e-6;
20
-
21
- // =============================================================================
22
- // BASIC MATH
23
- // =============================================================================
24
-
25
- export function clamp(value: number, min: number, max: number): number {
26
- return Math.max(min, Math.min(max, value));
27
- }
28
-
29
- export function lerp(a: number, b: number, t: number): number {
30
- return a + (b - a) * t;
31
- }
32
-
33
- export function inverseLerp(a: number, b: number, value: number): number {
34
- return (value - a) / (b - a);
35
- }
36
-
37
- export function remap(
38
- value: number,
39
- inMin: number,
40
- inMax: number,
41
- outMin: number,
42
- outMax: number
43
- ): number {
44
- return lerp(outMin, outMax, inverseLerp(inMin, inMax, value));
45
- }
46
-
47
- export function smoothstep(edge0: number, edge1: number, x: number): number {
48
- const t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
49
- return t * t * (3 - 2 * t);
50
- }
51
-
52
- export function smootherstep(edge0: number, edge1: number, x: number): number {
53
- const t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
54
- return t * t * t * (t * (t * 6 - 15) + 10);
55
- }
56
-
57
- export function degToRad(degrees: number): number {
58
- return degrees * DEG_TO_RAD;
59
- }
60
-
61
- export function radToDeg(radians: number): number {
62
- return radians * RAD_TO_DEG;
63
- }
64
-
65
- export function mod(n: number, m: number): number {
66
- return ((n % m) + m) % m;
67
- }
68
-
69
- export function fract(x: number): number {
70
- return x - Math.floor(x);
71
- }
72
-
73
- export function sign(x: number): number {
74
- return x > 0 ? 1 : x < 0 ? -1 : 0;
75
- }
76
-
77
- export function step(edge: number, x: number): number {
78
- return x < edge ? 0 : 1;
79
- }
80
-
81
- // =============================================================================
82
- // VEC2 OPERATIONS
83
- // =============================================================================
84
-
85
- export const vec2Math = {
86
- add: (a: Vec2, b: Vec2): Vec2 => ({ x: a.x + b.x, y: a.y + b.y }),
87
- sub: (a: Vec2, b: Vec2): Vec2 => ({ x: a.x - b.x, y: a.y - b.y }),
88
- mul: (a: Vec2, s: number): Vec2 => ({ x: a.x * s, y: a.y * s }),
89
- div: (a: Vec2, s: number): Vec2 => ({ x: a.x / s, y: a.y / s }),
90
- dot: (a: Vec2, b: Vec2): number => a.x * b.x + a.y * b.y,
91
- length: (v: Vec2): number => Math.sqrt(v.x * v.x + v.y * v.y),
92
- lengthSq: (v: Vec2): number => v.x * v.x + v.y * v.y,
93
- normalize: (v: Vec2): Vec2 => {
94
- const len = vec2Math.length(v);
95
- return len > 0 ? vec2Math.div(v, len) : { x: 0, y: 0 };
96
- },
97
- distance: (a: Vec2, b: Vec2): number => vec2Math.length(vec2Math.sub(a, b)),
98
- lerp: (a: Vec2, b: Vec2, t: number): Vec2 => ({
99
- x: lerp(a.x, b.x, t),
100
- y: lerp(a.y, b.y, t),
101
- }),
102
- rotate: (v: Vec2, angle: number): Vec2 => {
103
- const c = Math.cos(angle);
104
- const s = Math.sin(angle);
105
- return { x: v.x * c - v.y * s, y: v.x * s + v.y * c };
106
- },
107
- angle: (v: Vec2): number => Math.atan2(v.y, v.x),
108
- angleBetween: (a: Vec2, b: Vec2): number => {
109
- return Math.acos(clamp(vec2Math.dot(vec2Math.normalize(a), vec2Math.normalize(b)), -1, 1));
110
- },
111
- };
112
-
113
- // =============================================================================
114
- // VEC3 OPERATIONS
115
- // =============================================================================
116
-
117
- export const vec3Math = {
118
- zero: (): Vec3 => vec3(0, 0, 0),
119
- one: (): Vec3 => vec3(1, 1, 1),
120
- up: (): Vec3 => vec3(0, 1, 0),
121
- down: (): Vec3 => vec3(0, -1, 0),
122
- forward: (): Vec3 => vec3(0, 0, -1),
123
- back: (): Vec3 => vec3(0, 0, 1),
124
- left: (): Vec3 => vec3(-1, 0, 0),
125
- right: (): Vec3 => vec3(1, 0, 0),
126
-
127
- add: (a: Vec3, b: Vec3): Vec3 => vec3(a.x + b.x, a.y + b.y, a.z + b.z),
128
- sub: (a: Vec3, b: Vec3): Vec3 => ({ x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }),
129
- mul: (a: Vec3, s: number): Vec3 => ({ x: a.x * s, y: a.y * s, z: a.z * s }),
130
- div: (a: Vec3, s: number): Vec3 => ({ x: a.x / s, y: a.y / s, z: a.z / s }),
131
- mulVec: (a: Vec3, b: Vec3): Vec3 => ({ x: a.x * b.x, y: a.y * b.y, z: a.z * b.z }),
132
-
133
- dot: (a: Vec3, b: Vec3): number => a.x * b.x + a.y * b.y + a.z * b.z,
134
-
135
- cross: (a: Vec3, b: Vec3): Vec3 => ({
136
- x: a.y * b.z - a.z * b.y,
137
- y: a.z * b.x - a.x * b.z,
138
- z: a.x * b.y - a.y * b.x,
139
- }),
140
-
141
- length: (v: Vec3): number => Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z),
142
- lengthSq: (v: Vec3): number => v.x * v.x + v.y * v.y + v.z * v.z,
143
-
144
- normalize: (v: Vec3): Vec3 => {
145
- const len = vec3Math.length(v);
146
- return len > EPSILON ? vec3Math.div(v, len) : vec3(0, 0, 0);
147
- },
148
-
149
- distance: (a: Vec3, b: Vec3): number => vec3Math.length(vec3Math.sub(a, b)),
150
- distanceSq: (a: Vec3, b: Vec3): number => vec3Math.lengthSq(vec3Math.sub(a, b)),
151
-
152
- lerp: (a: Vec3, b: Vec3, t: number): Vec3 => ({
153
- x: lerp(a.x, b.x, t),
154
- y: lerp(a.y, b.y, t),
155
- z: lerp(a.z, b.z, t),
156
- }),
157
-
158
- slerp: (a: Vec3, b: Vec3, t: number): Vec3 => {
159
- const dot = clamp(vec3Math.dot(a, b), -1, 1);
160
- const theta = Math.acos(dot) * t;
161
- const relative = vec3Math.normalize(vec3Math.sub(b, vec3Math.mul(a, dot)));
162
- return vec3Math.add(vec3Math.mul(a, Math.cos(theta)), vec3Math.mul(relative, Math.sin(theta)));
163
- },
164
-
165
- negate: (v: Vec3): Vec3 => ({ x: -v.x, y: -v.y, z: -v.z }),
166
-
167
- abs: (v: Vec3): Vec3 => ({ x: Math.abs(v.x), y: Math.abs(v.y), z: Math.abs(v.z) }),
168
-
169
- min: (a: Vec3, b: Vec3): Vec3 => ({
170
- x: Math.min(a.x, b.x),
171
- y: Math.min(a.y, b.y),
172
- z: Math.min(a.z, b.z),
173
- }),
174
-
175
- max: (a: Vec3, b: Vec3): Vec3 => ({
176
- x: Math.max(a.x, b.x),
177
- y: Math.max(a.y, b.y),
178
- z: Math.max(a.z, b.z),
179
- }),
180
-
181
- clamp: (v: Vec3, min: Vec3, max: Vec3): Vec3 => ({
182
- x: clamp(v.x, min.x, max.x),
183
- y: clamp(v.y, min.y, max.y),
184
- z: clamp(v.z, min.z, max.z),
185
- }),
186
-
187
- floor: (v: Vec3): Vec3 => ({
188
- x: Math.floor(v.x),
189
- y: Math.floor(v.y),
190
- z: Math.floor(v.z),
191
- }),
192
-
193
- ceil: (v: Vec3): Vec3 => ({
194
- x: Math.ceil(v.x),
195
- y: Math.ceil(v.y),
196
- z: Math.ceil(v.z),
197
- }),
198
-
199
- round: (v: Vec3): Vec3 => ({
200
- x: Math.round(v.x),
201
- y: Math.round(v.y),
202
- z: Math.round(v.z),
203
- }),
204
-
205
- reflect: (v: Vec3, normal: Vec3): Vec3 => {
206
- const dot = vec3Math.dot(v, normal);
207
- return vec3Math.sub(v, vec3Math.mul(normal, 2 * dot));
208
- },
209
-
210
- project: (v: Vec3, onto: Vec3): Vec3 => {
211
- const dot = vec3Math.dot(v, onto);
212
- const lenSq = vec3Math.lengthSq(onto);
213
- return vec3Math.mul(onto, dot / lenSq);
214
- },
215
-
216
- angle: (a: Vec3, b: Vec3): number => {
217
- const dot = vec3Math.dot(vec3Math.normalize(a), vec3Math.normalize(b));
218
- return Math.acos(clamp(dot, -1, 1));
219
- },
220
-
221
- equals: (a: Vec3, b: Vec3, epsilon: number = EPSILON): boolean => {
222
- return (
223
- Math.abs(a.x - b.x) < epsilon &&
224
- Math.abs(a.y - b.y) < epsilon &&
225
- Math.abs(a.z - b.z) < epsilon
226
- );
227
- },
228
- };
229
-
230
- // =============================================================================
231
- // QUATERNION OPERATIONS
232
- // =============================================================================
233
-
234
- export const quatMath = {
235
- identity: (): Quat => quat(0, 0, 0, 1),
236
-
237
- fromAxisAngle: (axis: Vec3, angle: number): Quat => {
238
- const halfAngle = angle / 2;
239
- const s = Math.sin(halfAngle);
240
- const normalized = vec3Math.normalize(axis);
241
- return {
242
- x: normalized.x * s,
243
- y: normalized.y * s,
244
- z: normalized.z * s,
245
- w: Math.cos(halfAngle),
246
- };
247
- },
248
-
249
- fromEuler: (euler: EulerAngles): Quat => {
250
- const { x, y, z } = euler;
251
- const c1 = Math.cos(degToRad(x) / 2);
252
- const c2 = Math.cos(degToRad(y) / 2);
253
- const c3 = Math.cos(degToRad(z) / 2);
254
- const s1 = Math.sin(degToRad(x) / 2);
255
- const s2 = Math.sin(degToRad(y) / 2);
256
- const s3 = Math.sin(degToRad(z) / 2);
257
-
258
- return {
259
- x: s1 * c2 * c3 + c1 * s2 * s3,
260
- y: c1 * s2 * c3 - s1 * c2 * s3,
261
- z: c1 * c2 * s3 + s1 * s2 * c3,
262
- w: c1 * c2 * c3 - s1 * s2 * s3,
263
- };
264
- },
265
-
266
- toEuler: (q: Quat): EulerAngles => {
267
- const sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
268
- const cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
269
- const x = Math.atan2(sinr_cosp, cosr_cosp);
270
-
271
- const sinp = 2 * (q.w * q.y - q.z * q.x);
272
- let y: number;
273
- if (Math.abs(sinp) >= 1) {
274
- y = (Math.PI / 2) * Math.sign(sinp);
275
- } else {
276
- y = Math.asin(sinp);
277
- }
278
-
279
- const siny_cosp = 2 * (q.w * q.z + q.x * q.y);
280
- const cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
281
- const z = Math.atan2(siny_cosp, cosy_cosp);
282
-
283
- return {
284
- x: radToDeg(x),
285
- y: radToDeg(y),
286
- z: radToDeg(z),
287
- };
288
- },
289
-
290
- multiply: (a: Quat, b: Quat): Quat => ({
291
- x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
292
- y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
293
- z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
294
- w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
295
- }),
296
-
297
- conjugate: (q: Quat): Quat => ({ x: -q.x, y: -q.y, z: -q.z, w: q.w }),
298
-
299
- inverse: (q: Quat): Quat => {
300
- const lenSq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
301
- return {
302
- x: -q.x / lenSq,
303
- y: -q.y / lenSq,
304
- z: -q.z / lenSq,
305
- w: q.w / lenSq,
306
- };
307
- },
308
-
309
- normalize: (q: Quat): Quat => {
310
- const len = Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
311
- return { x: q.x / len, y: q.y / len, z: q.z / len, w: q.w / len };
312
- },
313
-
314
- dot: (a: Quat, b: Quat): number => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w,
315
-
316
- slerp: (a: Quat, b: Quat, t: number): Quat => {
317
- let dot = quatMath.dot(a, b);
318
-
319
- // If dot is negative, negate one quaternion to take shorter path
320
- let bAdjusted = b;
321
- if (dot < 0) {
322
- bAdjusted = { x: -b.x, y: -b.y, z: -b.z, w: -b.w };
323
- dot = -dot;
324
- }
325
-
326
- if (dot > 0.9995) {
327
- // Linear interpolation for very close quaternions
328
- return quatMath.normalize({
329
- x: lerp(a.x, bAdjusted.x, t),
330
- y: lerp(a.y, bAdjusted.y, t),
331
- z: lerp(a.z, bAdjusted.z, t),
332
- w: lerp(a.w, bAdjusted.w, t),
333
- });
334
- }
335
-
336
- const theta0 = Math.acos(dot);
337
- const theta = theta0 * t;
338
- const sinTheta = Math.sin(theta);
339
- const sinTheta0 = Math.sin(theta0);
340
-
341
- const s0 = Math.cos(theta) - (dot * sinTheta) / sinTheta0;
342
- const s1 = sinTheta / sinTheta0;
343
-
344
- return {
345
- x: a.x * s0 + bAdjusted.x * s1,
346
- y: a.y * s0 + bAdjusted.y * s1,
347
- z: a.z * s0 + bAdjusted.z * s1,
348
- w: a.w * s0 + bAdjusted.w * s1,
349
- };
350
- },
351
-
352
- rotateVec3: (q: Quat, v: Vec3): Vec3 => {
353
- const qv = { x: q.x, y: q.y, z: q.z };
354
- const uv = vec3Math.cross(qv, v);
355
- const uuv = vec3Math.cross(qv, uv);
356
- return vec3Math.add(v, vec3Math.add(vec3Math.mul(uv, 2 * q.w), vec3Math.mul(uuv, 2)));
357
- },
358
-
359
- lookAt: (forward: Vec3, up: Vec3 = vec3(0, 1, 0)): Quat => {
360
- const f = vec3Math.normalize(forward);
361
- const r = vec3Math.normalize(vec3Math.cross(up, f));
362
- const u = vec3Math.cross(f, r);
363
-
364
- const trace = r.x + u.y + f.z;
365
- let q: Quat;
366
-
367
- if (trace > 0) {
368
- const s = 0.5 / Math.sqrt(trace + 1);
369
- q = {
370
- w: 0.25 / s,
371
- x: (u.z - f.y) * s,
372
- y: (f.x - r.z) * s,
373
- z: (r.y - u.x) * s,
374
- };
375
- } else if (r.x > u.y && r.x > f.z) {
376
- const s = 2 * Math.sqrt(1 + r.x - u.y - f.z);
377
- q = {
378
- w: (u.z - f.y) / s,
379
- x: 0.25 * s,
380
- y: (u.x + r.y) / s,
381
- z: (f.x + r.z) / s,
382
- };
383
- } else if (u.y > f.z) {
384
- const s = 2 * Math.sqrt(1 + u.y - r.x - f.z);
385
- q = {
386
- w: (f.x - r.z) / s,
387
- x: (u.x + r.y) / s,
388
- y: 0.25 * s,
389
- z: (f.y + u.z) / s,
390
- };
391
- } else {
392
- const s = 2 * Math.sqrt(1 + f.z - r.x - u.y);
393
- q = {
394
- w: (r.y - u.x) / s,
395
- x: (f.x + r.z) / s,
396
- y: (f.y + u.z) / s,
397
- z: 0.25 * s,
398
- };
399
- }
400
-
401
- return quatMath.normalize(q);
402
- },
403
- };
404
-
405
- // =============================================================================
406
- // AABB OPERATIONS
407
- // =============================================================================
408
-
409
- export const aabbMath = {
410
- contains: (aabb: AABB, point: Vec3): boolean => {
411
- return (
412
- point.x >= aabb.min.x &&
413
- point.x <= aabb.max.x &&
414
- point.y >= aabb.min.y &&
415
- point.y <= aabb.max.y &&
416
- point.z >= aabb.min.z &&
417
- point.z <= aabb.max.z
418
- );
419
- },
420
-
421
- intersects: (a: AABB, b: AABB): boolean => {
422
- return (
423
- a.min.x <= b.max.x &&
424
- a.max.x >= b.min.x &&
425
- a.min.y <= b.max.y &&
426
- a.max.y >= b.min.y &&
427
- a.min.z <= b.max.z &&
428
- a.max.z >= b.min.z
429
- );
430
- },
431
-
432
- center: (aabb: AABB): Vec3 => vec3Math.mul(vec3Math.add(aabb.min, aabb.max), 0.5),
433
-
434
- size: (aabb: AABB): Vec3 => vec3Math.sub(aabb.max, aabb.min),
435
-
436
- expand: (aabb: AABB, point: Vec3): AABB => ({
437
- min: vec3Math.min(aabb.min, point),
438
- max: vec3Math.max(aabb.max, point),
439
- }),
440
-
441
- merge: (a: AABB, b: AABB): AABB => ({
442
- min: vec3Math.min(a.min, b.min),
443
- max: vec3Math.max(a.max, b.max),
444
- }),
445
- };
446
-
447
- // =============================================================================
448
- // NOISE FUNCTIONS
449
- // =============================================================================
450
-
451
- // Simple permutation table for noise
452
- const perm = new Uint8Array(512);
453
- for (let i = 0; i < 256; i++) perm[i] = perm[i + 256] = i;
454
- for (let i = 255; i > 0; i--) {
455
- const j = Math.floor(Math.random() * (i + 1));
456
- [perm[i], perm[j]] = [perm[j], perm[i]];
457
- perm[i + 256] = perm[i];
458
- }
459
-
460
- function fade(t: number): number {
461
- return t * t * t * (t * (t * 6 - 15) + 10);
462
- }
463
-
464
- function grad(hash: number, x: number, y: number, z: number): number {
465
- const h = hash & 15;
466
- const u = h < 8 ? x : y;
467
- const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
468
- return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
469
- }
470
-
471
- export const noise = {
472
- /**
473
- * 3D Perlin noise (-1 to 1)
474
- */
475
- perlin3d: (x: number, y: number, z: number): number => {
476
- const X = Math.floor(x) & 255;
477
- const Y = Math.floor(y) & 255;
478
- const Z = Math.floor(z) & 255;
479
-
480
- x -= Math.floor(x);
481
- y -= Math.floor(y);
482
- z -= Math.floor(z);
483
-
484
- const u = fade(x);
485
- const v = fade(y);
486
- const w = fade(z);
487
-
488
- const A = perm[X] + Y;
489
- const AA = perm[A] + Z;
490
- const AB = perm[A + 1] + Z;
491
- const B = perm[X + 1] + Y;
492
- const BA = perm[B] + Z;
493
- const BB = perm[B + 1] + Z;
494
-
495
- return lerp(
496
- lerp(
497
- lerp(grad(perm[AA], x, y, z), grad(perm[BA], x - 1, y, z), u),
498
- lerp(grad(perm[AB], x, y - 1, z), grad(perm[BB], x - 1, y - 1, z), u),
499
- v
500
- ),
501
- lerp(
502
- lerp(grad(perm[AA + 1], x, y, z - 1), grad(perm[BA + 1], x - 1, y, z - 1), u),
503
- lerp(grad(perm[AB + 1], x, y - 1, z - 1), grad(perm[BB + 1], x - 1, y - 1, z - 1), u),
504
- v
505
- ),
506
- w
507
- );
508
- },
509
-
510
- /**
511
- * 2D Perlin noise (-1 to 1)
512
- */
513
- perlin2d: (x: number, y: number): number => {
514
- return noise.perlin3d(x, y, 0);
515
- },
516
-
517
- /**
518
- * Fractal Brownian Motion (fBm)
519
- */
520
- fbm: (
521
- x: number,
522
- y: number,
523
- z: number,
524
- octaves: number = 6,
525
- lacunarity: number = 2,
526
- gain: number = 0.5
527
- ): number => {
528
- let value = 0;
529
- let amplitude = 1;
530
- let frequency = 1;
531
- let maxValue = 0;
532
-
533
- for (let i = 0; i < octaves; i++) {
534
- value += amplitude * noise.perlin3d(x * frequency, y * frequency, z * frequency);
535
- maxValue += amplitude;
536
- amplitude *= gain;
537
- frequency *= lacunarity;
538
- }
539
-
540
- return value / maxValue;
541
- },
542
-
543
- /**
544
- * Simplex-like noise (approximation using perlin)
545
- */
546
- simplex: (x: number, y: number): number => {
547
- return noise.perlin2d(x * 1.2, y * 1.2);
548
- },
549
-
550
- /**
551
- * Worley/Cellular noise
552
- */
553
- worley: (x: number, y: number, z: number): number => {
554
- const xi = Math.floor(x);
555
- const yi = Math.floor(y);
556
- const zi = Math.floor(z);
557
-
558
- let minDist = Infinity;
559
-
560
- for (let i = -1; i <= 1; i++) {
561
- for (let j = -1; j <= 1; j++) {
562
- for (let k = -1; k <= 1; k++) {
563
- const cellX = xi + i;
564
- const cellY = yi + j;
565
- const cellZ = zi + k;
566
-
567
- // Pseudo-random point in cell
568
- const hash = perm[(perm[(perm[cellX & 255] + cellY) & 255] + cellZ) & 255];
569
- const px = cellX + hash / 255;
570
- const py = cellY + ((hash * 7) % 255) / 255;
571
- const pz = cellZ + ((hash * 13) % 255) / 255;
572
-
573
- const dist = (x - px) * (x - px) + (y - py) * (y - py) + (z - pz) * (z - pz);
574
- minDist = Math.min(minDist, dist);
575
- }
576
- }
577
- }
578
-
579
- return Math.sqrt(minDist);
580
- },
581
- };
582
-
583
- // =============================================================================
584
- // RANDOM
585
- // =============================================================================
586
-
587
- export const random = {
588
- /**
589
- * Random float between 0 and 1
590
- */
591
- float: (): number => Math.random(),
592
-
593
- /**
594
- * Random float in range [min, max)
595
- */
596
- range: (min: number, max: number): number => min + Math.random() * (max - min),
597
-
598
- /**
599
- * Random integer in range [min, max]
600
- */
601
- int: (min: number, max: number): number => Math.floor(min + Math.random() * (max - min + 1)),
602
-
603
- /**
604
- * Random boolean with probability
605
- */
606
- bool: (probability: number = 0.5): boolean => Math.random() < probability,
607
-
608
- /**
609
- * Random element from array
610
- */
611
- pick: <T>(array: T[]): T => array[Math.floor(Math.random() * array.length)],
612
-
613
- /**
614
- * Shuffle array (Fisher-Yates)
615
- */
616
- shuffle: <T>(array: T[]): T[] => {
617
- const result = [...array];
618
- for (let i = result.length - 1; i > 0; i--) {
619
- const j = Math.floor(Math.random() * (i + 1));
620
- [result[i], result[j]] = [result[j], result[i]];
621
- }
622
- return result;
623
- },
624
-
625
- /**
626
- * Random Vec3 in unit sphere
627
- */
628
- insideUnitSphere: (): Vec3 => {
629
- const theta = Math.random() * TAU;
630
- const phi = Math.acos(2 * Math.random() - 1);
631
- const r = Math.cbrt(Math.random());
632
- return {
633
- x: r * Math.sin(phi) * Math.cos(theta),
634
- y: r * Math.sin(phi) * Math.sin(theta),
635
- z: r * Math.cos(phi),
636
- };
637
- },
638
-
639
- /**
640
- * Random Vec3 on unit sphere surface
641
- */
642
- onUnitSphere: (): Vec3 => {
643
- const theta = Math.random() * TAU;
644
- const phi = Math.acos(2 * Math.random() - 1);
645
- return {
646
- x: Math.sin(phi) * Math.cos(theta),
647
- y: Math.sin(phi) * Math.sin(theta),
648
- z: Math.cos(phi),
649
- };
650
- },
651
-
652
- /**
653
- * Random Vec2 in unit circle
654
- */
655
- insideUnitCircle: (): Vec2 => {
656
- const theta = Math.random() * TAU;
657
- const r = Math.sqrt(Math.random());
658
- return {
659
- x: r * Math.cos(theta),
660
- y: r * Math.sin(theta),
661
- };
662
- },
663
-
664
- /**
665
- * Seeded random number generator
666
- */
667
- seeded: (seed: number) => {
668
- let s = seed;
669
- return () => {
670
- s = (s * 1103515245 + 12345) & 0x7fffffff;
671
- return s / 0x7fffffff;
672
- };
673
- },
674
- };