@vib3code/sdk 2.0.3-canary.60bc0f0 → 2.0.3-canary.74aebb4
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.
- package/DOCS/EXPANSION_DESIGN.md +977 -0
- package/DOCS/EXPANSION_DESIGN_ULTRA.md +387 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +2 -2
- package/DOCS/OPTIMIZATION_PLAN_MATH.md +118 -0
- package/DOCS/SYSTEM_INVENTORY.md +2 -2
- package/DOCS/WEBGPU_STATUS.md +119 -38
- package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +38 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +108 -0
- package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +308 -0
- package/docs/webgpu-live.html +1 -1
- package/package.json +1 -1
- package/src/agent/mcp/MCPServer.js +195 -136
- package/src/agent/mcp/tools.js +45 -32
- package/src/experimental/GameLoop.js +72 -0
- package/src/experimental/LatticePhysics.js +100 -0
- package/src/experimental/LiveDirector.js +143 -0
- package/src/experimental/PlayerController4D.js +154 -0
- package/src/experimental/VIB3Actor.js +138 -0
- package/src/experimental/VIB3Compositor.js +117 -0
- package/src/experimental/VIB3Link.js +122 -0
- package/src/experimental/VIB3Orchestrator.js +146 -0
- package/src/experimental/VIB3Universe.js +109 -0
- package/src/experimental/demos/CrystalLabyrinth.js +202 -0
- package/src/faceted/FacetedSystem.js +19 -6
- package/src/geometry/generators/Crystal.js +2 -2
- package/src/holograms/HolographicVisualizer.js +58 -89
- package/src/math/Mat4x4.js +122 -6
- package/src/math/Rotor4D.js +93 -39
- package/src/math/Vec4.js +119 -78
- package/src/quantum/QuantumVisualizer.js +24 -20
- package/src/render/ShaderLoader.js +38 -0
- package/src/render/ShaderProgram.js +4 -4
- package/src/render/UnifiedRenderBridge.js +1 -1
- package/src/render/backends/WebGPUBackend.js +8 -4
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +4 -4
- package/src/shaders/common/rotation4d.wgsl +2 -2
- package/src/shaders/common/uniforms.wgsl +15 -8
- package/src/shaders/faceted/faceted.frag.wgsl +19 -6
- package/src/shaders/holographic/holographic.frag.wgsl +7 -5
- package/src/shaders/quantum/quantum.frag.wgsl +7 -5
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
- package/tools/shader-sync-verify.js +6 -4
|
@@ -132,28 +132,28 @@ export class HolographicVisualizer {
|
|
|
132
132
|
const finalName = geometryName + suffixes[variationLevel];
|
|
133
133
|
|
|
134
134
|
const geometryConfigs = {
|
|
135
|
-
0: {
|
|
136
|
-
1: {
|
|
137
|
-
2: {
|
|
138
|
-
3: {
|
|
139
|
-
4: {
|
|
140
|
-
5: {
|
|
141
|
-
6: {
|
|
142
|
-
7: {
|
|
135
|
+
0: { gridDensity: 0.8 + variationLevel * 0.2, speed: 0.3 + variationLevel * 0.1, chaos: variationLevel * 0.1, morphFactor: 0.0 + variationLevel * 0.2 },
|
|
136
|
+
1: { gridDensity: 1.0 + variationLevel * 0.3, speed: 0.5 + variationLevel * 0.1, chaos: variationLevel * 0.15, morphFactor: variationLevel * 0.2 },
|
|
137
|
+
2: { gridDensity: 1.2 + variationLevel * 0.4, speed: 0.4 + variationLevel * 0.2, chaos: 0.1 + variationLevel * 0.1, morphFactor: 0.3 + variationLevel * 0.2 },
|
|
138
|
+
3: { gridDensity: 0.9 + variationLevel * 0.3, speed: 0.6 + variationLevel * 0.2, chaos: 0.2 + variationLevel * 0.2, morphFactor: 0.5 + variationLevel * 0.1 },
|
|
139
|
+
4: { gridDensity: 1.4 + variationLevel * 0.5, speed: 0.7 + variationLevel * 0.1, chaos: 0.3 + variationLevel * 0.2, morphFactor: 0.7 + variationLevel * 0.1 },
|
|
140
|
+
5: { gridDensity: 1.8 + variationLevel * 0.3, speed: 0.5 + variationLevel * 0.3, chaos: 0.5 + variationLevel * 0.2, morphFactor: 0.8 + variationLevel * 0.05 },
|
|
141
|
+
6: { gridDensity: 0.6 + variationLevel * 0.4, speed: 0.8 + variationLevel * 0.4, chaos: 0.4 + variationLevel * 0.3, morphFactor: 0.6 + variationLevel * 0.2 },
|
|
142
|
+
7: { gridDensity: 1.6 + variationLevel * 0.2, speed: 0.2 + variationLevel * 0.1, chaos: 0.1 + variationLevel * 0.1, morphFactor: 0.2 + variationLevel * 0.2 }
|
|
143
143
|
};
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
const config = geometryConfigs[baseGeometry];
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
return {
|
|
148
|
-
|
|
148
|
+
geometry: baseGeometry,
|
|
149
149
|
name: finalName,
|
|
150
|
-
|
|
150
|
+
gridDensity: config.gridDensity,
|
|
151
151
|
speed: config.speed,
|
|
152
152
|
hue: (variant * 12.27) % 360,
|
|
153
|
-
saturation: 0.8 + (variationLevel * 0.05),
|
|
153
|
+
saturation: 0.8 + (variationLevel * 0.05),
|
|
154
154
|
intensity: 0.5 + (variationLevel * 0.1),
|
|
155
155
|
chaos: config.chaos,
|
|
156
|
-
|
|
156
|
+
morphFactor: config.morphFactor
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -169,20 +169,20 @@ export class HolographicVisualizer {
|
|
|
169
169
|
densityMult: 0.8, speedMult: 0.3, colorShift: 180.0, intensity: 0.4,
|
|
170
170
|
mouseReactivity: 0.5, clickReactivity: 0.3
|
|
171
171
|
},
|
|
172
|
-
'content': {
|
|
173
|
-
densityMult: vp.
|
|
172
|
+
'content': {
|
|
173
|
+
densityMult: vp.gridDensity, speedMult: vp.speed,
|
|
174
174
|
colorShift: vp.hue, intensity: vp.intensity,
|
|
175
|
-
mouseReactivity: 1.0, clickReactivity: 0.8
|
|
175
|
+
mouseReactivity: 1.0, clickReactivity: 0.8
|
|
176
176
|
},
|
|
177
|
-
'highlight': {
|
|
178
|
-
densityMult: 1.5 + (vp.
|
|
177
|
+
'highlight': {
|
|
178
|
+
densityMult: 1.5 + (vp.gridDensity * 0.3), speedMult: 0.8 + (vp.speed * 0.2),
|
|
179
179
|
colorShift: vp.hue + 60.0, intensity: 0.6 + (vp.intensity * 0.2),
|
|
180
|
-
mouseReactivity: 1.2, clickReactivity: 1.0
|
|
180
|
+
mouseReactivity: 1.2, clickReactivity: 1.0
|
|
181
181
|
},
|
|
182
|
-
'accent': {
|
|
183
|
-
densityMult: 2.5 + (vp.
|
|
182
|
+
'accent': {
|
|
183
|
+
densityMult: 2.5 + (vp.gridDensity * 0.5), speedMult: 0.4 + (vp.speed * 0.1),
|
|
184
184
|
colorShift: vp.hue + 300.0, intensity: 0.3 + (vp.intensity * 0.1),
|
|
185
|
-
mouseReactivity: 1.5, clickReactivity: 1.2
|
|
185
|
+
mouseReactivity: 1.5, clickReactivity: 1.2
|
|
186
186
|
}
|
|
187
187
|
};
|
|
188
188
|
|
|
@@ -207,7 +207,7 @@ export class HolographicVisualizer {
|
|
|
207
207
|
uniform float u_time;
|
|
208
208
|
uniform vec2 u_mouse;
|
|
209
209
|
uniform float u_geometry;
|
|
210
|
-
uniform float
|
|
210
|
+
uniform float u_gridDensity;
|
|
211
211
|
uniform float u_speed;
|
|
212
212
|
uniform vec3 u_color;
|
|
213
213
|
uniform float u_intensity;
|
|
@@ -218,9 +218,8 @@ export class HolographicVisualizer {
|
|
|
218
218
|
uniform float u_mouseIntensity;
|
|
219
219
|
uniform float u_clickIntensity;
|
|
220
220
|
uniform float u_densityVariation;
|
|
221
|
-
uniform float u_geometryType;
|
|
222
221
|
uniform float u_chaos;
|
|
223
|
-
uniform float
|
|
222
|
+
uniform float u_morphFactor;
|
|
224
223
|
uniform float u_touchMorph;
|
|
225
224
|
uniform float u_touchChaos;
|
|
226
225
|
uniform float u_scrollParallax;
|
|
@@ -293,7 +292,7 @@ export class HolographicVisualizer {
|
|
|
293
292
|
// ========================================
|
|
294
293
|
vec3 warpHypersphereCore(vec3 p, int geometryIndex, vec2 mouseDelta) {
|
|
295
294
|
float radius = length(p);
|
|
296
|
-
float morphBlend = clamp(
|
|
295
|
+
float morphBlend = clamp(u_morphFactor * 0.6 + 0.3, 0.0, 2.0);
|
|
297
296
|
float w = sin(radius * (1.3 + float(geometryIndex) * 0.12) + u_time * 0.0008 * u_speed);
|
|
298
297
|
w *= (0.4 + morphBlend * 0.45);
|
|
299
298
|
|
|
@@ -315,7 +314,7 @@ export class HolographicVisualizer {
|
|
|
315
314
|
vec3 c3 = normalize(vec3(-1.0, 1.0, -1.0));
|
|
316
315
|
vec3 c4 = normalize(vec3(1.0, -1.0, -1.0));
|
|
317
316
|
|
|
318
|
-
float morphBlend = clamp(
|
|
317
|
+
float morphBlend = clamp(u_morphFactor * 0.8 + 0.2, 0.0, 2.0);
|
|
319
318
|
float basisMix = dot(p, c1) * 0.14 + dot(p, c2) * 0.1 + dot(p, c3) * 0.08;
|
|
320
319
|
float w = sin(basisMix * 5.5 + u_time * 0.0009 * u_speed);
|
|
321
320
|
w *= cos(dot(p, c4) * 4.2 - u_time * 0.0007 * u_speed);
|
|
@@ -551,12 +550,12 @@ export class HolographicVisualizer {
|
|
|
551
550
|
float audioDensityMod = 1.0 + u_audioDensityBoost * 0.5;
|
|
552
551
|
// Controlled density calculation - breathing modulation added
|
|
553
552
|
float breathDensityMod = 1.0 + u_breath * 0.1;
|
|
554
|
-
float baseDensity =
|
|
553
|
+
float baseDensity = u_gridDensity * u_roleDensity * breathDensityMod;
|
|
555
554
|
|
|
556
555
|
float densityVariations = (u_densityVariation * 0.3 + (scrollDensityMod - 1.0) * 0.4 + (audioDensityMod - 1.0) * 0.2);
|
|
557
556
|
float roleDensity = baseDensity + densityVariations;
|
|
558
557
|
|
|
559
|
-
float morphedGeometry =
|
|
558
|
+
float morphedGeometry = u_geometry + u_morphFactor * 3.0 + u_touchMorph * 2.0 + u_audioMorphBoost * 1.5;
|
|
560
559
|
float lattice = getDynamicGeometry(p, roleDensity, morphedGeometry);
|
|
561
560
|
|
|
562
561
|
// Enhanced holographic color processing
|
|
@@ -590,9 +589,9 @@ export class HolographicVisualizer {
|
|
|
590
589
|
color = rgbGlitch(color, uv, enhancedChaos);
|
|
591
590
|
|
|
592
591
|
// Apply morph distortion to position
|
|
593
|
-
vec2 morphDistortion = vec2(sin(uv.y * 10.0 + u_time * 0.001) *
|
|
594
|
-
cos(uv.x * 10.0 + u_time * 0.001) *
|
|
595
|
-
color = mix(color, color * (1.0 + length(morphDistortion)),
|
|
592
|
+
vec2 morphDistortion = vec2(sin(uv.y * 10.0 + u_time * 0.001) * u_morphFactor * 0.1,
|
|
593
|
+
cos(uv.x * 10.0 + u_time * 0.001) * u_morphFactor * 0.1);
|
|
594
|
+
color = mix(color, color * (1.0 + length(morphDistortion)), u_morphFactor * 0.5);
|
|
596
595
|
|
|
597
596
|
// Enhanced holographic interaction effects
|
|
598
597
|
float mouseDist = length(uv - (u_mouse - 0.5) * vec2(aspectRatio, 1.0));
|
|
@@ -621,7 +620,7 @@ export class HolographicVisualizer {
|
|
|
621
620
|
time: this.gl.getUniformLocation(this.program, 'u_time'),
|
|
622
621
|
mouse: this.gl.getUniformLocation(this.program, 'u_mouse'),
|
|
623
622
|
geometry: this.gl.getUniformLocation(this.program, 'u_geometry'),
|
|
624
|
-
|
|
623
|
+
gridDensity: this.gl.getUniformLocation(this.program, 'u_gridDensity'),
|
|
625
624
|
speed: this.gl.getUniformLocation(this.program, 'u_speed'),
|
|
626
625
|
color: this.gl.getUniformLocation(this.program, 'u_color'),
|
|
627
626
|
intensity: this.gl.getUniformLocation(this.program, 'u_intensity'),
|
|
@@ -632,9 +631,8 @@ export class HolographicVisualizer {
|
|
|
632
631
|
mouseIntensity: this.gl.getUniformLocation(this.program, 'u_mouseIntensity'),
|
|
633
632
|
clickIntensity: this.gl.getUniformLocation(this.program, 'u_clickIntensity'),
|
|
634
633
|
densityVariation: this.gl.getUniformLocation(this.program, 'u_densityVariation'),
|
|
635
|
-
geometryType: this.gl.getUniformLocation(this.program, 'u_geometryType'),
|
|
636
634
|
chaos: this.gl.getUniformLocation(this.program, 'u_chaos'),
|
|
637
|
-
|
|
635
|
+
morphFactor: this.gl.getUniformLocation(this.program, 'u_morphFactor'),
|
|
638
636
|
touchMorph: this.gl.getUniformLocation(this.program, 'u_touchMorph'),
|
|
639
637
|
touchChaos: this.gl.getUniformLocation(this.program, 'u_touchChaos'),
|
|
640
638
|
scrollParallax: this.gl.getUniformLocation(this.program, 'u_scrollParallax'),
|
|
@@ -894,11 +892,11 @@ export class HolographicVisualizer {
|
|
|
894
892
|
this.gl.uniform2f(this.uniforms.resolution, this.canvas.width, this.canvas.height);
|
|
895
893
|
this.gl.uniform1f(this.uniforms.time, time);
|
|
896
894
|
this.gl.uniform2f(this.uniforms.mouse, this.mouseX, this.mouseY);
|
|
897
|
-
this.gl.uniform1f(this.uniforms.
|
|
898
|
-
this.gl.uniform1f(this.uniforms.
|
|
899
|
-
//
|
|
900
|
-
const baseSpeed = (this.variantParams.speed || 0.5) * 0.2;
|
|
901
|
-
const audioBoost = (this.audioSpeedBoost || 0.0) * 0.1;
|
|
895
|
+
this.gl.uniform1f(this.uniforms.geometry, this.variantParams.geometry !== undefined ? this.variantParams.geometry : this.variant || 0);
|
|
896
|
+
this.gl.uniform1f(this.uniforms.gridDensity, this.variantParams.gridDensity || 1.0);
|
|
897
|
+
// Controlled speed calculation - base speed controls main movement, audio provides subtle boost
|
|
898
|
+
const baseSpeed = (this.variantParams.speed || 0.5) * 0.2;
|
|
899
|
+
const audioBoost = (this.audioSpeedBoost || 0.0) * 0.1;
|
|
902
900
|
this.gl.uniform1f(this.uniforms.speed, baseSpeed + audioBoost);
|
|
903
901
|
this.gl.uniform3fv(this.uniforms.color, new Float32Array(rgbColor));
|
|
904
902
|
this.gl.uniform1f(this.uniforms.intensity, (this.variantParams.intensity || 0.5) * this.roleParams.intensity);
|
|
@@ -909,9 +907,8 @@ export class HolographicVisualizer {
|
|
|
909
907
|
this.gl.uniform1f(this.uniforms.mouseIntensity, this.mouseIntensity);
|
|
910
908
|
this.gl.uniform1f(this.uniforms.clickIntensity, this.clickIntensity);
|
|
911
909
|
this.gl.uniform1f(this.uniforms.densityVariation, this.densityVariation);
|
|
912
|
-
this.gl.uniform1f(this.uniforms.geometryType, this.variantParams.geometryType !== undefined ? this.variantParams.geometryType : this.variant || 0);
|
|
913
910
|
this.gl.uniform1f(this.uniforms.chaos, this.variantParams.chaos || 0.0);
|
|
914
|
-
this.gl.uniform1f(this.uniforms.
|
|
911
|
+
this.gl.uniform1f(this.uniforms.morphFactor, this.variantParams.morphFactor || 0.0);
|
|
915
912
|
|
|
916
913
|
// Touch and scroll uniforms
|
|
917
914
|
this.gl.uniform1f(this.uniforms.touchMorph, this.touchMorph);
|
|
@@ -1001,62 +998,34 @@ export class HolographicVisualizer {
|
|
|
1001
998
|
}
|
|
1002
999
|
|
|
1003
1000
|
/**
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1001
|
+
* Update visualization parameters from SDK global parameter names.
|
|
1002
|
+
* Parameters are written directly to variantParams — no name mapping needed
|
|
1003
|
+
* since shader uniforms now use SDK-standard names.
|
|
1006
1004
|
*/
|
|
1007
1005
|
updateParameters(params) {
|
|
1008
1006
|
if (!params || typeof params !== 'object') return;
|
|
1009
|
-
// Update variant parameters with proper mapping and scaling
|
|
1010
1007
|
if (this.variantParams) {
|
|
1011
1008
|
Object.keys(params).forEach(param => {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
this.variantParams[mappedParam] = scaledValue;
|
|
1027
|
-
|
|
1028
|
-
// Handle special parameter types
|
|
1029
|
-
if (mappedParam === 'geometryType') {
|
|
1030
|
-
// Regenerate role params with new geometry
|
|
1031
|
-
this.roleParams = this.generateRoleParams(this.role);
|
|
1032
|
-
}
|
|
1009
|
+
let scaledValue = params[param];
|
|
1010
|
+
// Guard against NaN/Infinity reaching GPU uniforms
|
|
1011
|
+
if (typeof scaledValue !== 'number' || !Number.isFinite(scaledValue)) return;
|
|
1012
|
+
|
|
1013
|
+
// Scale gridDensity (5-100) to holographic density range (0.3-2.5)
|
|
1014
|
+
if (param === 'gridDensity') {
|
|
1015
|
+
scaledValue = 0.3 + (parseFloat(params[param]) - 5) / 95 * 2.2;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
this.variantParams[param] = scaledValue;
|
|
1019
|
+
|
|
1020
|
+
// Regenerate role params when geometry changes
|
|
1021
|
+
if (param === 'geometry') {
|
|
1022
|
+
this.roleParams = this.generateRoleParams(this.role);
|
|
1033
1023
|
}
|
|
1034
1024
|
});
|
|
1035
1025
|
}
|
|
1036
|
-
|
|
1026
|
+
|
|
1037
1027
|
// Don't call render() here - engine will call it to prevent infinite loop
|
|
1038
1028
|
}
|
|
1039
|
-
|
|
1040
|
-
/**
|
|
1041
|
-
* Map global parameter names to holographic system parameter names
|
|
1042
|
-
*/
|
|
1043
|
-
mapParameterName(globalParam) {
|
|
1044
|
-
const paramMap = {
|
|
1045
|
-
'gridDensity': 'density',
|
|
1046
|
-
'morphFactor': 'morph',
|
|
1047
|
-
'rot4dXW': 'rot4dXW',
|
|
1048
|
-
'rot4dYW': 'rot4dYW',
|
|
1049
|
-
'rot4dZW': 'rot4dZW',
|
|
1050
|
-
'hue': 'hue',
|
|
1051
|
-
'intensity': 'intensity',
|
|
1052
|
-
'saturation': 'saturation',
|
|
1053
|
-
'chaos': 'chaos',
|
|
1054
|
-
'speed': 'speed',
|
|
1055
|
-
'geometry': 'geometryType',
|
|
1056
|
-
'breath': 'breath'
|
|
1057
|
-
};
|
|
1058
|
-
return paramMap[globalParam] || globalParam;
|
|
1059
|
-
}
|
|
1060
1029
|
|
|
1061
1030
|
/**
|
|
1062
1031
|
* Clean up all WebGL resources and event listeners
|
package/src/math/Mat4x4.js
CHANGED
|
@@ -547,6 +547,122 @@ export class Mat4x4 {
|
|
|
547
547
|
return new Mat4x4(json.data);
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
+
// ========== IN-PLACE ROTATIONS ==========
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Rotate in XY plane in place
|
|
554
|
+
* @param {number} angle
|
|
555
|
+
* @returns {Mat4x4} this
|
|
556
|
+
*/
|
|
557
|
+
rotateXY(angle) {
|
|
558
|
+
const c = Math.cos(angle);
|
|
559
|
+
const s = Math.sin(angle);
|
|
560
|
+
const m = this.data;
|
|
561
|
+
|
|
562
|
+
for (let i = 0; i < 4; i++) {
|
|
563
|
+
const a0 = m[i]; // Col 0
|
|
564
|
+
const a1 = m[i + 4]; // Col 1
|
|
565
|
+
m[i] = a0 * c + a1 * s;
|
|
566
|
+
m[i + 4] = -a0 * s + a1 * c;
|
|
567
|
+
}
|
|
568
|
+
return this;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Rotate in XZ plane in place
|
|
573
|
+
* @param {number} angle
|
|
574
|
+
* @returns {Mat4x4} this
|
|
575
|
+
*/
|
|
576
|
+
rotateXZ(angle) {
|
|
577
|
+
const c = Math.cos(angle);
|
|
578
|
+
const s = Math.sin(angle);
|
|
579
|
+
const m = this.data;
|
|
580
|
+
|
|
581
|
+
for (let i = 0; i < 4; i++) {
|
|
582
|
+
const a0 = m[i]; // Col 0
|
|
583
|
+
const a2 = m[i + 8]; // Col 2
|
|
584
|
+
m[i] = a0 * c - a2 * s;
|
|
585
|
+
m[i + 8] = a0 * s + a2 * c;
|
|
586
|
+
}
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Rotate in YZ plane in place
|
|
592
|
+
* @param {number} angle
|
|
593
|
+
* @returns {Mat4x4} this
|
|
594
|
+
*/
|
|
595
|
+
rotateYZ(angle) {
|
|
596
|
+
const c = Math.cos(angle);
|
|
597
|
+
const s = Math.sin(angle);
|
|
598
|
+
const m = this.data;
|
|
599
|
+
|
|
600
|
+
for (let i = 0; i < 4; i++) {
|
|
601
|
+
const a1 = m[i + 4]; // Col 1
|
|
602
|
+
const a2 = m[i + 8]; // Col 2
|
|
603
|
+
m[i + 4] = a1 * c + a2 * s;
|
|
604
|
+
m[i + 8] = -a1 * s + a2 * c;
|
|
605
|
+
}
|
|
606
|
+
return this;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Rotate in XW plane in place
|
|
611
|
+
* @param {number} angle
|
|
612
|
+
* @returns {Mat4x4} this
|
|
613
|
+
*/
|
|
614
|
+
rotateXW(angle) {
|
|
615
|
+
const c = Math.cos(angle);
|
|
616
|
+
const s = Math.sin(angle);
|
|
617
|
+
const m = this.data;
|
|
618
|
+
|
|
619
|
+
for (let i = 0; i < 4; i++) {
|
|
620
|
+
const a0 = m[i]; // Col 0
|
|
621
|
+
const a3 = m[i + 12]; // Col 3
|
|
622
|
+
m[i] = a0 * c + a3 * s;
|
|
623
|
+
m[i + 12] = -a0 * s + a3 * c;
|
|
624
|
+
}
|
|
625
|
+
return this;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Rotate in YW plane in place
|
|
630
|
+
* @param {number} angle
|
|
631
|
+
* @returns {Mat4x4} this
|
|
632
|
+
*/
|
|
633
|
+
rotateYW(angle) {
|
|
634
|
+
const c = Math.cos(angle);
|
|
635
|
+
const s = Math.sin(angle);
|
|
636
|
+
const m = this.data;
|
|
637
|
+
|
|
638
|
+
for (let i = 0; i < 4; i++) {
|
|
639
|
+
const a1 = m[i + 4]; // Col 1
|
|
640
|
+
const a3 = m[i + 12]; // Col 3
|
|
641
|
+
m[i + 4] = a1 * c + a3 * s;
|
|
642
|
+
m[i + 12] = -a1 * s + a3 * c;
|
|
643
|
+
}
|
|
644
|
+
return this;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Rotate in ZW plane in place
|
|
649
|
+
* @param {number} angle
|
|
650
|
+
* @returns {Mat4x4} this
|
|
651
|
+
*/
|
|
652
|
+
rotateZW(angle) {
|
|
653
|
+
const c = Math.cos(angle);
|
|
654
|
+
const s = Math.sin(angle);
|
|
655
|
+
const m = this.data;
|
|
656
|
+
|
|
657
|
+
for (let i = 0; i < 4; i++) {
|
|
658
|
+
const a2 = m[i + 8]; // Col 2
|
|
659
|
+
const a3 = m[i + 12]; // Col 3
|
|
660
|
+
m[i + 8] = a2 * c + a3 * s;
|
|
661
|
+
m[i + 12] = -a2 * s + a3 * c;
|
|
662
|
+
}
|
|
663
|
+
return this;
|
|
664
|
+
}
|
|
665
|
+
|
|
550
666
|
// ========== ROTATION MATRICES FOR ALL 6 PLANES ==========
|
|
551
667
|
|
|
552
668
|
/**
|
|
@@ -681,12 +797,12 @@ export class Mat4x4 {
|
|
|
681
797
|
static rotationFromAngles(angles) {
|
|
682
798
|
let result = Mat4x4.identity();
|
|
683
799
|
|
|
684
|
-
if (angles.xy) result
|
|
685
|
-
if (angles.xz) result
|
|
686
|
-
if (angles.yz) result
|
|
687
|
-
if (angles.xw) result
|
|
688
|
-
if (angles.yw) result
|
|
689
|
-
if (angles.zw) result
|
|
800
|
+
if (angles.xy) result.rotateXY(angles.xy);
|
|
801
|
+
if (angles.xz) result.rotateXZ(angles.xz);
|
|
802
|
+
if (angles.yz) result.rotateYZ(angles.yz);
|
|
803
|
+
if (angles.xw) result.rotateXW(angles.xw);
|
|
804
|
+
if (angles.yw) result.rotateYW(angles.yw);
|
|
805
|
+
if (angles.zw) result.rotateZW(angles.zw);
|
|
690
806
|
|
|
691
807
|
return result;
|
|
692
808
|
}
|
package/src/math/Rotor4D.js
CHANGED
|
@@ -323,54 +323,108 @@ 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
|
-
* @
|
|
330
|
+
* @param {Vec4} [target] - Optional pre-allocated Vec4 to write result into
|
|
331
|
+
* @returns {Vec4} Rotated vector (target if provided, otherwise new Vec4)
|
|
328
332
|
*/
|
|
329
|
-
rotate(v) {
|
|
330
|
-
// For efficiency, we expand the sandwich product directly
|
|
331
|
-
// rather than doing two rotor multiplications
|
|
332
|
-
|
|
333
|
+
rotate(v, target) {
|
|
333
334
|
const x = v.x, y = v.y, z = v.z, w = v.w;
|
|
334
335
|
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// Then multiply by R† (reverse of rotor)
|
|
340
|
-
// Extract the vector part of the result
|
|
336
|
+
// Normalize for numerical stability (same as toMatrix)
|
|
337
|
+
const n = this.norm();
|
|
338
|
+
const invN = n > 1e-10 ? 1 / n : 1;
|
|
341
339
|
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
const
|
|
340
|
+
const s = this.s * invN;
|
|
341
|
+
const xy = this.xy * invN;
|
|
342
|
+
const xz = this.xz * invN;
|
|
343
|
+
const yz = this.yz * invN;
|
|
344
|
+
const xw = this.xw * invN;
|
|
345
|
+
const yw = this.yw * invN;
|
|
346
|
+
const zw = this.zw * invN;
|
|
347
|
+
const xyzw = this.xyzw * invN;
|
|
347
348
|
|
|
348
|
-
// Squared terms
|
|
349
|
+
// Squared terms
|
|
349
350
|
const s2 = s * s;
|
|
350
|
-
const xy2 = xy * xy
|
|
351
|
-
const
|
|
351
|
+
const xy2 = xy * xy;
|
|
352
|
+
const xz2 = xz * xz;
|
|
353
|
+
const yz2 = yz * yz;
|
|
354
|
+
const xw2 = xw * xw;
|
|
355
|
+
const yw2 = yw * yw;
|
|
356
|
+
const zw2 = zw * zw;
|
|
352
357
|
const xyzw2 = xyzw * xyzw;
|
|
353
358
|
|
|
354
|
-
//
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
359
|
+
// Cross terms (pre-multiplied by 2)
|
|
360
|
+
const sxy = 2 * s * xy;
|
|
361
|
+
const sxz = 2 * s * xz;
|
|
362
|
+
const syz = 2 * s * yz;
|
|
363
|
+
const sxw = 2 * s * xw;
|
|
364
|
+
const syw = 2 * s * yw;
|
|
365
|
+
const szw = 2 * s * zw;
|
|
366
|
+
|
|
367
|
+
const xzyz = 2 * xz * yz;
|
|
368
|
+
const xyyz = 2 * xy * yz;
|
|
369
|
+
const xyxz = 2 * xy * xz;
|
|
370
|
+
const xyxw = 2 * xy * xw;
|
|
371
|
+
const xyyw = 2 * xy * yw;
|
|
372
|
+
|
|
373
|
+
const xzxw = 2 * xz * xw;
|
|
374
|
+
const xzyw = 2 * xz * yw;
|
|
375
|
+
const xzzw = 2 * xz * zw;
|
|
376
|
+
|
|
377
|
+
const yzxw = 2 * yz * xw;
|
|
378
|
+
const yzyw = 2 * yz * yw;
|
|
379
|
+
const yzzw = 2 * yz * zw;
|
|
380
|
+
|
|
381
|
+
const xwyw = 2 * xw * yw;
|
|
382
|
+
const xwzw = 2 * xw * zw;
|
|
383
|
+
const ywzw = 2 * yw * zw;
|
|
384
|
+
|
|
385
|
+
const xyxyzw = 2 * xy * xyzw;
|
|
386
|
+
const xzxyzw = 2 * xz * xyzw;
|
|
387
|
+
const yzxyzw = 2 * yz * xyzw;
|
|
388
|
+
const xwxyzw = 2 * xw * xyzw;
|
|
389
|
+
const ywxyzw = 2 * yw * xyzw;
|
|
390
|
+
const zwxyzw = 2 * zw * xyzw;
|
|
391
|
+
|
|
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;
|
|
419
|
+
|
|
420
|
+
if (target) {
|
|
421
|
+
target.x = rx;
|
|
422
|
+
target.y = ry;
|
|
423
|
+
target.z = rz;
|
|
424
|
+
target.w = rw;
|
|
425
|
+
return target;
|
|
426
|
+
}
|
|
427
|
+
return new Vec4(rx, ry, rz, rw);
|
|
374
428
|
}
|
|
375
429
|
|
|
376
430
|
/**
|