@vib3code/sdk 2.0.3-canary.91a95f3 → 2.0.3-canary.98b84da

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 (138) 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 +4 -2
  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 +4 -2
  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 +121 -38
  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 -0
  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 +15 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -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/docs/webgpu-live.html +1 -1
  55. package/package.json +11 -4
  56. package/src/agent/index.js +1 -3
  57. package/src/agent/mcp/MCPServer.js +542 -188
  58. package/src/agent/mcp/index.js +1 -1
  59. package/src/agent/mcp/tools.js +132 -32
  60. package/src/cli/index.js +431 -47
  61. package/src/core/VIB3Engine.js +55 -3
  62. package/src/core/index.js +18 -0
  63. package/src/core/renderers/FacetedRendererAdapter.js +10 -9
  64. package/src/core/renderers/HolographicRendererAdapter.js +11 -7
  65. package/src/core/renderers/QuantumRendererAdapter.js +11 -7
  66. package/src/creative/index.js +11 -0
  67. package/src/experimental/GameLoop.js +72 -0
  68. package/src/experimental/LatticePhysics.js +100 -0
  69. package/src/experimental/LiveDirector.js +143 -0
  70. package/src/experimental/PlayerController4D.js +154 -0
  71. package/src/experimental/VIB3Actor.js +138 -0
  72. package/src/experimental/VIB3Compositor.js +117 -0
  73. package/src/experimental/VIB3Link.js +122 -0
  74. package/src/experimental/VIB3Orchestrator.js +146 -0
  75. package/src/experimental/VIB3Universe.js +109 -0
  76. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  77. package/src/export/SVGExporter.js +9 -5
  78. package/src/export/index.js +11 -1
  79. package/src/faceted/FacetedSystem.js +27 -10
  80. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  81. package/src/geometry/generators/Crystal.js +2 -2
  82. package/src/geometry/warp/HypersphereCore.js +53 -24
  83. package/src/holograms/HolographicVisualizer.js +58 -89
  84. package/src/holograms/RealHolographicSystem.js +126 -31
  85. package/src/math/Mat4x4.js +372 -140
  86. package/src/math/Projection.js +39 -4
  87. package/src/math/Rotor4D.js +157 -67
  88. package/src/math/Vec4.js +265 -111
  89. package/src/math/index.js +7 -7
  90. package/src/quantum/QuantumVisualizer.js +24 -20
  91. package/src/reactivity/index.js +3 -5
  92. package/src/render/LayerPresetManager.js +372 -0
  93. package/src/render/LayerReactivityBridge.js +344 -0
  94. package/src/render/LayerRelationshipGraph.js +610 -0
  95. package/src/render/MultiCanvasBridge.js +148 -25
  96. package/src/render/ShaderLoader.js +38 -0
  97. package/src/render/ShaderProgram.js +4 -4
  98. package/src/render/UnifiedRenderBridge.js +1 -1
  99. package/src/render/backends/WebGPUBackend.js +8 -4
  100. package/src/render/index.js +27 -2
  101. package/src/scene/Node4D.js +74 -24
  102. package/src/scene/index.js +4 -4
  103. package/src/shaders/common/geometry24.glsl +65 -0
  104. package/src/shaders/common/geometry24.wgsl +54 -0
  105. package/src/shaders/common/rotation4d.glsl +4 -4
  106. package/src/shaders/common/rotation4d.wgsl +2 -2
  107. package/src/shaders/common/uniforms.wgsl +15 -8
  108. package/src/shaders/faceted/faceted.frag.wgsl +19 -6
  109. package/src/shaders/holographic/holographic.frag.wgsl +7 -5
  110. package/src/shaders/quantum/quantum.frag.wgsl +7 -5
  111. package/src/testing/ParallelTestFramework.js +2 -2
  112. package/src/testing/ProjectionClass.test.js +38 -0
  113. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  114. package/src/viewer/GalleryUI.js +17 -0
  115. package/src/viewer/ViewerPortal.js +2 -2
  116. package/tools/shader-sync-verify.js +6 -4
  117. package/tools/update_projection.py +109 -0
  118. package/types/adaptive-sdk.d.ts +204 -5
  119. package/types/agent/cli.d.ts +78 -0
  120. package/types/agent/index.d.ts +18 -0
  121. package/types/agent/mcp.d.ts +87 -0
  122. package/types/agent/telemetry.d.ts +190 -0
  123. package/types/core/VIB3Engine.d.ts +26 -0
  124. package/types/core/index.d.ts +261 -0
  125. package/types/creative/AestheticMapper.d.ts +72 -0
  126. package/types/creative/ChoreographyPlayer.d.ts +96 -0
  127. package/types/creative/index.d.ts +17 -0
  128. package/types/export/index.d.ts +243 -0
  129. package/types/geometry/index.d.ts +164 -0
  130. package/types/math/index.d.ts +214 -0
  131. package/types/render/LayerPresetManager.d.ts +78 -0
  132. package/types/render/LayerReactivityBridge.d.ts +85 -0
  133. package/types/render/LayerRelationshipGraph.d.ts +174 -0
  134. package/types/render/index.d.ts +3 -0
  135. package/types/scene/index.d.ts +204 -0
  136. package/types/systems/index.d.ts +244 -0
  137. package/types/variations/index.d.ts +62 -0
  138. package/types/viewer/index.d.ts +225 -0
@@ -36,16 +36,28 @@ export class Projection {
36
36
  *
37
37
  * @param {Vec4} v - 4D point
38
38
  * @param {number} d - Distance parameter (typically 1.5-5)
39
+ * @param {object} [options] - Projection options
40
+ * @param {Vec4} [target] - Optional target vector to write result to
39
41
  * @returns {Vec4} Projected point (w=0)
40
42
  */
41
- static perspective(v, d = 2, options = {}) {
43
+ static perspective(v, d = 2, options = {}, target = null) {
42
44
  if (typeof d === 'object') {
43
45
  options = d;
44
46
  d = options.d ?? 2;
45
47
  }
46
- const epsilon = options.epsilon ?? DEFAULT_EPSILON;
48
+
49
+ // Handle options overload or direct target argument
50
+ if (!target && options && options.target) {
51
+ target = options.target;
52
+ }
53
+
54
+ const epsilon = (options && options.epsilon) ?? DEFAULT_EPSILON;
47
55
  const denom = clampDenominator(d - v.w, epsilon);
48
56
  const scale = 1 / denom;
57
+
58
+ if (target) {
59
+ return target.set(v.x * scale, v.y * scale, v.z * scale, 0);
60
+ }
49
61
  return new Vec4(v.x * scale, v.y * scale, v.z * scale, 0);
50
62
  }
51
63
 
@@ -126,10 +138,33 @@ export class Projection {
126
138
  * Project array of Vec4s using perspective projection
127
139
  * @param {Vec4[]} vectors
128
140
  * @param {number} d
141
+ * @param {object} [options]
142
+ * @param {Vec4[]} [target] - Optional target array to write results to
129
143
  * @returns {Vec4[]}
130
144
  */
131
- static perspectiveArray(vectors, d = 2, options = {}) {
132
- return vectors.map(v => Projection.perspective(v, d, options));
145
+ static perspectiveArray(vectors, d = 2, options = {}, target = null) {
146
+ // Handle options overload for 'd'
147
+ if (typeof d === 'object') {
148
+ options = d;
149
+ d = options.d ?? 2;
150
+ }
151
+
152
+ if (!target) {
153
+ return vectors.map(v => Projection.perspective(v, d, options));
154
+ }
155
+
156
+ const count = vectors.length;
157
+ // Iterate and reuse
158
+ for (let i = 0; i < count; i++) {
159
+ const out = target[i];
160
+ if (out) {
161
+ Projection.perspective(vectors[i], d, options, out);
162
+ } else {
163
+ target[i] = Projection.perspective(vectors[i], d, options);
164
+ }
165
+ }
166
+
167
+ return target;
133
168
  }
134
169
 
135
170
  /**
@@ -276,108 +276,169 @@ export class Rotor4D {
276
276
  * The result applies this rotation, then r's rotation
277
277
  *
278
278
  * @param {Rotor4D} r - Right operand
279
+ * @param {Rotor4D} [target=null] - Optional target rotor to write result into
279
280
  * @returns {Rotor4D} Composed rotor
280
281
  */
281
- multiply(r) {
282
+ multiply(r, target = null) {
282
283
  // Full geometric product of two rotors in 4D
283
284
  // This is derived from the geometric algebra product rules
284
285
 
285
286
  const a = this;
286
287
  const b = r;
287
288
 
288
- return new Rotor4D(
289
- // Scalar component
290
- a.s * b.s - a.xy * b.xy - a.xz * b.xz - a.yz * b.yz -
291
- a.xw * b.xw - a.yw * b.yw - a.zw * b.zw - a.xyzw * b.xyzw,
289
+ // Compute all components first to ensure safety if target aliases a or b
290
+ const s = a.s * b.s - a.xy * b.xy - a.xz * b.xz - a.yz * b.yz -
291
+ a.xw * b.xw - a.yw * b.yw - a.zw * b.zw - a.xyzw * b.xyzw;
292
292
 
293
- // XY bivector
294
- a.s * b.xy + a.xy * b.s + a.xz * b.yz - a.yz * b.xz +
295
- a.xw * b.yw - a.yw * b.xw - a.zw * b.xyzw - a.xyzw * b.zw,
293
+ const xy = a.s * b.xy + a.xy * b.s + a.xz * b.yz - a.yz * b.xz +
294
+ a.xw * b.yw - a.yw * b.xw - a.zw * b.xyzw - a.xyzw * b.zw;
296
295
 
297
- // XZ bivector
298
- a.s * b.xz + a.xz * b.s - a.xy * b.yz + a.yz * b.xy +
299
- a.xw * b.zw + a.yw * b.xyzw - a.zw * b.xw + a.xyzw * b.yw,
296
+ const xz = a.s * b.xz + a.xz * b.s - a.xy * b.yz + a.yz * b.xy +
297
+ a.xw * b.zw + a.yw * b.xyzw - a.zw * b.xw + a.xyzw * b.yw;
300
298
 
301
- // YZ bivector
302
- a.s * b.yz + a.yz * b.s + a.xy * b.xz - a.xz * b.xy -
303
- a.xw * b.xyzw + a.yw * b.zw - a.zw * b.yw - a.xyzw * b.xw,
299
+ const yz = a.s * b.yz + a.yz * b.s + a.xy * b.xz - a.xz * b.xy -
300
+ a.xw * b.xyzw + a.yw * b.zw - a.zw * b.yw - a.xyzw * b.xw;
304
301
 
305
- // XW bivector
306
- a.s * b.xw + a.xw * b.s - a.xy * b.yw + a.xz * b.zw +
307
- a.yz * b.xyzw + a.yw * b.xy - a.zw * b.xz + a.xyzw * b.yz,
302
+ const xw = a.s * b.xw + a.xw * b.s - a.xy * b.yw + a.xz * b.zw +
303
+ a.yz * b.xyzw + a.yw * b.xy - a.zw * b.xz + a.xyzw * b.yz;
308
304
 
309
- // YW bivector
310
- a.s * b.yw + a.yw * b.s + a.xy * b.xw - a.xz * b.xyzw -
311
- a.yz * b.zw - a.xw * b.xy + a.zw * b.yz - a.xyzw * b.xz,
305
+ const yw = a.s * b.yw + a.yw * b.s + a.xy * b.xw - a.xz * b.xyzw -
306
+ a.yz * b.zw - a.xw * b.xy + a.zw * b.yz - a.xyzw * b.xz;
312
307
 
313
- // ZW bivector
314
- a.s * b.zw + a.zw * b.s + a.xy * b.xyzw + a.xz * b.xw +
315
- a.yz * b.yw - a.xw * b.xz - a.yw * b.yz + a.xyzw * b.xy,
308
+ const zw = a.s * b.zw + a.zw * b.s + a.xy * b.xyzw + a.xz * b.xw +
309
+ a.yz * b.yw - a.xw * b.xz - a.yw * b.yz + a.xyzw * b.xy;
316
310
 
317
- // Pseudoscalar XYZW
318
- a.s * b.xyzw + a.xyzw * b.s + a.xy * b.zw - a.xz * b.yw +
319
- a.yz * b.xw + a.xw * b.yz - a.yw * b.xz + a.zw * b.xy
320
- );
311
+ const xyzw = a.s * b.xyzw + a.xyzw * b.s + a.xy * b.zw - a.xz * b.yw +
312
+ a.yz * b.xw + a.xw * b.yz - a.yw * b.xz + a.zw * b.xy;
313
+
314
+ if (target) {
315
+ target.s = s;
316
+ target.xy = xy;
317
+ target.xz = xz;
318
+ target.yz = yz;
319
+ target.xw = xw;
320
+ target.yw = yw;
321
+ target.zw = zw;
322
+ target.xyzw = xyzw;
323
+ return target;
324
+ }
325
+
326
+ return new Rotor4D(s, xy, xz, yz, xw, yw, zw, xyzw);
321
327
  }
322
328
 
323
329
  /**
324
330
  * Rotate a 4D vector using sandwich product: v' = R v R†
325
331
  *
332
+ * Matrix math is inlined to avoid allocating a temporary Float32Array(16).
333
+ * Pass an optional target Vec4 to eliminate all allocations.
334
+ *
326
335
  * @param {Vec4} v - Vector to rotate
327
- * @returns {Vec4} Rotated vector
336
+ * @param {Vec4} [target] - Optional pre-allocated Vec4 to write result into
337
+ * @returns {Vec4} Rotated vector (target if provided, otherwise new Vec4)
328
338
  */
329
- rotate(v) {
330
- // For efficiency, we expand the sandwich product directly
331
- // rather than doing two rotor multiplications
332
-
339
+ rotate(v, target) {
333
340
  const x = v.x, y = v.y, z = v.z, w = v.w;
334
341
 
335
- // Compute R v (rotor times vector)
336
- // Vector in GA is: x*e1 + y*e2 + z*e3 + w*e4
337
- // This produces a mixed multivector
338
-
339
- // Then multiply by R† (reverse of rotor)
340
- // Extract the vector part of the result
342
+ // Normalize for numerical stability (same as toMatrix)
343
+ const n = this.norm();
344
+ const invN = n > 1e-10 ? 1 / n : 1;
341
345
 
342
- // Pre-compute some common terms
343
- const s = this.s;
344
- const xy = this.xy, xz = this.xz, yz = this.yz;
345
- const xw = this.xw, yw = this.yw, zw = this.zw;
346
- const xyzw = this.xyzw;
346
+ const s = this.s * invN;
347
+ const xy = this.xy * invN;
348
+ const xz = this.xz * invN;
349
+ const yz = this.yz * invN;
350
+ const xw = this.xw * invN;
351
+ const yw = this.yw * invN;
352
+ const zw = this.zw * invN;
353
+ const xyzw = this.xyzw * invN;
347
354
 
348
- // Squared terms for the rotation formula
355
+ // Squared terms
349
356
  const s2 = s * s;
350
- const xy2 = xy * xy, xz2 = xz * xz, yz2 = yz * yz;
351
- const xw2 = xw * xw, yw2 = yw * yw, zw2 = zw * zw;
357
+ const xy2 = xy * xy;
358
+ const xz2 = xz * xz;
359
+ const yz2 = yz * yz;
360
+ const xw2 = xw * xw;
361
+ const yw2 = yw * yw;
362
+ const zw2 = zw * zw;
352
363
  const xyzw2 = xyzw * xyzw;
353
364
 
354
- // The full rotation formula derived from R v R†
355
- const newX =
356
- x * (s2 + xy2 + xz2 - yz2 + xw2 - yw2 - zw2 - xyzw2) +
357
- 2 * y * (s * xy + xz * yz + xw * yw - s * xyzw * zw + xy * s - xyzw * zw) +
358
- 2 * z * (s * xz - xy * yz + xw * zw + xyzw * yw) +
359
- 2 * w * (s * xw - xy * yw - xz * zw - xyzw * yz);
360
-
361
- // Simplified rotation using matrix form
362
- // This is equivalent but clearer
363
-
364
- // Actually, let's use the direct matrix multiplication approach
365
- // which is more numerically stable
366
-
367
- const m = this.toMatrix();
368
- return new Vec4(
369
- m[0] * x + m[4] * y + m[8] * z + m[12] * w,
370
- m[1] * x + m[5] * y + m[9] * z + m[13] * w,
371
- m[2] * x + m[6] * y + m[10] * z + m[14] * w,
372
- m[3] * x + m[7] * y + m[11] * z + m[15] * w
373
- );
365
+ // Cross terms (pre-multiplied by 2)
366
+ const sxy = 2 * s * xy;
367
+ const sxz = 2 * s * xz;
368
+ const syz = 2 * s * yz;
369
+ const sxw = 2 * s * xw;
370
+ const syw = 2 * s * yw;
371
+ const szw = 2 * s * zw;
372
+
373
+ const xzyz = 2 * xz * yz;
374
+ const xyyz = 2 * xy * yz;
375
+ const xyxz = 2 * xy * xz;
376
+ const xyxw = 2 * xy * xw;
377
+ const xyyw = 2 * xy * yw;
378
+
379
+ const xzxw = 2 * xz * xw;
380
+ const xzyw = 2 * xz * yw;
381
+ const xzzw = 2 * xz * zw;
382
+
383
+ const yzxw = 2 * yz * xw;
384
+ const yzyw = 2 * yz * yw;
385
+ const yzzw = 2 * yz * zw;
386
+
387
+ const xwyw = 2 * xw * yw;
388
+ const xwzw = 2 * xw * zw;
389
+ const ywzw = 2 * yw * zw;
390
+
391
+ const xyxyzw = 2 * xy * xyzw;
392
+ const xzxyzw = 2 * xz * xyzw;
393
+ const yzxyzw = 2 * yz * xyzw;
394
+ const xwxyzw = 2 * xw * xyzw;
395
+ const ywxyzw = 2 * yw * xyzw;
396
+ const zwxyzw = 2 * zw * xyzw;
397
+
398
+ // Column-major 4x4 rotation matrix entries (inlined from toMatrix)
399
+ // Column 0
400
+ const m0 = s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2;
401
+ const m1 = sxy + xzyz + xwyw - zwxyzw;
402
+ const m2 = sxz - xyyz + xwzw + ywxyzw;
403
+ const m3 = sxw - xyyw - xzzw - yzxyzw;
404
+ // Column 1
405
+ const m4 = -sxy + xzyz + xwyw + zwxyzw;
406
+ const m5 = s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2;
407
+ const m6 = syz + xyxz + ywzw - xwxyzw;
408
+ const m7 = syw + xyxw - yzzw + xzxyzw;
409
+ // Column 2
410
+ const m8 = -sxz - xyyz + xwzw - ywxyzw;
411
+ const m9 = -syz + xyxz + ywzw + xwxyzw;
412
+ const m10 = s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2;
413
+ const m11 = szw + xzxw + yzyw - xyxyzw;
414
+ // Column 3
415
+ const m12 = -sxw - xyyw - xzzw + yzxyzw;
416
+ const m13 = -syw + xyxw - yzzw - xzxyzw;
417
+ const m14 = -szw + xzxw + yzyw + xyxyzw;
418
+ const m15 = s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2;
419
+
420
+ // Matrix-vector multiply
421
+ const rx = m0 * x + m4 * y + m8 * z + m12 * w;
422
+ const ry = m1 * x + m5 * y + m9 * z + m13 * w;
423
+ const rz = m2 * x + m6 * y + m10 * z + m14 * w;
424
+ const rw = m3 * x + m7 * y + m11 * z + m15 * w;
425
+
426
+ if (target) {
427
+ target.x = rx;
428
+ target.y = ry;
429
+ target.z = rz;
430
+ target.w = rw;
431
+ return target;
432
+ }
433
+ return new Vec4(rx, ry, rz, rw);
374
434
  }
375
435
 
376
436
  /**
377
437
  * Convert rotor to 4x4 rotation matrix (column-major for WebGL)
438
+ * @param {Float32Array|Array} [target] - Optional target array to write into
378
439
  * @returns {Float32Array} 16-element array in column-major order
379
440
  */
380
- toMatrix() {
441
+ toMatrix(target = null) {
381
442
  // Normalize first for numerical stability
382
443
  const n = this.norm();
383
444
  const invN = n > 1e-10 ? 1 / n : 1;
@@ -441,6 +502,35 @@ export class Rotor4D {
441
502
  // Formula derived from sandwich product R v R†
442
503
  // Diagonal: s² minus bivectors containing that axis, plus others
443
504
  // Off-diagonal: 2*s*bivector terms for single-plane contributions
505
+
506
+ if (target) {
507
+ // Column 0 (transformed X axis)
508
+ target[0] = s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2;
509
+ target[1] = sxy + xzyz + xwyw - zwxyzw;
510
+ target[2] = sxz - xyyz + xwzw + ywxyzw;
511
+ target[3] = sxw - xyyw - xzzw - yzxyzw;
512
+
513
+ // Column 1 (transformed Y axis)
514
+ target[4] = -sxy + xzyz + xwyw + zwxyzw;
515
+ target[5] = s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2;
516
+ target[6] = syz + xyxz + ywzw - xwxyzw;
517
+ target[7] = syw + xyxw - yzzw + xzxyzw;
518
+
519
+ // Column 2 (transformed Z axis)
520
+ target[8] = -sxz - xyyz + xwzw - ywxyzw;
521
+ target[9] = -syz + xyxz + ywzw + xwxyzw;
522
+ target[10] = s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2;
523
+ target[11] = szw + xzxw + yzyw - xyxyzw;
524
+
525
+ // Column 3 (transformed W axis)
526
+ target[12] = -sxw - xyyw - xzzw + yzxyzw;
527
+ target[13] = -syw + xyxw - yzzw - xzxyzw;
528
+ target[14] = -szw + xzxw + yzyw + xyxyzw;
529
+ target[15] = s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2;
530
+
531
+ return target;
532
+ }
533
+
444
534
  return new Float32Array([
445
535
  // Column 0 (transformed X axis)
446
536
  s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2,