@vib3code/sdk 2.0.3-canary.590fbae → 2.0.3-canary.69d53b3

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 (69) 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 +2 -0
  53. package/DOCS/dev-tracks/README.md +2 -0
  54. package/package.json +1 -1
  55. package/src/experimental/GameLoop.js +72 -0
  56. package/src/experimental/LatticePhysics.js +100 -0
  57. package/src/experimental/LiveDirector.js +143 -0
  58. package/src/experimental/PlayerController4D.js +154 -0
  59. package/src/experimental/VIB3Actor.js +138 -0
  60. package/src/experimental/VIB3Compositor.js +117 -0
  61. package/src/experimental/VIB3Link.js +122 -0
  62. package/src/experimental/VIB3Orchestrator.js +146 -0
  63. package/src/experimental/VIB3Universe.js +109 -0
  64. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  65. package/src/geometry/generators/Crystal.js +2 -2
  66. package/src/math/Mat4x4.js +238 -92
  67. package/src/math/Rotor4D.js +69 -46
  68. package/src/math/Vec4.js +200 -103
  69. package/src/scene/Node4D.js +74 -24
@@ -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');
@@ -45,12 +53,7 @@ export class Mat4x4 {
45
53
  * @returns {Mat4x4}
46
54
  */
47
55
  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
- ]);
56
+ return new Mat4x4();
54
57
  }
55
58
 
56
59
  /**
@@ -58,7 +61,7 @@ export class Mat4x4 {
58
61
  * @returns {Mat4x4}
59
62
  */
60
63
  static zero() {
61
- return new Mat4x4(new Float32Array(16));
64
+ return new Mat4x4(Mat4x4.UNINITIALIZED);
62
65
  }
63
66
 
64
67
  /**
@@ -157,10 +160,11 @@ export class Mat4x4 {
157
160
  /**
158
161
  * Multiply two matrices
159
162
  * @param {Mat4x4} m - Right operand
163
+ * @param {Mat4x4} [target=null] - Optional target matrix to store result
160
164
  * @returns {Mat4x4} New matrix = this * m
161
165
  */
162
- multiply(m) {
163
- const out = new Mat4x4();
166
+ multiply(m, target = null) {
167
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
164
168
  const r = out.data;
165
169
  const a = this.data;
166
170
  const b = m.data;
@@ -259,16 +263,22 @@ export class Mat4x4 {
259
263
  /**
260
264
  * Transform a Vec4 by this matrix
261
265
  * @param {Vec4} v
266
+ * @param {Vec4} [target=null] - Optional target vector to store result
262
267
  * @returns {Vec4} Transformed vector
263
268
  */
264
- multiplyVec4(v) {
269
+ multiplyVec4(v, target = null) {
265
270
  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
- );
271
+ const out = target || new Vec4();
272
+
273
+ // Cache components to support aliasing (target === v)
274
+ const x = v.x, y = v.y, z = v.z, w = v.w;
275
+
276
+ out.x = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
277
+ out.y = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
278
+ out.z = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
279
+ out.w = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
280
+
281
+ return out;
272
282
  }
273
283
 
274
284
  /**
@@ -310,27 +320,36 @@ export class Mat4x4 {
310
320
  /**
311
321
  * Add another matrix
312
322
  * @param {Mat4x4} m
323
+ * @param {Mat4x4} [target=null] - Optional target matrix
313
324
  * @returns {Mat4x4} New matrix
314
325
  */
315
- add(m) {
316
- const result = new Float32Array(16);
326
+ add(m, target = null) {
327
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
328
+ const r = out.data;
329
+ const a = this.data;
330
+ const b = m.data;
331
+
317
332
  for (let i = 0; i < 16; i++) {
318
- result[i] = this.data[i] + m.data[i];
333
+ r[i] = a[i] + b[i];
319
334
  }
320
- return new Mat4x4(result);
335
+ return out;
321
336
  }
322
337
 
323
338
  /**
324
339
  * Multiply by scalar
325
340
  * @param {number} s
341
+ * @param {Mat4x4} [target=null] - Optional target matrix
326
342
  * @returns {Mat4x4} New matrix
327
343
  */
328
- scale(s) {
329
- const result = new Float32Array(16);
344
+ scale(s, target = null) {
345
+ const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
346
+ const r = out.data;
347
+ const a = this.data;
348
+
330
349
  for (let i = 0; i < 16; i++) {
331
- result[i] = this.data[i] * s;
350
+ r[i] = a[i] * s;
332
351
  }
333
- return new Mat4x4(result);
352
+ return out;
334
353
  }
335
354
 
336
355
  /**
@@ -339,12 +358,13 @@ export class Mat4x4 {
339
358
  */
340
359
  transpose() {
341
360
  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
- ]);
361
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
362
+ const r = out.data;
363
+ r[0] = m[0]; r[4] = m[1]; r[8] = m[2]; r[12] = m[3];
364
+ r[1] = m[4]; r[5] = m[5]; r[9] = m[6]; r[13] = m[7];
365
+ r[2] = m[8]; r[6] = m[9]; r[10] = m[10]; r[14] = m[11];
366
+ r[3] = m[12]; r[7] = m[13]; r[11] = m[14]; r[15] = m[15];
367
+ return out;
348
368
  }
349
369
 
350
370
  /**
@@ -399,7 +419,8 @@ export class Mat4x4 {
399
419
  */
400
420
  inverse() {
401
421
  const m = this.data;
402
- const inv = new Float32Array(16);
422
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
423
+ const inv = out.data;
403
424
 
404
425
  inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] +
405
426
  m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
@@ -460,7 +481,7 @@ export class Mat4x4 {
460
481
  inv[i] *= invDet;
461
482
  }
462
483
 
463
- return new Mat4x4(inv);
484
+ return out;
464
485
  }
465
486
 
466
487
  /**
@@ -547,6 +568,122 @@ export class Mat4x4 {
547
568
  return new Mat4x4(json.data);
548
569
  }
549
570
 
571
+ // ========== IN-PLACE ROTATIONS ==========
572
+
573
+ /**
574
+ * Rotate in XY plane in place
575
+ * @param {number} angle
576
+ * @returns {Mat4x4} this
577
+ */
578
+ rotateXY(angle) {
579
+ const c = Math.cos(angle);
580
+ const s = Math.sin(angle);
581
+ const m = this.data;
582
+
583
+ for (let i = 0; i < 4; i++) {
584
+ const a0 = m[i]; // Col 0
585
+ const a1 = m[i + 4]; // Col 1
586
+ m[i] = a0 * c + a1 * s;
587
+ m[i + 4] = -a0 * s + a1 * c;
588
+ }
589
+ return this;
590
+ }
591
+
592
+ /**
593
+ * Rotate in XZ plane in place
594
+ * @param {number} angle
595
+ * @returns {Mat4x4} this
596
+ */
597
+ rotateXZ(angle) {
598
+ const c = Math.cos(angle);
599
+ const s = Math.sin(angle);
600
+ const m = this.data;
601
+
602
+ for (let i = 0; i < 4; i++) {
603
+ const a0 = m[i]; // Col 0
604
+ const a2 = m[i + 8]; // Col 2
605
+ m[i] = a0 * c - a2 * s;
606
+ m[i + 8] = a0 * s + a2 * c;
607
+ }
608
+ return this;
609
+ }
610
+
611
+ /**
612
+ * Rotate in YZ plane in place
613
+ * @param {number} angle
614
+ * @returns {Mat4x4} this
615
+ */
616
+ rotateYZ(angle) {
617
+ const c = Math.cos(angle);
618
+ const s = Math.sin(angle);
619
+ const m = this.data;
620
+
621
+ for (let i = 0; i < 4; i++) {
622
+ const a1 = m[i + 4]; // Col 1
623
+ const a2 = m[i + 8]; // Col 2
624
+ m[i + 4] = a1 * c + a2 * s;
625
+ m[i + 8] = -a1 * s + a2 * c;
626
+ }
627
+ return this;
628
+ }
629
+
630
+ /**
631
+ * Rotate in XW plane in place
632
+ * @param {number} angle
633
+ * @returns {Mat4x4} this
634
+ */
635
+ rotateXW(angle) {
636
+ const c = Math.cos(angle);
637
+ const s = Math.sin(angle);
638
+ const m = this.data;
639
+
640
+ for (let i = 0; i < 4; i++) {
641
+ const a0 = m[i]; // Col 0
642
+ const a3 = m[i + 12]; // Col 3
643
+ m[i] = a0 * c + a3 * s;
644
+ m[i + 12] = -a0 * s + a3 * c;
645
+ }
646
+ return this;
647
+ }
648
+
649
+ /**
650
+ * Rotate in YW plane in place
651
+ * @param {number} angle
652
+ * @returns {Mat4x4} this
653
+ */
654
+ rotateYW(angle) {
655
+ const c = Math.cos(angle);
656
+ const s = Math.sin(angle);
657
+ const m = this.data;
658
+
659
+ for (let i = 0; i < 4; i++) {
660
+ const a1 = m[i + 4]; // Col 1
661
+ const a3 = m[i + 12]; // Col 3
662
+ m[i + 4] = a1 * c + a3 * s;
663
+ m[i + 12] = -a1 * s + a3 * c;
664
+ }
665
+ return this;
666
+ }
667
+
668
+ /**
669
+ * Rotate in ZW plane in place
670
+ * @param {number} angle
671
+ * @returns {Mat4x4} this
672
+ */
673
+ rotateZW(angle) {
674
+ const c = Math.cos(angle);
675
+ const s = Math.sin(angle);
676
+ const m = this.data;
677
+
678
+ for (let i = 0; i < 4; i++) {
679
+ const a2 = m[i + 8]; // Col 2
680
+ const a3 = m[i + 12]; // Col 3
681
+ m[i + 8] = a2 * c + a3 * s;
682
+ m[i + 12] = -a2 * s + a3 * c;
683
+ }
684
+ return this;
685
+ }
686
+
550
687
  // ========== ROTATION MATRICES FOR ALL 6 PLANES ==========
551
688
 
552
689
  /**
@@ -557,12 +694,13 @@ export class Mat4x4 {
557
694
  static rotationXY(angle) {
558
695
  const c = Math.cos(angle);
559
696
  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
- ]);
697
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
698
+ const r = out.data;
699
+ r[0] = c; r[1] = s;
700
+ r[4] = -s; r[5] = c;
701
+ r[10] = 1;
702
+ r[15] = 1;
703
+ return out;
566
704
  }
567
705
 
568
706
  /**
@@ -573,12 +711,13 @@ export class Mat4x4 {
573
711
  static rotationXZ(angle) {
574
712
  const c = Math.cos(angle);
575
713
  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
- ]);
714
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
715
+ const r = out.data;
716
+ r[0] = c; r[2] = -s;
717
+ r[5] = 1;
718
+ r[8] = s; r[10] = c;
719
+ r[15] = 1;
720
+ return out;
582
721
  }
583
722
 
584
723
  /**
@@ -589,12 +728,13 @@ export class Mat4x4 {
589
728
  static rotationYZ(angle) {
590
729
  const c = Math.cos(angle);
591
730
  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
- ]);
731
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
732
+ const r = out.data;
733
+ r[0] = 1;
734
+ r[5] = c; r[6] = s;
735
+ r[9] = -s; r[10] = c;
736
+ r[15] = 1;
737
+ return out;
598
738
  }
599
739
 
600
740
  /**
@@ -606,12 +746,13 @@ export class Mat4x4 {
606
746
  static rotationXW(angle) {
607
747
  const c = Math.cos(angle);
608
748
  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
- ]);
749
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
750
+ const r = out.data;
751
+ r[0] = c; r[3] = s;
752
+ r[5] = 1;
753
+ r[10] = 1;
754
+ r[12] = -s; r[15] = c;
755
+ return out;
615
756
  }
616
757
 
617
758
  /**
@@ -622,12 +763,13 @@ export class Mat4x4 {
622
763
  static rotationYW(angle) {
623
764
  const c = Math.cos(angle);
624
765
  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
- ]);
766
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
767
+ const r = out.data;
768
+ r[0] = 1;
769
+ r[5] = c; r[7] = s;
770
+ r[10] = 1;
771
+ r[13] = -s; r[15] = c;
772
+ return out;
631
773
  }
632
774
 
633
775
  /**
@@ -638,12 +780,13 @@ export class Mat4x4 {
638
780
  static rotationZW(angle) {
639
781
  const c = Math.cos(angle);
640
782
  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
- ]);
783
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
784
+ const r = out.data;
785
+ r[0] = 1;
786
+ r[5] = 1;
787
+ r[10] = c; r[11] = s;
788
+ r[14] = -s; r[15] = c;
789
+ return out;
647
790
  }
648
791
 
649
792
  /**
@@ -681,12 +824,12 @@ export class Mat4x4 {
681
824
  static rotationFromAngles(angles) {
682
825
  let result = Mat4x4.identity();
683
826
 
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));
827
+ if (angles.xy) result.rotateXY(angles.xy);
828
+ if (angles.xz) result.rotateXZ(angles.xz);
829
+ if (angles.yz) result.rotateYZ(angles.yz);
830
+ if (angles.xw) result.rotateXW(angles.xw);
831
+ if (angles.yw) result.rotateYW(angles.yw);
832
+ if (angles.zw) result.rotateZW(angles.zw);
690
833
 
691
834
  return result;
692
835
  }
@@ -715,12 +858,13 @@ export class Mat4x4 {
715
858
  * @returns {Mat4x4}
716
859
  */
717
860
  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
- ]);
861
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
862
+ const r = out.data;
863
+ r[0] = s;
864
+ r[5] = s;
865
+ r[10] = s;
866
+ r[15] = s;
867
+ return out;
724
868
  }
725
869
 
726
870
  /**
@@ -732,12 +876,13 @@ export class Mat4x4 {
732
876
  * @returns {Mat4x4}
733
877
  */
734
878
  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
- ]);
879
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
880
+ const r = out.data;
881
+ r[0] = sx;
882
+ r[5] = sy;
883
+ r[10] = sz;
884
+ r[15] = sw;
885
+ return out;
741
886
  }
742
887
 
743
888
  /**
@@ -753,12 +898,13 @@ export class Mat4x4 {
753
898
  static translation(tx, ty, tz, tw = 0) {
754
899
  // For true 4D translation, you need 5D homogeneous coordinates
755
900
  // 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
- ]);
901
+ const out = new Mat4x4(Mat4x4.UNINITIALIZED);
902
+ const r = out.data;
903
+ r[0] = 1;
904
+ r[5] = 1;
905
+ r[10] = 1;
906
+ r[12] = tx; r[13] = ty; r[14] = tz; r[15] = 1 + tw;
907
+ return out;
762
908
  }
763
909
  }
764
910
 
@@ -323,14 +323,17 @@ export class Rotor4D {
323
323
  /**
324
324
  * Rotate a 4D vector using sandwich product: v' = R v R†
325
325
  *
326
+ * Matrix math is inlined to avoid allocating a temporary Float32Array(16).
327
+ * Pass an optional target Vec4 to eliminate all allocations.
328
+ *
326
329
  * @param {Vec4} v - Vector to rotate
327
- * @param {Vec4} [target] - Optional target vector to write result to
328
- * @returns {Vec4} Rotated vector
330
+ * @param {Vec4} [target] - Optional pre-allocated Vec4 to write result into
331
+ * @returns {Vec4} Rotated vector (target if provided, otherwise new Vec4)
329
332
  */
330
333
  rotate(v, target) {
331
- // Direct matrix multiplication without allocation
334
+ const x = v.x, y = v.y, z = v.z, w = v.w;
332
335
 
333
- // Normalize components for stability (same as toMatrix)
336
+ // Normalize for numerical stability (same as toMatrix)
334
337
  const n = this.norm();
335
338
  const invN = n > 1e-10 ? 1 / n : 1;
336
339
 
@@ -343,7 +346,7 @@ export class Rotor4D {
343
346
  const zw = this.zw * invN;
344
347
  const xyzw = this.xyzw * invN;
345
348
 
346
- // Pre-compute products
349
+ // Squared terms
347
350
  const s2 = s * s;
348
351
  const xy2 = xy * xy;
349
352
  const xz2 = xz * xz;
@@ -353,22 +356,20 @@ export class Rotor4D {
353
356
  const zw2 = zw * zw;
354
357
  const xyzw2 = xyzw * xyzw;
355
358
 
356
- // Cross terms
359
+ // Cross terms (pre-multiplied by 2)
357
360
  const sxy = 2 * s * xy;
358
361
  const sxz = 2 * s * xz;
359
362
  const syz = 2 * s * yz;
360
363
  const sxw = 2 * s * xw;
361
364
  const syw = 2 * s * yw;
362
365
  const szw = 2 * s * zw;
363
- // const sxyzw = 2 * s * xyzw; // Unused in rotation matrix
364
366
 
365
- const xyxz = 2 * xy * xz;
367
+ const xzyz = 2 * xz * yz;
366
368
  const xyyz = 2 * xy * yz;
369
+ const xyxz = 2 * xy * xz;
367
370
  const xyxw = 2 * xy * xw;
368
371
  const xyyw = 2 * xy * yw;
369
- // const xyzw_c = 2 * xy * zw; // Unused in rotation matrix
370
372
 
371
- const xzyz = 2 * xz * yz;
372
373
  const xzxw = 2 * xz * xw;
373
374
  const xzyw = 2 * xz * yw;
374
375
  const xzzw = 2 * xz * zw;
@@ -388,40 +389,33 @@ export class Rotor4D {
388
389
  const ywxyzw = 2 * yw * xyzw;
389
390
  const zwxyzw = 2 * zw * xyzw;
390
391
 
391
- // Matrix elements
392
- // Col 0
393
- const m00 = s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2;
394
- const m01 = sxy + xzyz + xwyw - zwxyzw;
395
- const m02 = sxz - xyyz + xwzw + ywxyzw;
396
- const m03 = sxw - xyyw - xzzw - yzxyzw;
397
-
398
- // Col 1
399
- const m10 = -sxy + xzyz + xwyw + zwxyzw;
400
- const m11 = s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2;
401
- const m12 = syz + xyxz + ywzw - xwxyzw;
402
- const m13 = syw + xyxw - yzzw + xzxyzw;
403
-
404
- // Col 2
405
- const m20 = -sxz - xyyz + xwzw - ywxyzw;
406
- const m21 = -syz + xyxz + ywzw + xwxyzw;
407
- const m22 = s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2;
408
- const m23 = szw + xzxw + yzyw - xyxyzw;
409
-
410
- // Col 3
411
- const m30 = -sxw - xyyw - xzzw + yzxyzw;
412
- const m31 = -syw + xyxw - yzzw - xzxyzw;
413
- const m32 = -szw + xzxw + yzyw + xyxyzw;
414
- const m33 = s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2;
415
-
416
- const x = v.x;
417
- const y = v.y;
418
- const z = v.z;
419
- const w = v.w;
420
-
421
- const rx = m00 * x + m10 * y + m20 * z + m30 * w;
422
- const ry = m01 * x + m11 * y + m21 * z + m31 * w;
423
- const rz = m02 * x + m12 * y + m22 * z + m32 * w;
424
- const rw = m03 * x + m13 * y + m23 * z + m33 * w;
392
+ // Column-major 4x4 rotation matrix entries (inlined from toMatrix)
393
+ // Column 0
394
+ const m0 = s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2;
395
+ const m1 = sxy + xzyz + xwyw - zwxyzw;
396
+ const m2 = sxz - xyyz + xwzw + ywxyzw;
397
+ const m3 = sxw - xyyw - xzzw - yzxyzw;
398
+ // Column 1
399
+ const m4 = -sxy + xzyz + xwyw + zwxyzw;
400
+ const m5 = s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2;
401
+ const m6 = syz + xyxz + ywzw - xwxyzw;
402
+ const m7 = syw + xyxw - yzzw + xzxyzw;
403
+ // Column 2
404
+ const m8 = -sxz - xyyz + xwzw - ywxyzw;
405
+ const m9 = -syz + xyxz + ywzw + xwxyzw;
406
+ const m10 = s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2;
407
+ const m11 = szw + xzxw + yzyw - xyxyzw;
408
+ // Column 3
409
+ const m12 = -sxw - xyyw - xzzw + yzxyzw;
410
+ const m13 = -syw + xyxw - yzzw - xzxyzw;
411
+ const m14 = -szw + xzxw + yzyw + xyxyzw;
412
+ const m15 = s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2;
413
+
414
+ // Matrix-vector multiply
415
+ const rx = m0 * x + m4 * y + m8 * z + m12 * w;
416
+ const ry = m1 * x + m5 * y + m9 * z + m13 * w;
417
+ const rz = m2 * x + m6 * y + m10 * z + m14 * w;
418
+ const rw = m3 * x + m7 * y + m11 * z + m15 * w;
425
419
 
426
420
  if (target) {
427
421
  target.x = rx;
@@ -430,15 +424,15 @@ export class Rotor4D {
430
424
  target.w = rw;
431
425
  return target;
432
426
  }
433
-
434
427
  return new Vec4(rx, ry, rz, rw);
435
428
  }
436
429
 
437
430
  /**
438
431
  * Convert rotor to 4x4 rotation matrix (column-major for WebGL)
432
+ * @param {Float32Array|Array} [target] - Optional target array to write into
439
433
  * @returns {Float32Array} 16-element array in column-major order
440
434
  */
441
- toMatrix() {
435
+ toMatrix(target = null) {
442
436
  // Normalize first for numerical stability
443
437
  const n = this.norm();
444
438
  const invN = n > 1e-10 ? 1 / n : 1;
@@ -502,6 +496,35 @@ export class Rotor4D {
502
496
  // Formula derived from sandwich product R v R†
503
497
  // Diagonal: s² minus bivectors containing that axis, plus others
504
498
  // Off-diagonal: 2*s*bivector terms for single-plane contributions
499
+
500
+ if (target) {
501
+ // Column 0 (transformed X axis)
502
+ target[0] = s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2;
503
+ target[1] = sxy + xzyz + xwyw - zwxyzw;
504
+ target[2] = sxz - xyyz + xwzw + ywxyzw;
505
+ target[3] = sxw - xyyw - xzzw - yzxyzw;
506
+
507
+ // Column 1 (transformed Y axis)
508
+ target[4] = -sxy + xzyz + xwyw + zwxyzw;
509
+ target[5] = s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2;
510
+ target[6] = syz + xyxz + ywzw - xwxyzw;
511
+ target[7] = syw + xyxw - yzzw + xzxyzw;
512
+
513
+ // Column 2 (transformed Z axis)
514
+ target[8] = -sxz - xyyz + xwzw - ywxyzw;
515
+ target[9] = -syz + xyxz + ywzw + xwxyzw;
516
+ target[10] = s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2;
517
+ target[11] = szw + xzxw + yzyw - xyxyzw;
518
+
519
+ // Column 3 (transformed W axis)
520
+ target[12] = -sxw - xyyw - xzzw + yzxyzw;
521
+ target[13] = -syw + xyxw - yzzw - xzxyzw;
522
+ target[14] = -szw + xzxw + yzyw + xyxyzw;
523
+ target[15] = s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2;
524
+
525
+ return target;
526
+ }
527
+
505
528
  return new Float32Array([
506
529
  // Column 0 (transformed X axis)
507
530
  s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2,