@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
@@ -1,38 +1 @@
1
- # WebGPU status and testing requirements
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
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Dev Track Session — January 31, 2026
2
4
 
3
5
  **Branch**: `claude/review-project-status-BwVbr`
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Development Session — 2026-02-06
2
4
 
3
5
  **Session type**: Full codebase audit + hygiene + MCP server + agent docs + testing
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Development Session — 2026-02-13
2
4
 
3
5
  **Session type**: Agent Harness Implementation — MCP tools, ChoreographyPlayer, aesthetic mapping, headless rendering
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Development Session — 2026-02-15
2
4
 
3
5
  **Session type**: Layer Architecture Redesign, Codebase Audit, Preset/Reactivity Expansion
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Development Session — 2026-02-16
2
4
 
3
5
  **Session type**: Architecture Bug Fixes, Shader Consistency, Documentation Sweep
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Performance Upgrade Report — 2026-02-16
2
4
 
3
5
  **Type**: CPU-side math optimization (Rotor4D + Vec4)
@@ -1,3 +1,5 @@
1
+ Last reviewed: 2026-02-17
2
+
1
3
  # Development Track Logs
2
4
 
3
5
  Detailed, session-level implementation notes are stored here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vib3code/sdk",
3
- "version": "2.0.3-canary.590fbae",
3
+ "version": "2.0.3-canary.69d53b3",
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",
@@ -0,0 +1,72 @@
1
+ /**
2
+ * GameLoop - Fixed-Timestep Physics Loop
3
+ *
4
+ * Provides a robust game loop that decouples physics updates (fixed step)
5
+ * from rendering (variable step). This is crucial for consistent physics
6
+ * and smooth rendering across different device capabilities.
7
+ *
8
+ * @experimental
9
+ */
10
+ export class GameLoop {
11
+ /**
12
+ * @param {function(number)} updateFn - Physics update (fixed dt)
13
+ * @param {function(number)} renderFn - Render update (interpolated alpha)
14
+ * @param {number} step - Physics step size in seconds (default 1/60)
15
+ */
16
+ constructor(updateFn, renderFn, step = 1 / 60) {
17
+ this.updateFn = updateFn;
18
+ this.renderFn = renderFn;
19
+ this.step = step;
20
+ this.dt = 0;
21
+ this.last = 0;
22
+ this.now = 0;
23
+ this.accumulator = 0;
24
+ this.running = false;
25
+ this.rafId = null;
26
+
27
+ // Bind loop
28
+ this.frame = this.frame.bind(this);
29
+ }
30
+
31
+ start() {
32
+ if (this.running) return;
33
+ this.running = true;
34
+ this.last = performance.now();
35
+ this.accumulator = 0;
36
+ this.rafId = requestAnimationFrame(this.frame);
37
+ console.log('GameLoop: Started.');
38
+ }
39
+
40
+ stop() {
41
+ this.running = false;
42
+ if (this.rafId) {
43
+ cancelAnimationFrame(this.rafId);
44
+ this.rafId = null;
45
+ }
46
+ console.log('GameLoop: Stopped.');
47
+ }
48
+
49
+ frame(timestamp) {
50
+ if (!this.running) return;
51
+
52
+ this.now = timestamp;
53
+ // Cap dt to avoid "spiral of death" on lag spikes (max 1s)
54
+ this.dt = Math.min(1, (this.now - this.last) / 1000);
55
+ this.last = this.now;
56
+
57
+ this.accumulator += this.dt;
58
+
59
+ // Consume accumulator in fixed steps
60
+ while (this.accumulator >= this.step) {
61
+ this.updateFn(this.step);
62
+ this.accumulator -= this.step;
63
+ }
64
+
65
+ // Render with interpolation factor alpha
66
+ // alpha = accumulator / step
67
+ // Allows renderer to interpolate between previous and current physics state
68
+ this.renderFn(this.accumulator / this.step);
69
+
70
+ this.rafId = requestAnimationFrame(this.frame);
71
+ }
72
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * LatticePhysics - Function-Based Collision Detection
3
+ *
4
+ * Provides a physics engine for "Lattice Worlds" where geometry is defined
5
+ * by mathematical density functions (SDFs, fractals).
6
+ *
7
+ * @experimental
8
+ */
9
+ export class LatticePhysics {
10
+ constructor() {
11
+ this.gravity = 9.8; // m/s²
12
+ this.friction = 0.95; // Velocity decay per step
13
+ this.densityThreshold = 0.8; // Collision threshold (0-1)
14
+ }
15
+
16
+ /**
17
+ * Update physics for all entities in the universe.
18
+ * @param {Map<string, object>} entities
19
+ * @param {number} dt
20
+ */
21
+ update(entities, dt) {
22
+ entities.forEach(entity => {
23
+ if (entity.physics && entity.active) {
24
+ this.updateEntity(entity, dt);
25
+ }
26
+ });
27
+ }
28
+
29
+ /**
30
+ * Update a single entity's physics state.
31
+ * @param {object} entity
32
+ * @param {number} dt
33
+ */
34
+ updateEntity(entity, dt) {
35
+ const { pos, vel, acc } = entity.physics;
36
+
37
+ // Apply forces (Gravity)
38
+ // In this abstract world, gravity pulls "down" in Y
39
+ acc.y -= this.gravity * dt;
40
+
41
+ // Integrate Velocity (Euler)
42
+ vel.x += acc.x * dt;
43
+ vel.y += acc.y * dt;
44
+ vel.z += acc.z * dt;
45
+
46
+ // Reset acceleration (forces are transient)
47
+ acc.x = 0; acc.y = 0; acc.z = 0;
48
+
49
+ // Collision Check (Projected Position)
50
+ const nextX = pos.x + vel.x * dt;
51
+ const nextY = pos.y + vel.y * dt;
52
+ const nextZ = pos.z + vel.z * dt;
53
+
54
+ // Sample density at next position
55
+ const density = this.getDensityAt(nextX, nextY, nextZ);
56
+
57
+ if (density > this.densityThreshold) {
58
+ // Collision!
59
+ // Simple response: Stop velocity component and push out
60
+ // A real engine would calculate surface normal from gradient
61
+
62
+ // Simplified: Just stop movement and bounce slightly
63
+ vel.x *= -0.5;
64
+ vel.y *= -0.5;
65
+ vel.z *= -0.5;
66
+
67
+ // Don't update position into solid
68
+ } else {
69
+ // Move freely
70
+ pos.x = nextX;
71
+ pos.y = nextY;
72
+ pos.z = nextZ;
73
+ }
74
+
75
+ // Apply Friction (Air/Ether drag)
76
+ vel.x *= this.friction;
77
+ vel.y *= this.friction;
78
+ vel.z *= this.friction;
79
+ }
80
+
81
+ /**
82
+ * Sample the "world density" at a given point.
83
+ * This mimics the shader's generation logic (e.g., fractal noise).
84
+ * @param {number} x
85
+ * @param {number} y
86
+ * @param {number} z
87
+ * @returns {number} Density 0.0 to 1.0
88
+ */
89
+ getDensityAt(x, y, z) {
90
+ // Mock function: simple floor plane at y = -2
91
+ if (y < -2) return 1.0;
92
+
93
+ // Mock function: occasional "floating islands" based on sine waves
94
+ // simulating the VIB3 lattice structure
95
+ const noise = (Math.sin(x * 0.5) + Math.cos(z * 0.5)) * 0.5 + 0.5;
96
+ if (y > 0 && y < 1 && noise > 0.8) return 1.0;
97
+
98
+ return 0.0;
99
+ }
100
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * LiveDirector - Autonomous Creative Agent
3
+ *
4
+ * An AI agent that analyzes user input ("Audience Reaction") and adjusts the
5
+ * VIB3Universe in real-time to maintain engagement, flow, and narrative tension.
6
+ *
7
+ * @experimental
8
+ */
9
+ export class LiveDirector {
10
+ constructor(universe) {
11
+ this.universe = universe;
12
+ this.active = false;
13
+
14
+ // Audience State
15
+ this.audience = {
16
+ energy: 0.5, // 0.0 (Bored) -> 1.0 (Excited)
17
+ attention: 0.8, // 0.0 (Distracted) -> 1.0 (Focused)
18
+ sentiment: 0.0, // -1.0 (Negative) -> 1.0 (Positive)
19
+ };
20
+
21
+ // Directing State
22
+ this.pacing = 'build'; // 'intro', 'build', 'climax', 'resolve'
23
+ this.lastActionTime = 0;
24
+ this.decisionInterval = 2000; // ms
25
+
26
+ // Bind methods
27
+ this.update = this.update.bind(this);
28
+ }
29
+
30
+ /**
31
+ * Start the director loop.
32
+ */
33
+ start() {
34
+ if (this.active) return;
35
+ this.active = true;
36
+ this.lastActionTime = performance.now();
37
+ requestAnimationFrame(this.update);
38
+ console.log('LiveDirector: Started directing.');
39
+ }
40
+
41
+ /**
42
+ * Stop the director loop.
43
+ */
44
+ stop() {
45
+ this.active = false;
46
+ console.log('LiveDirector: Stopped directing.');
47
+ }
48
+
49
+ /**
50
+ * Feed audience input signal.
51
+ * @param {string} type - 'audio', 'video', 'input'
52
+ * @param {object} data - Analysis data
53
+ */
54
+ feedInput(type, data) {
55
+ if (type === 'audio') {
56
+ // Loud audio = high energy
57
+ this.audience.energy = Math.min(1.0, this.audience.energy + data.volume * 0.1);
58
+ } else if (type === 'input') {
59
+ // Interaction = high attention
60
+ this.audience.attention = Math.min(1.0, this.audience.attention + 0.05);
61
+ }
62
+
63
+ // Decay logic runs in update loop
64
+ }
65
+
66
+ /**
67
+ * Main decision loop.
68
+ * @param {number} timestamp
69
+ */
70
+ update(timestamp) {
71
+ if (!this.active) return;
72
+
73
+ const dt = (timestamp - this.lastActionTime);
74
+
75
+ // Decay audience metrics over time
76
+ this.audience.energy = Math.max(0, this.audience.energy - 0.001);
77
+ this.audience.attention = Math.max(0, this.audience.attention - 0.0005);
78
+
79
+ // Make a directing decision periodically
80
+ if (dt > this.decisionInterval) {
81
+ this.makeDecision();
82
+ this.lastActionTime = timestamp;
83
+ }
84
+
85
+ requestAnimationFrame(this.update);
86
+ }
87
+
88
+ /**
89
+ * The "Brain" of the Director.
90
+ * Decides what to change based on current state.
91
+ */
92
+ makeDecision() {
93
+ const { energy, attention } = this.audience;
94
+
95
+ console.log(`LiveDirector: Audience state - Energy: ${energy.toFixed(2)}, Attention: ${attention.toFixed(2)}`);
96
+
97
+ // Strategy: Maintain a "Sine Wave" of tension
98
+ // If energy is too low, spike it. If too high, calm it down.
99
+
100
+ if (attention < 0.3) {
101
+ // Lost attention -> TRIGGER EVENT
102
+ this.triggerEvent('focus_snap');
103
+ } else if (energy < 0.2) {
104
+ // Boring -> INCREASE INTENSITY
105
+ this.adjustGlobalParams({ speed: 1.5, chaos: 0.4 });
106
+ } else if (energy > 0.8) {
107
+ // Too frantic -> CALM DOWN
108
+ this.adjustGlobalParams({ speed: 0.5, chaos: 0.1 });
109
+ } else {
110
+ // Just right -> DO NOTHING or subtle shift
111
+ // Maybe drift hue slightly?
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Execute a parameter adjustment across all actors.
117
+ * @param {object} params
118
+ */
119
+ adjustGlobalParams(params) {
120
+ console.log('LiveDirector: Adjusting global parameters', params);
121
+ this.universe.actors.forEach(actor => {
122
+ if (actor.animator) {
123
+ actor.animator.transition(params, 2000, 'easeInOut');
124
+ }
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Trigger a specific scripted event.
130
+ * @param {string} eventName
131
+ */
132
+ triggerEvent(eventName) {
133
+ console.log(`LiveDirector: Triggering event '${eventName}'`);
134
+ // Example: Flash screen, spawn particle burst, etc.
135
+ if (eventName === 'focus_snap') {
136
+ // Quick snap zoom / flash
137
+ this.adjustGlobalParams({ intensity: 1.0, speed: 0.0 });
138
+ setTimeout(() => {
139
+ this.adjustGlobalParams({ intensity: 0.5, speed: 1.0 });
140
+ }, 200);
141
+ }
142
+ }
143
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * PlayerController4D - Navigation in Hyperspace
3
+ *
4
+ * Maps 2D/3D inputs (WASD, Mouse) into 4D motion vectors (X, Y, Z, W).
5
+ * Handles movement, strafing, and "portal rotation" (XW/YW planes).
6
+ *
7
+ * @experimental
8
+ */
9
+ export class PlayerController4D {
10
+ /**
11
+ * @param {HTMLElement} domElement - Element to listen for events on
12
+ * @param {object} engine - VIB3Engine instance to drive
13
+ */
14
+ constructor(domElement, engine) {
15
+ this.domElement = domElement;
16
+ this.engine = engine;
17
+
18
+ // Input State
19
+ this.keys = {
20
+ w: false, a: false, s: false, d: false,
21
+ q: false, e: false, space: false, shift: false
22
+ };
23
+
24
+ this.mouse = {
25
+ dx: 0, dy: 0,
26
+ down: false
27
+ };
28
+
29
+ // Player Physics State
30
+ this.velocity = { x: 0, y: 0, z: 0, w: 0 };
31
+ this.rotation = { x: 0, y: 0 }; // Looking direction (Pitch/Yaw)
32
+ this.portalRot = 0; // XW plane rotation
33
+
34
+ // Config
35
+ this.speed = 5.0;
36
+ this.sensitivity = 0.002;
37
+ this.damping = 0.9;
38
+
39
+ // Bind events
40
+ this.onKeyDown = this.onKeyDown.bind(this);
41
+ this.onKeyUp = this.onKeyUp.bind(this);
42
+ this.onMouseMove = this.onMouseMove.bind(this);
43
+ this.onMouseDown = this.onMouseDown.bind(this);
44
+ this.onMouseUp = this.onMouseUp.bind(this);
45
+
46
+ this.setupListeners();
47
+ }
48
+
49
+ setupListeners() {
50
+ window.addEventListener('keydown', this.onKeyDown);
51
+ window.addEventListener('keyup', this.onKeyUp);
52
+ this.domElement.addEventListener('mousemove', this.onMouseMove);
53
+ this.domElement.addEventListener('mousedown', this.onMouseDown);
54
+ this.domElement.addEventListener('mouseup', this.onMouseUp);
55
+ }
56
+
57
+ onKeyDown(e) {
58
+ const k = e.key.toLowerCase();
59
+ if (this.keys.hasOwnProperty(k)) this.keys[k] = true;
60
+ }
61
+
62
+ onKeyUp(e) {
63
+ const k = e.key.toLowerCase();
64
+ if (this.keys.hasOwnProperty(k)) this.keys[k] = false;
65
+ }
66
+
67
+ onMouseDown() { this.mouse.down = true; }
68
+ onMouseUp() { this.mouse.down = false; }
69
+
70
+ onMouseMove(e) {
71
+ if (this.mouse.down) {
72
+ this.mouse.dx += e.movementX;
73
+ this.mouse.dy += e.movementY;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Update loop called by GameLoop.
79
+ * @param {number} dt
80
+ */
81
+ update(dt) {
82
+ // 1. Process Rotation (Mouse)
83
+ this.rotation.y -= this.mouse.dx * this.sensitivity; // Yaw
84
+ this.rotation.x -= this.mouse.dy * this.sensitivity; // Pitch
85
+
86
+ // Clamp pitch to avoid flipping
87
+ this.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, this.rotation.x));
88
+
89
+ // Reset mouse delta (consumed)
90
+ this.mouse.dx = 0;
91
+ this.mouse.dy = 0;
92
+
93
+ // 2. Process Movement (WASD)
94
+ // Forward vector derived from Yaw
95
+ const fwdX = Math.sin(this.rotation.y);
96
+ const fwdZ = Math.cos(this.rotation.y);
97
+ const rightX = Math.cos(this.rotation.y); // Perpendicular
98
+ const rightZ = -Math.sin(this.rotation.y);
99
+
100
+ const moveSpeed = this.speed * dt;
101
+
102
+ if (this.keys.w) {
103
+ this.velocity.x += fwdX * moveSpeed;
104
+ this.velocity.z -= fwdZ * moveSpeed; // WebGL Z is negative forward
105
+ }
106
+ if (this.keys.s) {
107
+ this.velocity.x -= fwdX * moveSpeed;
108
+ this.velocity.z += fwdZ * moveSpeed;
109
+ }
110
+ if (this.keys.a) {
111
+ this.velocity.x -= rightX * moveSpeed;
112
+ this.velocity.z += rightZ * moveSpeed;
113
+ }
114
+ if (this.keys.d) {
115
+ this.velocity.x += rightX * moveSpeed;
116
+ this.velocity.z -= rightZ * moveSpeed;
117
+ }
118
+
119
+ // Vertical Movement (Space/Shift)
120
+ if (this.keys.space) this.velocity.y += moveSpeed;
121
+ if (this.keys.shift) this.velocity.y -= moveSpeed;
122
+
123
+ // 4D Portal Rotation (Q/E)
124
+ if (this.keys.q) this.portalRot -= moveSpeed;
125
+ if (this.keys.e) this.portalRot += moveSpeed;
126
+
127
+ // Apply Damping (Friction)
128
+ this.velocity.x *= this.damping;
129
+ this.velocity.y *= this.damping;
130
+ this.velocity.z *= this.damping;
131
+
132
+ // 3. Apply to VIB3Engine Parameters
133
+ // Map 4D position to shader uniforms (e.g., u_noiseOffset or camera pos)
134
+ // Here we map to rotation parameters as a proxy for camera movement
135
+
136
+ // Visual feedback: Velocity tilts the view
137
+ this.engine.setParameter('rot4dXY', this.rotation.y + this.velocity.x * 0.1);
138
+ this.engine.setParameter('rot4dYZ', this.rotation.x + this.velocity.y * 0.1);
139
+
140
+ // Portal rotation affects XW plane
141
+ this.engine.setParameter('rot4dXW', this.portalRot);
142
+
143
+ // "Moving forward" increases grid density/scale to simulate zooming through
144
+ // In a real implementation, we'd update a u_cameraPosition uniform
145
+ }
146
+
147
+ destroy() {
148
+ window.removeEventListener('keydown', this.onKeyDown);
149
+ window.removeEventListener('keyup', this.onKeyUp);
150
+ this.domElement.removeEventListener('mousemove', this.onMouseMove);
151
+ this.domElement.removeEventListener('mousedown', this.onMouseDown);
152
+ this.domElement.removeEventListener('mouseup', this.onMouseUp);
153
+ }
154
+ }