@vib3code/sdk 2.0.3-canary.0e9a1ac → 2.0.3-canary.183c93e

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 (90) 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 +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 +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 +1 -1
  56. package/src/agent/mcp/MCPServer.js +346 -188
  57. package/src/agent/mcp/tools.js +45 -32
  58. package/src/experimental/GameLoop.js +72 -0
  59. package/src/experimental/LatticePhysics.js +100 -0
  60. package/src/experimental/LiveDirector.js +143 -0
  61. package/src/experimental/PlayerController4D.js +154 -0
  62. package/src/experimental/VIB3Actor.js +138 -0
  63. package/src/experimental/VIB3Compositor.js +117 -0
  64. package/src/experimental/VIB3Link.js +122 -0
  65. package/src/experimental/VIB3Orchestrator.js +146 -0
  66. package/src/experimental/VIB3Universe.js +109 -0
  67. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  68. package/src/faceted/FacetedSystem.js +19 -6
  69. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  70. package/src/geometry/generators/Crystal.js +2 -2
  71. package/src/holograms/HolographicVisualizer.js +58 -89
  72. package/src/math/Mat4x4.js +225 -36
  73. package/src/math/Rotor4D.js +124 -40
  74. package/src/math/Vec4.js +200 -103
  75. package/src/quantum/QuantumVisualizer.js +24 -20
  76. package/src/render/ShaderLoader.js +38 -0
  77. package/src/render/ShaderProgram.js +4 -4
  78. package/src/render/UnifiedRenderBridge.js +1 -1
  79. package/src/render/backends/WebGPUBackend.js +8 -4
  80. package/src/scene/Node4D.js +74 -24
  81. package/src/shaders/common/geometry24.glsl +65 -0
  82. package/src/shaders/common/geometry24.wgsl +54 -0
  83. package/src/shaders/common/rotation4d.glsl +4 -4
  84. package/src/shaders/common/rotation4d.wgsl +2 -2
  85. package/src/shaders/common/uniforms.wgsl +15 -8
  86. package/src/shaders/faceted/faceted.frag.wgsl +19 -6
  87. package/src/shaders/holographic/holographic.frag.wgsl +7 -5
  88. package/src/shaders/quantum/quantum.frag.wgsl +7 -5
  89. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  90. package/tools/shader-sync-verify.js +6 -4
@@ -222,51 +222,64 @@ export const toolDefinitions = {
222
222
  // Onboarding Tools
223
223
  get_sdk_context: {
224
224
  name: 'get_sdk_context',
225
- description: 'Returns essential SDK context for agent onboarding. Call this first to understand the system.',
225
+ description: 'Returns a compact capability manifest: what systems exist, what tools are available, what parameter ranges are valid, and what the current engine state is. Designed for injection into agent context call once at session start, not repeatedly.',
226
226
  inputSchema: {
227
227
  type: 'object',
228
- properties: {}
228
+ properties: {
229
+ include_state: {
230
+ type: 'boolean',
231
+ default: true,
232
+ description: 'Include current engine state in response'
233
+ },
234
+ include_tools: {
235
+ type: 'boolean',
236
+ default: false,
237
+ description: 'Include tool summary list (names + one-line descriptions)'
238
+ }
239
+ }
229
240
  }
230
241
  },
231
242
 
232
- verify_knowledge: {
233
- name: 'verify_knowledge',
234
- description: 'Verifies agent has absorbed SDK context. Multiple choice quiz - submit letter answers (a/b/c/d).',
243
+ inspect_layers: {
244
+ name: 'inspect_layers',
245
+ description: 'Returns the current state of all holographic canvas layers with per-layer metadata: role, opacity, blend mode, reactivity multiplier, role-specific parameters, and enabled state. Only meaningful when holographic system is active.',
235
246
  inputSchema: {
236
247
  type: 'object',
237
248
  properties: {
238
- q1_rotation_planes: {
239
- type: 'string',
240
- enum: ['a', 'b', 'c', 'd'],
241
- description: 'Q1: How many rotation planes? a)3 b)4 c)6 d)8'
242
- },
243
- q2_geometry_formula: {
244
- type: 'string',
245
- enum: ['a', 'b', 'c', 'd'],
246
- description: 'Q2: Geometry encoding formula? a)base*3+core b)core*8+base c)base+core d)core*base'
247
- },
248
- q3_canvas_layers: {
249
+ layer: {
249
250
  type: 'string',
250
- enum: ['a', 'b', 'c', 'd'],
251
- description: 'Q3: Canvas layers per system? a)3 b)4 c)5 d)6'
252
- },
253
- q4_active_systems: {
251
+ enum: ['background', 'shadow', 'content', 'highlight', 'accent', 'all'],
252
+ default: 'all',
253
+ description: 'Inspect a specific layer or all layers'
254
+ }
255
+ }
256
+ }
257
+ },
258
+
259
+ set_holographic_layer: {
260
+ name: 'set_holographic_layer',
261
+ description: 'Controls individual holographic layer properties. Set opacity, blend mode, enable/disable, or override role parameters for any of the 5 layers (background, shadow, content, highlight, accent). Only works when holographic system is active.',
262
+ inputSchema: {
263
+ type: 'object',
264
+ properties: {
265
+ layer: {
254
266
  type: 'string',
255
- enum: ['a', 'b', 'c', 'd'],
256
- description: 'Q4: Which are the 3 ACTIVE systems? a)quantum,faceted,holographic b)quantum,faceted,polychora c)faceted,holographic,polychora d)all four'
267
+ enum: ['background', 'shadow', 'content', 'highlight', 'accent'],
268
+ description: 'Target layer role name'
257
269
  },
258
- q5_base_geometries: {
270
+ opacity: { type: 'number', minimum: 0, maximum: 1, description: 'Layer opacity (0=invisible, 1=full)' },
271
+ blendMode: {
259
272
  type: 'string',
260
- enum: ['a', 'b', 'c', 'd'],
261
- description: 'Q5: How many base geometry types? a)6 b)8 c)10 d)24'
273
+ enum: ['normal', 'screen', 'multiply', 'add', 'overlay'],
274
+ description: 'CSS blend mode for this layer'
262
275
  },
263
- q6_core_types: {
264
- type: 'string',
265
- enum: ['a', 'b', 'c', 'd'],
266
- description: 'Q6: Core warp types? a)base,sphere,cube b)base,hypersphere,hypertetrahedron c)none,partial,full d)2D,3D,4D'
267
- }
276
+ enabled: { type: 'boolean', description: 'Show/hide this layer' },
277
+ colorShift: { type: 'number', minimum: 0, maximum: 360, description: 'Hue offset for this layer' },
278
+ densityMult: { type: 'number', minimum: 0.1, maximum: 5, description: 'Grid density multiplier' },
279
+ speedMult: { type: 'number', minimum: 0, maximum: 3, description: 'Animation speed multiplier' },
280
+ reactivity: { type: 'number', minimum: 0, maximum: 3, description: 'Mouse/touch reactivity multiplier' }
268
281
  },
269
- required: ['q1_rotation_planes', 'q2_geometry_formula', 'q3_canvas_layers']
282
+ required: ['layer']
270
283
  }
271
284
  },
272
285
 
@@ -651,7 +664,7 @@ export const toolDefinitions = {
651
664
 
652
665
  capture_screenshot: {
653
666
  name: 'capture_screenshot',
654
- description: 'Captures the current visualization as a base64-encoded PNG image by compositing all 5 canvas layers. Only works in browser context. Returns image data that multimodal agents can analyze for visual feedback.',
667
+ description: 'Captures current visualization as a base64-encoded PNG by compositing canvas layers. BROWSER-ONLY: returns an EnvironmentError with capability report in headless/Node contexts. When available, returns data_url for multimodal analysis. Use describe_visual_state as a text-based alternative in non-browser environments.',
655
668
  inputSchema: {
656
669
  type: 'object',
657
670
  properties: {
@@ -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
+ }