@vib3code/sdk 2.0.3-canary.3b3ca18 → 2.0.3-canary.4e0dace
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/AGENT_HARNESS_ARCHITECTURE.md +2 -0
- package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
- package/DOCS/ARCHITECTURE.md +1 -0
- package/DOCS/CI_TESTING.md +2 -0
- package/DOCS/CLI_ONBOARDING.md +2 -0
- package/DOCS/CONTROL_REFERENCE.md +2 -0
- package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
- package/DOCS/ENV_SETUP.md +2 -0
- package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
- package/DOCS/EXPANSION_DESIGN.md +2 -0
- package/DOCS/EXPANSION_DESIGN_ULTRA.md +2 -0
- package/DOCS/EXPORT_FORMATS.md +2 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
- package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
- package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
- package/DOCS/LICENSING_TIERS.md +2 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +2 -0
- package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
- package/DOCS/OBS_SETUP_GUIDE.md +2 -0
- package/DOCS/OPTIMIZATION_PLAN_MATH.md +1 -0
- package/DOCS/PRODUCT_STRATEGY.md +2 -0
- package/DOCS/PROJECT_SETUP.md +2 -0
- package/DOCS/README.md +5 -3
- package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
- package/DOCS/RENDERER_LIFECYCLE.md +2 -0
- package/DOCS/REPO_MANIFEST.md +2 -0
- package/DOCS/ROADMAP.md +2 -0
- package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
- package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
- package/DOCS/STATUS.md +2 -0
- package/DOCS/SYSTEM_INVENTORY.md +2 -0
- package/DOCS/TELEMETRY_EXPORTS.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
- package/DOCS/WEBGPU_STATUS.md +2 -0
- package/DOCS/XR_BENCHMARKS.md +2 -0
- package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
- package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
- package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
- package/DOCS/archive/SESSION_014_PLAN.md +1 -195
- package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
- package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
- package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
- package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -38
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +2 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +2 -0
- package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +2 -0
- package/DOCS/dev-tracks/README.md +2 -0
- package/package.json +2 -4
- package/src/cli/index.js +59 -5
- package/src/geometry/warp/HypersphereCore.js +53 -24
- package/src/math/Mat4x4.js +86 -72
- package/src/math/Projection.js +39 -4
- package/src/math/Rotor4D.js +31 -1
- package/src/scene/Node4D.js +74 -24
- package/src/testing/ProjectionClass.test.js +38 -0
- package/tools/update_projection.py +109 -0
|
@@ -1,38 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
This document records the current WebGPU backend state, what is implemented, and what is required
|
|
4
|
-
to validate it in local development or CI.
|
|
5
|
-
|
|
6
|
-
## Current status
|
|
7
|
-
- **Backend scaffold:** `WebGPUBackend` initializes adapter/device, configures the canvas, manages
|
|
8
|
-
resize, and supports a clear-pass `renderFrame()` path.
|
|
9
|
-
- **Async context creation:** `createRenderContextAsync()` can instantiate WebGPU contexts using
|
|
10
|
-
`{ backend: 'webgpu' }`.
|
|
11
|
-
- **Resource tracking:** depth textures are registered in the shared `RenderResourceRegistry`.
|
|
12
|
-
|
|
13
|
-
## What is still needed
|
|
14
|
-
1. **Pipeline parity:** implement basic shader pipelines (vertex/fragment) and buffer binding that
|
|
15
|
-
match the WebGL backend command flow.
|
|
16
|
-
2. **Command buffer bridge:** map existing render commands to WebGPU render passes.
|
|
17
|
-
3. **Feature gating:** add host-app controls to toggle WebGPU via feature flags.
|
|
18
|
-
4. **Diagnostics:** add per-frame stats and resource delta reporting for WebGPU.
|
|
19
|
-
|
|
20
|
-
## Testing requirements
|
|
21
|
-
### Local smoke test
|
|
22
|
-
Prerequisites:
|
|
23
|
-
- A browser with WebGPU enabled (Chrome/Edge with `chrome://flags/#enable-unsafe-webgpu`, or a
|
|
24
|
-
Chromium build with WebGPU support).
|
|
25
|
-
- A device with WebGPU-capable GPU drivers.
|
|
26
|
-
|
|
27
|
-
Suggested smoke flow:
|
|
28
|
-
1. Create a canvas and call `createRenderContextAsync(canvas, { backend: 'webgpu' })`.
|
|
29
|
-
2. Call `backend.renderFrame({ clearColor: [0.1, 0.1, 0.2, 1] })` and confirm the canvas clears.
|
|
30
|
-
3. Resize the canvas and ensure the clear pass still succeeds.
|
|
31
|
-
|
|
32
|
-
### CI validation
|
|
33
|
-
- WebGPU cannot be reliably validated in headless CI without GPU support.
|
|
34
|
-
- CI should instead run WebGL tests and lint/static checks; keep a manual WebGPU smoke checklist.
|
|
35
|
-
|
|
36
|
-
## File locations
|
|
37
|
-
- `src/render/backends/WebGPUBackend.js`
|
|
38
|
-
- `src/render/index.js` (`createRenderContextAsync`)
|
|
1
|
+
Last reviewed: 2026-02-17
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vib3code/sdk",
|
|
3
|
-
"version": "2.0.3-canary.
|
|
3
|
+
"version": "2.0.3-canary.4e0dace",
|
|
4
4
|
"description": "VIB3+ 4D Visualization SDK - Unified engine with 6D rotation, MCP agentic integration, and cross-platform support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/core/VIB3Engine.js",
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
"vib3": "./src/cli/index.js",
|
|
10
10
|
"vib3-mcp": "./src/agent/mcp/stdio-server.js"
|
|
11
11
|
},
|
|
12
|
-
"sideEffects":
|
|
13
|
-
"./src/geometry/builders/*.js"
|
|
14
|
-
],
|
|
12
|
+
"sideEffects": false,
|
|
15
13
|
"exports": {
|
|
16
14
|
".": {
|
|
17
15
|
"types": "./types/adaptive-sdk.d.ts",
|
package/src/cli/index.js
CHANGED
|
@@ -5,9 +5,34 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { performance } from 'node:perf_hooks';
|
|
8
|
+
import path from 'node:path';
|
|
8
9
|
import { mcpServer, toolDefinitions } from '../agent/index.js';
|
|
9
10
|
import { schemaRegistry } from '../schemas/index.js';
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Resolves a file path and ensures it is within the current working directory.
|
|
14
|
+
* @param {string} filePath The path to validate
|
|
15
|
+
* @returns {string} The resolved absolute path
|
|
16
|
+
* @throws {Error} If the path is outside the allowed directory
|
|
17
|
+
*/
|
|
18
|
+
function getSafePath(filePath) {
|
|
19
|
+
if (!filePath) return filePath;
|
|
20
|
+
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
const resolvedPath = path.resolve(cwd, filePath);
|
|
23
|
+
const relative = path.relative(cwd, resolvedPath);
|
|
24
|
+
|
|
25
|
+
const isOutside = relative.startsWith('..') || path.isAbsolute(relative);
|
|
26
|
+
|
|
27
|
+
if (isOutside) {
|
|
28
|
+
const error = new Error('Security Error: Path traversal detected. Access denied.');
|
|
29
|
+
error.code = 'EACCES';
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return resolvedPath;
|
|
34
|
+
}
|
|
35
|
+
|
|
11
36
|
/**
|
|
12
37
|
* CLI Configuration
|
|
13
38
|
*/
|
|
@@ -446,7 +471,7 @@ async function handleTools(parsed, startTime) {
|
|
|
446
471
|
*/
|
|
447
472
|
async function handleValidate(parsed, startTime) {
|
|
448
473
|
const subcommand = parsed.subcommand || 'pack';
|
|
449
|
-
|
|
474
|
+
let filePath = parsed.options.file || parsed.options.f || parsed.positional[0];
|
|
450
475
|
|
|
451
476
|
if (!filePath && subcommand !== 'schema') {
|
|
452
477
|
return wrapResponse('validate', {
|
|
@@ -460,6 +485,10 @@ async function handleValidate(parsed, startTime) {
|
|
|
460
485
|
}
|
|
461
486
|
|
|
462
487
|
try {
|
|
488
|
+
if (filePath) {
|
|
489
|
+
filePath = getSafePath(filePath);
|
|
490
|
+
}
|
|
491
|
+
|
|
463
492
|
switch (subcommand) {
|
|
464
493
|
case 'pack': {
|
|
465
494
|
// Validate a .vib3 scene pack file
|
|
@@ -533,6 +562,17 @@ async function handleValidate(parsed, startTime) {
|
|
|
533
562
|
}, false, performance.now() - startTime);
|
|
534
563
|
}
|
|
535
564
|
} catch (error) {
|
|
565
|
+
if (error.code === 'EACCES') {
|
|
566
|
+
return wrapResponse('validate', {
|
|
567
|
+
error: {
|
|
568
|
+
type: 'SecurityError',
|
|
569
|
+
code: 'ACCESS_DENIED',
|
|
570
|
+
message: error.message,
|
|
571
|
+
suggestion: 'Ensure the file path is within the project directory'
|
|
572
|
+
}
|
|
573
|
+
}, false, performance.now() - startTime);
|
|
574
|
+
}
|
|
575
|
+
|
|
536
576
|
if (error.code === 'ENOENT') {
|
|
537
577
|
return wrapResponse('validate', {
|
|
538
578
|
error: {
|
|
@@ -659,7 +699,6 @@ async function main() {
|
|
|
659
699
|
*/
|
|
660
700
|
async function handleInit(parsed, startTime) {
|
|
661
701
|
const { writeFileSync, mkdirSync, existsSync } = await import('node:fs');
|
|
662
|
-
const { join } = await import('node:path');
|
|
663
702
|
|
|
664
703
|
const projectName = parsed.subcommand || parsed.positional[0] || 'my-vib3-app';
|
|
665
704
|
const template = parsed.options.template || parsed.options.t || 'vanilla';
|
|
@@ -677,7 +716,22 @@ async function handleInit(parsed, startTime) {
|
|
|
677
716
|
}, false, performance.now() - startTime);
|
|
678
717
|
}
|
|
679
718
|
|
|
680
|
-
|
|
719
|
+
let projectDir;
|
|
720
|
+
try {
|
|
721
|
+
projectDir = getSafePath(projectName);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
if (error.code === 'EACCES') {
|
|
724
|
+
return wrapResponse('init', {
|
|
725
|
+
error: {
|
|
726
|
+
type: 'SecurityError',
|
|
727
|
+
code: 'ACCESS_DENIED',
|
|
728
|
+
message: error.message,
|
|
729
|
+
suggestion: 'Choose a project name that results in a valid subdirectory'
|
|
730
|
+
}
|
|
731
|
+
}, false, performance.now() - startTime);
|
|
732
|
+
}
|
|
733
|
+
throw error;
|
|
734
|
+
}
|
|
681
735
|
|
|
682
736
|
if (existsSync(projectDir)) {
|
|
683
737
|
return wrapResponse('init', {
|
|
@@ -695,8 +749,8 @@ async function handleInit(parsed, startTime) {
|
|
|
695
749
|
const files = getTemplateFiles(template, projectName);
|
|
696
750
|
|
|
697
751
|
for (const [filename, content] of Object.entries(files)) {
|
|
698
|
-
const filepath = join(projectDir, filename);
|
|
699
|
-
const dir = join(projectDir, filename.split('/').slice(0, -1).join('/'));
|
|
752
|
+
const filepath = path.join(projectDir, filename);
|
|
753
|
+
const dir = path.join(projectDir, filename.split('/').slice(0, -1).join('/'));
|
|
700
754
|
if (dir !== projectDir) {
|
|
701
755
|
mkdirSync(dir, { recursive: true });
|
|
702
756
|
}
|
|
@@ -16,13 +16,14 @@ import { Vec4 } from '../../math/Vec4.js';
|
|
|
16
16
|
* @param {number} radius - Hypersphere radius
|
|
17
17
|
* @returns {Vec4} Point on hypersphere
|
|
18
18
|
*/
|
|
19
|
-
export function projectToHypersphere(point, radius = 1) {
|
|
19
|
+
export function projectToHypersphere(point, radius = 1, target = null) {
|
|
20
20
|
const len = point.length();
|
|
21
21
|
if (len < 0.0001) {
|
|
22
22
|
// Handle origin - project to north pole
|
|
23
|
+
if (target) return target.set(0, 0, 0, radius);
|
|
23
24
|
return new Vec4(0, 0, 0, radius);
|
|
24
25
|
}
|
|
25
|
-
return point.scale(radius / len);
|
|
26
|
+
return point.scale(radius / len, target);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -30,9 +31,10 @@ export function projectToHypersphere(point, radius = 1) {
|
|
|
30
31
|
* Maps all of 3D space onto the 4D hypersphere
|
|
31
32
|
* @param {Vec4} point - Input point (uses x, y, z)
|
|
32
33
|
* @param {number} radius - Hypersphere radius
|
|
34
|
+
* @param {Vec4} [target=null] - Optional target vector
|
|
33
35
|
* @returns {Vec4} Point on hypersphere
|
|
34
36
|
*/
|
|
35
|
-
export function stereographicToHypersphere(point, radius = 1) {
|
|
37
|
+
export function stereographicToHypersphere(point, radius = 1, target = null) {
|
|
36
38
|
const x = point.x;
|
|
37
39
|
const y = point.y;
|
|
38
40
|
const z = point.z;
|
|
@@ -40,6 +42,15 @@ export function stereographicToHypersphere(point, radius = 1) {
|
|
|
40
42
|
const sumSq = x * x + y * y + z * z;
|
|
41
43
|
const denom = sumSq + 1;
|
|
42
44
|
|
|
45
|
+
if (target) {
|
|
46
|
+
return target.set(
|
|
47
|
+
(2 * x) / denom * radius,
|
|
48
|
+
(2 * y) / denom * radius,
|
|
49
|
+
(2 * z) / denom * radius,
|
|
50
|
+
(sumSq - 1) / denom * radius
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
return new Vec4(
|
|
44
55
|
(2 * x) / denom * radius,
|
|
45
56
|
(2 * y) / denom * radius,
|
|
@@ -56,12 +67,22 @@ export function stereographicToHypersphere(point, radius = 1) {
|
|
|
56
67
|
* @param {number} phi - Azimuth on base S² (0 to 2π)
|
|
57
68
|
* @param {number} psi - Fiber angle (0 to 2π)
|
|
58
69
|
* @param {number} radius - Hypersphere radius
|
|
70
|
+
* @param {Vec4} [target=null] - Optional target vector
|
|
59
71
|
* @returns {Vec4} Point on hypersphere
|
|
60
72
|
*/
|
|
61
|
-
export function hopfFibration(theta, phi, psi, radius = 1) {
|
|
73
|
+
export function hopfFibration(theta, phi, psi, radius = 1, target = null) {
|
|
62
74
|
const cosTheta2 = Math.cos(theta / 2);
|
|
63
75
|
const sinTheta2 = Math.sin(theta / 2);
|
|
64
76
|
|
|
77
|
+
if (target) {
|
|
78
|
+
return target.set(
|
|
79
|
+
cosTheta2 * Math.cos((phi + psi) / 2) * radius,
|
|
80
|
+
cosTheta2 * Math.sin((phi + psi) / 2) * radius,
|
|
81
|
+
sinTheta2 * Math.cos((phi - psi) / 2) * radius,
|
|
82
|
+
sinTheta2 * Math.sin((phi - psi) / 2) * radius
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
65
86
|
return new Vec4(
|
|
66
87
|
cosTheta2 * Math.cos((phi + psi) / 2) * radius,
|
|
67
88
|
cosTheta2 * Math.sin((phi + psi) / 2) * radius,
|
|
@@ -78,8 +99,9 @@ export function hopfFibration(theta, phi, psi, radius = 1) {
|
|
|
78
99
|
* @returns {Vec4[]} Warped vertices
|
|
79
100
|
*/
|
|
80
101
|
export function warpRadial(vertices, radius = 1, blendFactor = 1) {
|
|
102
|
+
const onSphere = new Vec4();
|
|
81
103
|
return vertices.map(v => {
|
|
82
|
-
|
|
104
|
+
projectToHypersphere(v, radius, onSphere);
|
|
83
105
|
return v.lerp(onSphere, blendFactor);
|
|
84
106
|
});
|
|
85
107
|
}
|
|
@@ -93,8 +115,9 @@ export function warpRadial(vertices, radius = 1, blendFactor = 1) {
|
|
|
93
115
|
* @returns {Vec4[]} Warped vertices
|
|
94
116
|
*/
|
|
95
117
|
export function warpStereographic(vertices, radius = 1, scale = 1) {
|
|
118
|
+
const scaled = new Vec4();
|
|
96
119
|
return vertices.map(v => {
|
|
97
|
-
|
|
120
|
+
v.scale(scale, scaled);
|
|
98
121
|
return stereographicToHypersphere(scaled, radius);
|
|
99
122
|
});
|
|
100
123
|
}
|
|
@@ -146,25 +169,31 @@ export function warpHypersphereCore(geometry, options = {}) {
|
|
|
146
169
|
twist = 1
|
|
147
170
|
} = options;
|
|
148
171
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
const temp = new Vec4();
|
|
173
|
+
const warpedVertices = geometry.vertices.map(v => {
|
|
174
|
+
// Combined scaling and warping to minimize allocations
|
|
175
|
+
const result = v.scale(scale);
|
|
176
|
+
|
|
177
|
+
if (method === 'stereographic') {
|
|
178
|
+
stereographicToHypersphere(result, radius, result);
|
|
179
|
+
} else if (method === 'hopf') {
|
|
180
|
+
const r = result.length();
|
|
181
|
+
if (r < 0.0001) {
|
|
182
|
+
result.set(0, 0, 0, radius);
|
|
183
|
+
} else {
|
|
184
|
+
const theta = Math.acos(result.z / r);
|
|
185
|
+
const phi = Math.atan2(result.y, result.x);
|
|
186
|
+
const psi = result.w * twist + phi * 0.5;
|
|
187
|
+
hopfFibration(theta, phi, psi, radius, result);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
// Radial (default)
|
|
191
|
+
projectToHypersphere(result, radius, temp);
|
|
192
|
+
result.lerp(temp, blend, result);
|
|
193
|
+
}
|
|
162
194
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
warpedVertices = warpRadial(scaledVertices, radius, blend);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
195
|
+
return result;
|
|
196
|
+
});
|
|
168
197
|
|
|
169
198
|
return {
|
|
170
199
|
...geometry,
|
package/src/math/Mat4x4.js
CHANGED
|
@@ -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(
|
|
64
|
+
return new Mat4x4(Mat4x4.UNINITIALIZED);
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
/**
|
|
@@ -161,7 +164,7 @@ export class Mat4x4 {
|
|
|
161
164
|
* @returns {Mat4x4} New matrix = this * m
|
|
162
165
|
*/
|
|
163
166
|
multiply(m, target = null) {
|
|
164
|
-
const out = target || new Mat4x4();
|
|
167
|
+
const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
|
|
165
168
|
const r = out.data;
|
|
166
169
|
const a = this.data;
|
|
167
170
|
const b = m.data;
|
|
@@ -321,7 +324,7 @@ export class Mat4x4 {
|
|
|
321
324
|
* @returns {Mat4x4} New matrix
|
|
322
325
|
*/
|
|
323
326
|
add(m, target = null) {
|
|
324
|
-
const out = target || new Mat4x4();
|
|
327
|
+
const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
|
|
325
328
|
const r = out.data;
|
|
326
329
|
const a = this.data;
|
|
327
330
|
const b = m.data;
|
|
@@ -339,7 +342,7 @@ export class Mat4x4 {
|
|
|
339
342
|
* @returns {Mat4x4} New matrix
|
|
340
343
|
*/
|
|
341
344
|
scale(s, target = null) {
|
|
342
|
-
const out = target || new Mat4x4();
|
|
345
|
+
const out = target || new Mat4x4(Mat4x4.UNINITIALIZED);
|
|
343
346
|
const r = out.data;
|
|
344
347
|
const a = this.data;
|
|
345
348
|
|
|
@@ -355,12 +358,13 @@ export class Mat4x4 {
|
|
|
355
358
|
*/
|
|
356
359
|
transpose() {
|
|
357
360
|
const m = this.data;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
]
|
|
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;
|
|
364
368
|
}
|
|
365
369
|
|
|
366
370
|
/**
|
|
@@ -415,7 +419,8 @@ export class Mat4x4 {
|
|
|
415
419
|
*/
|
|
416
420
|
inverse() {
|
|
417
421
|
const m = this.data;
|
|
418
|
-
const
|
|
422
|
+
const out = new Mat4x4(Mat4x4.UNINITIALIZED);
|
|
423
|
+
const inv = out.data;
|
|
419
424
|
|
|
420
425
|
inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] +
|
|
421
426
|
m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
|
|
@@ -476,7 +481,7 @@ export class Mat4x4 {
|
|
|
476
481
|
inv[i] *= invDet;
|
|
477
482
|
}
|
|
478
483
|
|
|
479
|
-
return
|
|
484
|
+
return out;
|
|
480
485
|
}
|
|
481
486
|
|
|
482
487
|
/**
|
|
@@ -689,12 +694,13 @@ export class Mat4x4 {
|
|
|
689
694
|
static rotationXY(angle) {
|
|
690
695
|
const c = Math.cos(angle);
|
|
691
696
|
const s = Math.sin(angle);
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
]
|
|
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;
|
|
698
704
|
}
|
|
699
705
|
|
|
700
706
|
/**
|
|
@@ -705,12 +711,13 @@ export class Mat4x4 {
|
|
|
705
711
|
static rotationXZ(angle) {
|
|
706
712
|
const c = Math.cos(angle);
|
|
707
713
|
const s = Math.sin(angle);
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
]
|
|
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;
|
|
714
721
|
}
|
|
715
722
|
|
|
716
723
|
/**
|
|
@@ -721,12 +728,13 @@ export class Mat4x4 {
|
|
|
721
728
|
static rotationYZ(angle) {
|
|
722
729
|
const c = Math.cos(angle);
|
|
723
730
|
const s = Math.sin(angle);
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
]
|
|
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;
|
|
730
738
|
}
|
|
731
739
|
|
|
732
740
|
/**
|
|
@@ -738,12 +746,13 @@ export class Mat4x4 {
|
|
|
738
746
|
static rotationXW(angle) {
|
|
739
747
|
const c = Math.cos(angle);
|
|
740
748
|
const s = Math.sin(angle);
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
]
|
|
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;
|
|
747
756
|
}
|
|
748
757
|
|
|
749
758
|
/**
|
|
@@ -754,12 +763,13 @@ export class Mat4x4 {
|
|
|
754
763
|
static rotationYW(angle) {
|
|
755
764
|
const c = Math.cos(angle);
|
|
756
765
|
const s = Math.sin(angle);
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
]
|
|
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;
|
|
763
773
|
}
|
|
764
774
|
|
|
765
775
|
/**
|
|
@@ -770,12 +780,13 @@ export class Mat4x4 {
|
|
|
770
780
|
static rotationZW(angle) {
|
|
771
781
|
const c = Math.cos(angle);
|
|
772
782
|
const s = Math.sin(angle);
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
]
|
|
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;
|
|
779
790
|
}
|
|
780
791
|
|
|
781
792
|
/**
|
|
@@ -847,12 +858,13 @@ export class Mat4x4 {
|
|
|
847
858
|
* @returns {Mat4x4}
|
|
848
859
|
*/
|
|
849
860
|
static uniformScale(s) {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
]
|
|
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;
|
|
856
868
|
}
|
|
857
869
|
|
|
858
870
|
/**
|
|
@@ -864,12 +876,13 @@ export class Mat4x4 {
|
|
|
864
876
|
* @returns {Mat4x4}
|
|
865
877
|
*/
|
|
866
878
|
static scale(sx, sy, sz, sw = 1) {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
]
|
|
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;
|
|
873
886
|
}
|
|
874
887
|
|
|
875
888
|
/**
|
|
@@ -885,12 +898,13 @@ export class Mat4x4 {
|
|
|
885
898
|
static translation(tx, ty, tz, tw = 0) {
|
|
886
899
|
// For true 4D translation, you need 5D homogeneous coordinates
|
|
887
900
|
// This is a placeholder that adds the translation to the W column
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
]
|
|
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;
|
|
894
908
|
}
|
|
895
909
|
}
|
|
896
910
|
|