@vib3code/sdk 2.0.3-canary.45332e3 → 2.0.3-canary.4874bcf

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 (80) hide show
  1. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +2 -0
  2. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  3. package/DOCS/ARCHITECTURE.md +1 -0
  4. package/DOCS/CI_TESTING.md +2 -0
  5. package/DOCS/CLI_ONBOARDING.md +2 -0
  6. package/DOCS/CONTROL_REFERENCE.md +2 -0
  7. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
  8. package/DOCS/ENV_SETUP.md +2 -0
  9. package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
  10. package/DOCS/EXPANSION_DESIGN.md +979 -0
  11. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  12. package/DOCS/EXPORT_FORMATS.md +2 -0
  13. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  14. package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
  15. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
  16. package/DOCS/LICENSING_TIERS.md +2 -0
  17. package/DOCS/MASTER_PLAN_2026-01-31.md +2 -0
  18. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
  19. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  20. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  21. package/DOCS/PRODUCT_STRATEGY.md +2 -0
  22. package/DOCS/PROJECT_SETUP.md +2 -0
  23. package/DOCS/README.md +5 -3
  24. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
  25. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  26. package/DOCS/REPO_MANIFEST.md +2 -0
  27. package/DOCS/ROADMAP.md +2 -0
  28. package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
  29. package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
  30. package/DOCS/STATUS.md +2 -0
  31. package/DOCS/SYSTEM_INVENTORY.md +2 -0
  32. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  33. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
  35. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
  36. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
  37. package/DOCS/WEBGPU_STATUS.md +2 -0
  38. package/DOCS/XR_BENCHMARKS.md +2 -0
  39. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
  40. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
  41. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
  42. package/DOCS/archive/SESSION_014_PLAN.md +1 -195
  43. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
  44. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
  45. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
  46. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -38
  47. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
  48. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +2 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +2 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +2 -0
  52. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  53. package/DOCS/dev-tracks/README.md +2 -0
  54. package/package.json +2 -4
  55. package/src/cli/index.js +59 -5
  56. package/src/experimental/GameLoop.js +72 -0
  57. package/src/experimental/LatticePhysics.js +100 -0
  58. package/src/experimental/LiveDirector.js +143 -0
  59. package/src/experimental/PlayerController4D.js +154 -0
  60. package/src/experimental/VIB3Actor.js +138 -0
  61. package/src/experimental/VIB3Compositor.js +117 -0
  62. package/src/experimental/VIB3Link.js +122 -0
  63. package/src/experimental/VIB3Orchestrator.js +146 -0
  64. package/src/experimental/VIB3Universe.js +109 -0
  65. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  66. package/src/export/SVGExporter.js +9 -5
  67. package/src/features/CollectionManager.js +27 -9
  68. package/src/gallery/CollectionManager.js +27 -9
  69. package/src/geometry/generators/Crystal.js +2 -2
  70. package/src/geometry/warp/HypersphereCore.js +53 -24
  71. package/src/math/Mat4x4.js +418 -142
  72. package/src/math/Projection.js +57 -7
  73. package/src/math/Rotor4D.js +102 -73
  74. package/src/math/Vec4.js +265 -111
  75. package/src/quantum/QuantumVisualizer.js +28 -0
  76. package/src/scene/Node4D.js +74 -24
  77. package/src/testing/ProjectionClass.test.js +38 -0
  78. package/src/variations/VariationManager.js +6 -1
  79. package/src/wasm/WasmLoader.js +11 -6
  80. package/tools/update_projection.py +109 -0
@@ -18,6 +18,12 @@
18
18
  import { Vec4 } from './Vec4.js';
19
19
 
20
20
  export class Mat4x4 {
21
+ /**
22
+ * Internal token to skip initialization during construction
23
+ * @private
24
+ */
25
+ static UNINITIALIZED = {};
26
+
21
27
  /**
22
28
  * Create a new 4x4 matrix
23
29
  * Default is identity matrix
@@ -26,6 +32,8 @@ export class Mat4x4 {
26
32
  constructor(elements = null) {
27
33
  this.data = new Float32Array(16);
28
34
 
35
+ if (elements === Mat4x4.UNINITIALIZED) return;
36
+
29
37
  if (elements) {
30
38
  if (elements.length !== 16) {
31
39
  throw new Error('Mat4x4 requires exactly 16 elements');
@@ -40,17 +48,25 @@ export class Mat4x4 {
40
48
  }
41
49
  }
42
50
 
51
+ /**
52
+ * Reset to identity matrix
53
+ * @returns {Mat4x4} this
54
+ */
55
+ identity() {
56
+ const d = this.data;
57
+ d[0] = 1; d[1] = 0; d[2] = 0; d[3] = 0;
58
+ d[4] = 0; d[5] = 1; d[6] = 0; d[7] = 0;
59
+ d[8] = 0; d[9] = 0; d[10] = 1; d[11] = 0;
60
+ d[12] = 0; d[13] = 0; d[14] = 0; d[15] = 1;
61
+ return this;
62
+ }
63
+
43
64
  /**
44
65
  * Create identity matrix
45
66
  * @returns {Mat4x4}
46
67
  */
47
68
  static identity() {
48
- return new Mat4x4([
49
- 1, 0, 0, 0,
50
- 0, 1, 0, 0,
51
- 0, 0, 1, 0,
52
- 0, 0, 0, 1
53
- ]);
69
+ return new Mat4x4();
54
70
  }
55
71
 
56
72
  /**
@@ -58,7 +74,7 @@ export class Mat4x4 {
58
74
  * @returns {Mat4x4}
59
75
  */
60
76
  static zero() {
61
- return new Mat4x4(new Float32Array(16));
77
+ return new Mat4x4(Mat4x4.UNINITIALIZED);
62
78
  }
63
79
 
64
80
  /**
@@ -157,10 +173,11 @@ export class Mat4x4 {
157
173
  /**
158
174
  * Multiply two matrices
159
175
  * @param {Mat4x4} m - Right operand
176
+ * @param {Mat4x4} [target=null] - Optional target matrix to store result
160
177
  * @returns {Mat4x4} New matrix = this * m
161
178
  */
162
- multiply(m) {
163
- const out = new Mat4x4();
179
+ multiply(m, target = null) {
180
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
164
181
  const r = out.data;
165
182
  const a = this.data;
166
183
  const b = m.data;
@@ -259,16 +276,22 @@ export class Mat4x4 {
259
276
  /**
260
277
  * Transform a Vec4 by this matrix
261
278
  * @param {Vec4} v
279
+ * @param {Vec4} [target=null] - Optional target vector to store result
262
280
  * @returns {Vec4} Transformed vector
263
281
  */
264
- multiplyVec4(v) {
282
+ multiplyVec4(v, target = null) {
265
283
  const m = this.data;
266
- return new Vec4(
267
- m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12] * v.w,
268
- m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13] * v.w,
269
- m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14] * v.w,
270
- m[3] * v.x + m[7] * v.y + m[11] * v.z + m[15] * v.w
271
- );
284
+ const out = target || new Vec4();
285
+
286
+ // Cache components to support aliasing (target === v)
287
+ const x = v.x, y = v.y, z = v.z, w = v.w;
288
+
289
+ out.x = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
290
+ out.y = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
291
+ out.z = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
292
+ out.w = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
293
+
294
+ return out;
272
295
  }
273
296
 
274
297
  /**
@@ -310,41 +333,57 @@ export class Mat4x4 {
310
333
  /**
311
334
  * Add another matrix
312
335
  * @param {Mat4x4} m
336
+ * @param {Mat4x4} [target=null] - Optional target matrix
313
337
  * @returns {Mat4x4} New matrix
314
338
  */
315
- add(m) {
316
- const result = new Float32Array(16);
339
+ add(m, target = null) {
340
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
341
+ const r = out.data;
342
+ const a = this.data;
343
+ const b = m.data;
344
+
317
345
  for (let i = 0; i < 16; i++) {
318
- result[i] = this.data[i] + m.data[i];
346
+ r[i] = a[i] + b[i];
319
347
  }
320
- return new Mat4x4(result);
348
+ return out;
321
349
  }
322
350
 
323
351
  /**
324
352
  * Multiply by scalar
325
353
  * @param {number} s
354
+ * @param {Mat4x4} [target=null] - Optional target matrix
326
355
  * @returns {Mat4x4} New matrix
327
356
  */
328
- scale(s) {
329
- const result = new Float32Array(16);
357
+ scale(s, target = null) {
358
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
359
+ const r = out.data;
360
+ const a = this.data;
361
+
330
362
  for (let i = 0; i < 16; i++) {
331
- result[i] = this.data[i] * s;
363
+ r[i] = a[i] * s;
332
364
  }
333
- return new Mat4x4(result);
365
+ return out;
334
366
  }
335
367
 
336
368
  /**
337
369
  * Transpose matrix
370
+ * @param {Mat4x4} [target=null] - Optional target matrix
338
371
  * @returns {Mat4x4} New transposed matrix
339
372
  */
340
- transpose() {
373
+ transpose(target = null) {
341
374
  const m = this.data;
342
- return new Mat4x4([
343
- m[0], m[4], m[8], m[12],
344
- m[1], m[5], m[9], m[13],
345
- m[2], m[6], m[10], m[14],
346
- m[3], m[7], m[11], m[15]
347
- ]);
375
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
376
+ const r = out.data;
377
+ // If target is same as source, use intermediate or careful swap
378
+ if (target === this) {
379
+ return this.transposeInPlace();
380
+ }
381
+
382
+ r[0] = m[0]; r[4] = m[1]; r[8] = m[2]; r[12] = m[3];
383
+ r[1] = m[4]; r[5] = m[5]; r[9] = m[6]; r[13] = m[7];
384
+ r[2] = m[8]; r[6] = m[9]; r[10] = m[10]; r[14] = m[11];
385
+ r[3] = m[12]; r[7] = m[13]; r[11] = m[14]; r[15] = m[15];
386
+ return out;
348
387
  }
349
388
 
350
389
  /**
@@ -395,61 +434,85 @@ export class Mat4x4 {
395
434
 
396
435
  /**
397
436
  * Calculate inverse matrix
437
+ * @param {Mat4x4} [target=null] - Optional target matrix
398
438
  * @returns {Mat4x4|null} Inverse matrix or null if singular
399
439
  */
400
- inverse() {
440
+ inverse(target = null) {
401
441
  const m = this.data;
402
- const inv = new Float32Array(16);
442
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
443
+ const inv = out.data;
444
+
445
+ // Note: For in-place inversion (target === this), we need to be careful.
446
+ // The standard algorithm uses input values for every output cell.
447
+ // We can check for aliasing or use local variables if we wanted full safety,
448
+ // but simplest is to compute to temp if aliased, or just computing to the array directly works
449
+ // IF we cache everything first. But here we are writing to `inv` index by index.
450
+ // If inv === m, writing inv[0] destroys m[0] which is needed for inv[5] etc.
451
+ // So aliasing is NOT safe with this direct write approach.
452
+
453
+ // Handle aliasing by cloning first if needed, or using temp array.
454
+ // Since we want performance, let's detect aliasing.
455
+ let sourceData = m;
456
+ if (target === this) {
457
+ // Copy source data to temp array so we can write to 'this.data' safely
458
+ // We can't avoid allocation entirely in this specific edge case easily without unrolling everything into locals,
459
+ // which is huge for 4x4 inverse.
460
+ // Using a static temp buffer would be unsafe for threading/recursion (not an issue in JS single thread usually but still).
461
+ // Let's just clone the source data for the calculation.
462
+ sourceData = new Float32Array(m);
463
+ }
464
+
465
+ const s = sourceData;
403
466
 
404
- inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] +
405
- m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
467
+ inv[0] = s[5] * s[10] * s[15] - s[5] * s[11] * s[14] - s[9] * s[6] * s[15] +
468
+ s[9] * s[7] * s[14] + s[13] * s[6] * s[11] - s[13] * s[7] * s[10];
406
469
 
407
- inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] -
408
- m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
470
+ inv[4] = -s[4] * s[10] * s[15] + s[4] * s[11] * s[14] + s[8] * s[6] * s[15] -
471
+ s[8] * s[7] * s[14] - s[12] * s[6] * s[11] + s[12] * s[7] * s[10];
409
472
 
410
- inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] +
411
- m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
473
+ inv[8] = s[4] * s[9] * s[15] - s[4] * s[11] * s[13] - s[8] * s[5] * s[15] +
474
+ s[8] * s[7] * s[13] + s[12] * s[5] * s[11] - s[12] * s[7] * s[9];
412
475
 
413
- inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] -
414
- m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
476
+ inv[12] = -s[4] * s[9] * s[14] + s[4] * s[10] * s[13] + s[8] * s[5] * s[14] -
477
+ s[8] * s[6] * s[13] - s[12] * s[5] * s[10] + s[12] * s[6] * s[9];
415
478
 
416
- inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] -
417
- m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
479
+ inv[1] = -s[1] * s[10] * s[15] + s[1] * s[11] * s[14] + s[9] * s[2] * s[15] -
480
+ s[9] * s[3] * s[14] - s[13] * s[2] * s[11] + s[13] * s[3] * s[10];
418
481
 
419
- inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] +
420
- m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
482
+ inv[5] = s[0] * s[10] * s[15] - s[0] * s[11] * s[14] - s[8] * s[2] * s[15] +
483
+ s[8] * s[3] * s[14] + s[12] * s[2] * s[11] - s[12] * s[3] * s[10];
421
484
 
422
- inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] -
423
- m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
485
+ inv[9] = -s[0] * s[9] * s[15] + s[0] * s[11] * s[13] + s[8] * s[1] * s[15] -
486
+ s[8] * s[3] * s[13] - s[12] * s[1] * s[11] + s[12] * s[3] * s[9];
424
487
 
425
- inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] +
426
- m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
488
+ inv[13] = s[0] * s[9] * s[14] - s[0] * s[10] * s[13] - s[8] * s[1] * s[14] +
489
+ s[8] * s[2] * s[13] + s[12] * s[1] * s[10] - s[12] * s[2] * s[9];
427
490
 
428
- inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] +
429
- m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
491
+ inv[2] = s[1] * s[6] * s[15] - s[1] * s[7] * s[14] - s[5] * s[2] * s[15] +
492
+ s[5] * s[3] * s[14] + s[13] * s[2] * s[7] - s[13] * s[3] * s[6];
430
493
 
431
- inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] -
432
- m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
494
+ inv[6] = -s[0] * s[6] * s[15] + s[0] * s[7] * s[14] + s[4] * s[2] * s[15] -
495
+ s[4] * s[3] * s[14] - s[12] * s[2] * s[7] + s[12] * s[3] * s[6];
433
496
 
434
- inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] +
435
- m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
497
+ inv[10] = s[0] * s[5] * s[15] - s[0] * s[7] * s[13] - s[4] * s[1] * s[15] +
498
+ s[4] * s[3] * s[13] + s[12] * s[1] * s[7] - s[12] * s[3] * s[5];
436
499
 
437
- inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] -
438
- m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
500
+ inv[14] = -s[0] * s[5] * s[14] + s[0] * s[6] * s[13] + s[4] * s[1] * s[14] -
501
+ s[4] * s[2] * s[13] - s[12] * s[1] * s[6] + s[12] * s[2] * s[5];
439
502
 
440
- inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] -
441
- m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
503
+ inv[3] = -s[1] * s[6] * s[11] + s[1] * s[7] * s[10] + s[5] * s[2] * s[11] -
504
+ s[5] * s[3] * s[10] - s[9] * s[2] * s[7] + s[9] * s[3] * s[6];
442
505
 
443
- inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] +
444
- m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
506
+ inv[7] = s[0] * s[6] * s[11] - s[0] * s[7] * s[10] - s[4] * s[2] * s[11] +
507
+ s[4] * s[3] * s[10] + s[8] * s[2] * s[7] - s[8] * s[3] * s[6];
445
508
 
446
- inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] -
447
- m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
509
+ inv[11] = -s[0] * s[5] * s[11] + s[0] * s[7] * s[9] + s[4] * s[1] * s[11] -
510
+ s[4] * s[3] * s[9] - s[8] * s[1] * s[7] + s[8] * s[3] * s[5];
448
511
 
449
- inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] +
450
- m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
512
+ inv[15] = s[0] * s[5] * s[10] - s[0] * s[6] * s[9] - s[4] * s[1] * s[10] +
513
+ s[4] * s[2] * s[9] + s[8] * s[1] * s[6] - s[8] * s[2] * s[5];
451
514
 
452
- const det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
515
+ const det = s[0] * inv[0] + s[1] * inv[4] + s[2] * inv[8] + s[3] * inv[12];
453
516
 
454
517
  if (Math.abs(det) < 1e-10) {
455
518
  return null; // Singular matrix
@@ -460,7 +523,7 @@ export class Mat4x4 {
460
523
  inv[i] *= invDet;
461
524
  }
462
525
 
463
- return new Mat4x4(inv);
526
+ return out;
464
527
  }
465
528
 
466
529
  /**
@@ -547,103 +610,279 @@ export class Mat4x4 {
547
610
  return new Mat4x4(json.data);
548
611
  }
549
612
 
613
+ // ========== IN-PLACE ROTATIONS ==========
614
+
615
+ /**
616
+ * Rotate in XY plane in place
617
+ * @param {number} angle
618
+ * @returns {Mat4x4} this
619
+ */
620
+ rotateXY(angle) {
621
+ const c = Math.cos(angle);
622
+ const s = Math.sin(angle);
623
+ const m = this.data;
624
+
625
+ for (let i = 0; i < 4; i++) {
626
+ const a0 = m[i]; // Col 0
627
+ const a1 = m[i + 4]; // Col 1
628
+ m[i] = a0 * c + a1 * s;
629
+ m[i + 4] = -a0 * s + a1 * c;
630
+ }
631
+ return this;
632
+ }
633
+
634
+ /**
635
+ * Rotate in XZ plane in place
636
+ * @param {number} angle
637
+ * @returns {Mat4x4} this
638
+ */
639
+ rotateXZ(angle) {
640
+ const c = Math.cos(angle);
641
+ const s = Math.sin(angle);
642
+ const m = this.data;
643
+
644
+ for (let i = 0; i < 4; i++) {
645
+ const a0 = m[i]; // Col 0
646
+ const a2 = m[i + 8]; // Col 2
647
+ m[i] = a0 * c - a2 * s;
648
+ m[i + 8] = a0 * s + a2 * c;
649
+ }
650
+ return this;
651
+ }
652
+
653
+ /**
654
+ * Rotate in YZ plane in place
655
+ * @param {number} angle
656
+ * @returns {Mat4x4} this
657
+ */
658
+ rotateYZ(angle) {
659
+ const c = Math.cos(angle);
660
+ const s = Math.sin(angle);
661
+ const m = this.data;
662
+
663
+ for (let i = 0; i < 4; i++) {
664
+ const a1 = m[i + 4]; // Col 1
665
+ const a2 = m[i + 8]; // Col 2
666
+ m[i + 4] = a1 * c + a2 * s;
667
+ m[i + 8] = -a1 * s + a2 * c;
668
+ }
669
+ return this;
670
+ }
671
+
672
+ /**
673
+ * Rotate in XW plane in place
674
+ * @param {number} angle
675
+ * @returns {Mat4x4} this
676
+ */
677
+ rotateXW(angle) {
678
+ const c = Math.cos(angle);
679
+ const s = Math.sin(angle);
680
+ const m = this.data;
681
+
682
+ for (let i = 0; i < 4; i++) {
683
+ const a0 = m[i]; // Col 0
684
+ const a3 = m[i + 12]; // Col 3
685
+ m[i] = a0 * c + a3 * s;
686
+ m[i + 12] = -a0 * s + a3 * c;
687
+ }
688
+ return this;
689
+ }
690
+
691
+ /**
692
+ * Rotate in YW plane in place
693
+ * @param {number} angle
694
+ * @returns {Mat4x4} this
695
+ */
696
+ rotateYW(angle) {
697
+ const c = Math.cos(angle);
698
+ const s = Math.sin(angle);
699
+ const m = this.data;
700
+
701
+ for (let i = 0; i < 4; i++) {
702
+ const a1 = m[i + 4]; // Col 1
703
+ const a3 = m[i + 12]; // Col 3
704
+ m[i + 4] = a1 * c + a3 * s;
705
+ m[i + 12] = -a1 * s + a3 * c;
706
+ }
707
+ return this;
708
+ }
709
+
710
+ /**
711
+ * Rotate in ZW plane in place
712
+ * @param {number} angle
713
+ * @returns {Mat4x4} this
714
+ */
715
+ rotateZW(angle) {
716
+ const c = Math.cos(angle);
717
+ const s = Math.sin(angle);
718
+ const m = this.data;
719
+
720
+ for (let i = 0; i < 4; i++) {
721
+ const a2 = m[i + 8]; // Col 2
722
+ const a3 = m[i + 12]; // Col 3
723
+ m[i + 8] = a2 * c + a3 * s;
724
+ m[i + 12] = -a2 * s + a3 * c;
725
+ }
726
+ return this;
727
+ }
728
+
550
729
  // ========== ROTATION MATRICES FOR ALL 6 PLANES ==========
551
730
 
552
731
  /**
553
732
  * Create XY plane rotation matrix (standard Z-axis rotation in 3D)
554
733
  * @param {number} angle - Rotation angle in radians
734
+ * @param {Mat4x4} [target=null] - Optional target matrix
555
735
  * @returns {Mat4x4}
556
736
  */
557
- static rotationXY(angle) {
737
+ static rotationXY(angle, target = null) {
558
738
  const c = Math.cos(angle);
559
739
  const s = Math.sin(angle);
560
- return new Mat4x4([
561
- c, s, 0, 0,
562
- -s, c, 0, 0,
563
- 0, 0, 1, 0,
564
- 0, 0, 0, 1
565
- ]);
740
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
741
+ const r = out.data;
742
+
743
+ if (target) {
744
+ r[0] = c; r[1] = s; r[2] = 0; r[3] = 0;
745
+ r[4] = -s; r[5] = c; r[6] = 0; r[7] = 0;
746
+ r[8] = 0; r[9] = 0; r[10] = 1; r[11] = 0;
747
+ r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
748
+ } else {
749
+ r[0] = c; r[1] = s;
750
+ r[4] = -s; r[5] = c;
751
+ r[10] = 1;
752
+ r[15] = 1;
753
+ }
754
+ return out;
566
755
  }
567
756
 
568
757
  /**
569
758
  * Create XZ plane rotation matrix (standard Y-axis rotation in 3D)
570
759
  * @param {number} angle - Rotation angle in radians
760
+ * @param {Mat4x4} [target=null] - Optional target matrix
571
761
  * @returns {Mat4x4}
572
762
  */
573
- static rotationXZ(angle) {
763
+ static rotationXZ(angle, target = null) {
574
764
  const c = Math.cos(angle);
575
765
  const s = Math.sin(angle);
576
- return new Mat4x4([
577
- c, 0, -s, 0,
578
- 0, 1, 0, 0,
579
- s, 0, c, 0,
580
- 0, 0, 0, 1
581
- ]);
766
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
767
+ const r = out.data;
768
+
769
+ if (target) {
770
+ r[0] = c; r[1] = 0; r[2] = -s; r[3] = 0;
771
+ r[4] = 0; r[5] = 1; r[6] = 0; r[7] = 0;
772
+ r[8] = s; r[9] = 0; r[10] = c; r[11] = 0;
773
+ r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
774
+ } else {
775
+ r[0] = c; r[2] = -s;
776
+ r[5] = 1;
777
+ r[8] = s; r[10] = c;
778
+ r[15] = 1;
779
+ }
780
+ return out;
582
781
  }
583
782
 
584
783
  /**
585
784
  * Create YZ plane rotation matrix (standard X-axis rotation in 3D)
586
785
  * @param {number} angle - Rotation angle in radians
786
+ * @param {Mat4x4} [target=null] - Optional target matrix
587
787
  * @returns {Mat4x4}
588
788
  */
589
- static rotationYZ(angle) {
789
+ static rotationYZ(angle, target = null) {
590
790
  const c = Math.cos(angle);
591
791
  const s = Math.sin(angle);
592
- return new Mat4x4([
593
- 1, 0, 0, 0,
594
- 0, c, s, 0,
595
- 0, -s, c, 0,
596
- 0, 0, 0, 1
597
- ]);
792
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
793
+ const r = out.data;
794
+
795
+ if (target) {
796
+ r[0] = 1; r[1] = 0; r[2] = 0; r[3] = 0;
797
+ r[4] = 0; r[5] = c; r[6] = s; r[7] = 0;
798
+ r[8] = 0; r[9] = -s; r[10] = c; r[11] = 0;
799
+ r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
800
+ } else {
801
+ r[0] = 1;
802
+ r[5] = c; r[6] = s;
803
+ r[9] = -s; r[10] = c;
804
+ r[15] = 1;
805
+ }
806
+ return out;
598
807
  }
599
808
 
600
809
  /**
601
810
  * Create XW plane rotation matrix (4D hyperspace rotation)
602
811
  * Creates "inside-out" effect when w approaches viewer
603
812
  * @param {number} angle - Rotation angle in radians
813
+ * @param {Mat4x4} [target=null] - Optional target matrix
604
814
  * @returns {Mat4x4}
605
815
  */
606
- static rotationXW(angle) {
816
+ static rotationXW(angle, target = null) {
607
817
  const c = Math.cos(angle);
608
818
  const s = Math.sin(angle);
609
- return new Mat4x4([
610
- c, 0, 0, s,
611
- 0, 1, 0, 0,
612
- 0, 0, 1, 0,
613
- -s, 0, 0, c
614
- ]);
819
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
820
+ const r = out.data;
821
+
822
+ if (target) {
823
+ r[0] = c; r[1] = 0; r[2] = 0; r[3] = s;
824
+ r[4] = 0; r[5] = 1; r[6] = 0; r[7] = 0;
825
+ r[8] = 0; r[9] = 0; r[10] = 1; r[11] = 0;
826
+ r[12] = -s; r[13] = 0; r[14] = 0; r[15] = c;
827
+ } else {
828
+ r[0] = c; r[3] = s;
829
+ r[5] = 1;
830
+ r[10] = 1;
831
+ r[12] = -s; r[15] = c;
832
+ }
833
+ return out;
615
834
  }
616
835
 
617
836
  /**
618
837
  * Create YW plane rotation matrix (4D hyperspace rotation)
619
838
  * @param {number} angle - Rotation angle in radians
839
+ * @param {Mat4x4} [target=null] - Optional target matrix
620
840
  * @returns {Mat4x4}
621
841
  */
622
- static rotationYW(angle) {
842
+ static rotationYW(angle, target = null) {
623
843
  const c = Math.cos(angle);
624
844
  const s = Math.sin(angle);
625
- return new Mat4x4([
626
- 1, 0, 0, 0,
627
- 0, c, 0, s,
628
- 0, 0, 1, 0,
629
- 0, -s, 0, c
630
- ]);
845
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
846
+ const r = out.data;
847
+
848
+ if (target) {
849
+ r[0] = 1; r[1] = 0; r[2] = 0; r[3] = 0;
850
+ r[4] = 0; r[5] = c; r[6] = 0; r[7] = s;
851
+ r[8] = 0; r[9] = 0; r[10] = 1; r[11] = 0;
852
+ r[12] = 0; r[13] = -s; r[14] = 0; r[15] = c;
853
+ } else {
854
+ r[0] = 1;
855
+ r[5] = c; r[7] = s;
856
+ r[10] = 1;
857
+ r[13] = -s; r[15] = c;
858
+ }
859
+ return out;
631
860
  }
632
861
 
633
862
  /**
634
863
  * Create ZW plane rotation matrix (4D hyperspace rotation)
635
864
  * @param {number} angle - Rotation angle in radians
865
+ * @param {Mat4x4} [target=null] - Optional target matrix
636
866
  * @returns {Mat4x4}
637
867
  */
638
- static rotationZW(angle) {
868
+ static rotationZW(angle, target = null) {
639
869
  const c = Math.cos(angle);
640
870
  const s = Math.sin(angle);
641
- return new Mat4x4([
642
- 1, 0, 0, 0,
643
- 0, 1, 0, 0,
644
- 0, 0, c, s,
645
- 0, 0, -s, c
646
- ]);
871
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
872
+ const r = out.data;
873
+
874
+ if (target) {
875
+ r[0] = 1; r[1] = 0; r[2] = 0; r[3] = 0;
876
+ r[4] = 0; r[5] = 1; r[6] = 0; r[7] = 0;
877
+ r[8] = 0; r[9] = 0; r[10] = c; r[11] = s;
878
+ r[12] = 0; r[13] = 0; r[14] = -s; r[15] = c;
879
+ } else {
880
+ r[0] = 1;
881
+ r[5] = 1;
882
+ r[10] = c; r[11] = s;
883
+ r[14] = -s; r[15] = c;
884
+ }
885
+ return out;
647
886
  }
648
887
 
649
888
  /**
@@ -669,24 +908,58 @@ export class Mat4x4 {
669
908
  * Create combined rotation matrix from all 6 angles
670
909
  * Order: XY, XZ, YZ, XW, YW, ZW
671
910
  *
672
- * @param {object} angles - Rotation angles
673
- * @param {number} [angles.xy=0] - XY plane rotation
674
- * @param {number} [angles.xz=0] - XZ plane rotation
675
- * @param {number} [angles.yz=0] - YZ plane rotation
676
- * @param {number} [angles.xw=0] - XW plane rotation
677
- * @param {number} [angles.yw=0] - YW plane rotation
678
- * @param {number} [angles.zw=0] - ZW plane rotation
911
+ * Supports two signatures:
912
+ * 1. rotationFromAngles(angles, target?)
913
+ * 2. rotationFromAngles(xy, xz, yz, xw, yw, zw, target?)
914
+ *
915
+ * @param {object|number} anglesOrXY - Rotation angles object OR XY angle
916
+ * @param {number|Mat4x4} [xzOrTarget] - XZ angle OR target matrix
917
+ * @param {number} [yz=0] - YZ angle
918
+ * @param {number} [xw=0] - XW angle
919
+ * @param {number} [yw=0] - YW angle
920
+ * @param {number} [zw=0] - ZW angle
921
+ * @param {Mat4x4} [target=null] - Target matrix (if using 6-arg signature)
679
922
  * @returns {Mat4x4}
680
923
  */
681
- static rotationFromAngles(angles) {
682
- let result = Mat4x4.identity();
924
+ static rotationFromAngles(anglesOrXY, xzOrTarget, yz, xw, yw, zw, target) {
925
+ let xy = 0, xz = 0;
926
+ let _yz = 0, _xw = 0, _yw = 0, _zw = 0;
927
+ let out = null;
928
+
929
+ if (typeof anglesOrXY === 'number') {
930
+ // Signature: (xy, xz, yz, xw, yw, zw, target)
931
+ xy = anglesOrXY;
932
+ xz = typeof xzOrTarget === 'number' ? xzOrTarget : 0;
933
+ _yz = yz || 0;
934
+ _xw = xw || 0;
935
+ _yw = yw || 0;
936
+ _zw = zw || 0;
937
+ out = target || null;
938
+ } else {
939
+ // Signature: (angles, target)
940
+ const angles = anglesOrXY || {};
941
+ xy = angles.xy || 0;
942
+ xz = angles.xz || 0;
943
+ _yz = angles.yz || 0;
944
+ _xw = angles.xw || 0;
945
+ _yw = angles.yw || 0;
946
+ _zw = angles.zw || 0;
947
+ // The second argument is the target in this case
948
+ // Use duck typing or check constructor name to avoid circular dependency issues if any
949
+ if (xzOrTarget && typeof xzOrTarget === 'object' && xzOrTarget.data) {
950
+ out = xzOrTarget;
951
+ }
952
+ }
953
+
954
+ const result = out || new Mat4x4(); // Default constructor is identity
955
+ if (out) result.identity(); // Reset if reused
683
956
 
684
- if (angles.xy) result = result.multiply(Mat4x4.rotationXY(angles.xy));
685
- if (angles.xz) result = result.multiply(Mat4x4.rotationXZ(angles.xz));
686
- if (angles.yz) result = result.multiply(Mat4x4.rotationYZ(angles.yz));
687
- if (angles.xw) result = result.multiply(Mat4x4.rotationXW(angles.xw));
688
- if (angles.yw) result = result.multiply(Mat4x4.rotationYW(angles.yw));
689
- if (angles.zw) result = result.multiply(Mat4x4.rotationZW(angles.zw));
957
+ if (xy) result.rotateXY(xy);
958
+ if (xz) result.rotateXZ(xz);
959
+ if (_yz) result.rotateYZ(_yz);
960
+ if (_xw) result.rotateXW(_xw);
961
+ if (_yw) result.rotateYW(_yw);
962
+ if (_zw) result.rotateZW(_zw);
690
963
 
691
964
  return result;
692
965
  }
@@ -715,12 +988,13 @@ export class Mat4x4 {
715
988
  * @returns {Mat4x4}
716
989
  */
717
990
  static uniformScale(s) {
718
- return new Mat4x4([
719
- s, 0, 0, 0,
720
- 0, s, 0, 0,
721
- 0, 0, s, 0,
722
- 0, 0, 0, s
723
- ]);
991
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
992
+ const r = out.data;
993
+ r[0] = s;
994
+ r[5] = s;
995
+ r[10] = s;
996
+ r[15] = s;
997
+ return out;
724
998
  }
725
999
 
726
1000
  /**
@@ -732,12 +1006,13 @@ export class Mat4x4 {
732
1006
  * @returns {Mat4x4}
733
1007
  */
734
1008
  static scale(sx, sy, sz, sw = 1) {
735
- return new Mat4x4([
736
- sx, 0, 0, 0,
737
- 0, sy, 0, 0,
738
- 0, 0, sz, 0,
739
- 0, 0, 0, sw
740
- ]);
1009
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
1010
+ const r = out.data;
1011
+ r[0] = sx;
1012
+ r[5] = sy;
1013
+ r[10] = sz;
1014
+ r[15] = sw;
1015
+ return out;
741
1016
  }
742
1017
 
743
1018
  /**
@@ -753,12 +1028,13 @@ export class Mat4x4 {
753
1028
  static translation(tx, ty, tz, tw = 0) {
754
1029
  // For true 4D translation, you need 5D homogeneous coordinates
755
1030
  // This is a placeholder that adds the translation to the W column
756
- return new Mat4x4([
757
- 1, 0, 0, 0,
758
- 0, 1, 0, 0,
759
- 0, 0, 1, 0,
760
- tx, ty, tz, 1 + tw
761
- ]);
1031
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
1032
+ const r = out.data;
1033
+ r[0] = 1;
1034
+ r[5] = 1;
1035
+ r[10] = 1;
1036
+ r[12] = tx; r[13] = ty; r[14] = tz; r[15] = 1 + tw;
1037
+ return out;
762
1038
  }
763
1039
  }
764
1040