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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +2 -0
  2. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  3. package/DOCS/ARCHITECTURE.md +1 -0
  4. package/DOCS/CI_TESTING.md +2 -0
  5. package/DOCS/CLI_ONBOARDING.md +2 -0
  6. package/DOCS/CONTROL_REFERENCE.md +2 -0
  7. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
  8. package/DOCS/ENV_SETUP.md +2 -0
  9. package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
  10. package/DOCS/EXPANSION_DESIGN.md +979 -0
  11. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  12. package/DOCS/EXPORT_FORMATS.md +2 -0
  13. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  14. package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
  15. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
  16. package/DOCS/LICENSING_TIERS.md +2 -0
  17. package/DOCS/MASTER_PLAN_2026-01-31.md +4 -2
  18. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
  19. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  20. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  21. package/DOCS/PRODUCT_STRATEGY.md +2 -0
  22. package/DOCS/PROJECT_SETUP.md +2 -0
  23. package/DOCS/README.md +5 -3
  24. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
  25. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  26. package/DOCS/REPO_MANIFEST.md +2 -0
  27. package/DOCS/ROADMAP.md +2 -0
  28. package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
  29. package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
  30. package/DOCS/STATUS.md +2 -0
  31. package/DOCS/SYSTEM_INVENTORY.md +4 -2
  32. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  33. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
  35. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
  36. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
  37. package/DOCS/WEBGPU_STATUS.md +121 -38
  38. package/DOCS/XR_BENCHMARKS.md +2 -0
  39. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
  40. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
  41. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
  42. package/DOCS/archive/SESSION_014_PLAN.md +1 -195
  43. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
  44. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
  45. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
  46. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -0
  47. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
  48. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +15 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -0
  52. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  53. package/DOCS/dev-tracks/README.md +2 -0
  54. package/docs/webgpu-live.html +1 -1
  55. package/package.json +11 -4
  56. package/src/agent/index.js +1 -3
  57. package/src/agent/mcp/MCPServer.js +542 -188
  58. package/src/agent/mcp/index.js +1 -1
  59. package/src/agent/mcp/tools.js +132 -32
  60. package/src/cli/index.js +431 -47
  61. package/src/core/VIB3Engine.js +55 -3
  62. package/src/core/index.js +18 -0
  63. package/src/core/renderers/FacetedRendererAdapter.js +10 -9
  64. package/src/core/renderers/HolographicRendererAdapter.js +11 -7
  65. package/src/core/renderers/QuantumRendererAdapter.js +11 -7
  66. package/src/creative/index.js +11 -0
  67. package/src/experimental/GameLoop.js +72 -0
  68. package/src/experimental/LatticePhysics.js +100 -0
  69. package/src/experimental/LiveDirector.js +143 -0
  70. package/src/experimental/PlayerController4D.js +154 -0
  71. package/src/experimental/VIB3Actor.js +138 -0
  72. package/src/experimental/VIB3Compositor.js +117 -0
  73. package/src/experimental/VIB3Link.js +122 -0
  74. package/src/experimental/VIB3Orchestrator.js +146 -0
  75. package/src/experimental/VIB3Universe.js +109 -0
  76. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  77. package/src/export/SVGExporter.js +9 -5
  78. package/src/export/index.js +11 -1
  79. package/src/faceted/FacetedSystem.js +27 -10
  80. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  81. package/src/geometry/generators/Crystal.js +2 -2
  82. package/src/geometry/warp/HypersphereCore.js +53 -24
  83. package/src/holograms/HolographicVisualizer.js +58 -89
  84. package/src/holograms/RealHolographicSystem.js +126 -31
  85. package/src/math/Mat4x4.js +372 -140
  86. package/src/math/Projection.js +39 -4
  87. package/src/math/Rotor4D.js +157 -67
  88. package/src/math/Vec4.js +265 -111
  89. package/src/math/index.js +7 -7
  90. package/src/quantum/QuantumVisualizer.js +24 -20
  91. package/src/reactivity/index.js +3 -5
  92. package/src/render/LayerPresetManager.js +372 -0
  93. package/src/render/LayerReactivityBridge.js +344 -0
  94. package/src/render/LayerRelationshipGraph.js +610 -0
  95. package/src/render/MultiCanvasBridge.js +148 -25
  96. package/src/render/ShaderLoader.js +38 -0
  97. package/src/render/ShaderProgram.js +4 -4
  98. package/src/render/UnifiedRenderBridge.js +1 -1
  99. package/src/render/backends/WebGPUBackend.js +8 -4
  100. package/src/render/index.js +27 -2
  101. package/src/scene/Node4D.js +74 -24
  102. package/src/scene/index.js +4 -4
  103. package/src/shaders/common/geometry24.glsl +65 -0
  104. package/src/shaders/common/geometry24.wgsl +54 -0
  105. package/src/shaders/common/rotation4d.glsl +4 -4
  106. package/src/shaders/common/rotation4d.wgsl +2 -2
  107. package/src/shaders/common/uniforms.wgsl +15 -8
  108. package/src/shaders/faceted/faceted.frag.wgsl +19 -6
  109. package/src/shaders/holographic/holographic.frag.wgsl +7 -5
  110. package/src/shaders/quantum/quantum.frag.wgsl +7 -5
  111. package/src/testing/ParallelTestFramework.js +2 -2
  112. package/src/testing/ProjectionClass.test.js +38 -0
  113. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  114. package/src/viewer/GalleryUI.js +17 -0
  115. package/src/viewer/ViewerPortal.js +2 -2
  116. package/tools/shader-sync-verify.js +6 -4
  117. package/tools/update_projection.py +109 -0
  118. package/types/adaptive-sdk.d.ts +204 -5
  119. package/types/agent/cli.d.ts +78 -0
  120. package/types/agent/index.d.ts +18 -0
  121. package/types/agent/mcp.d.ts +87 -0
  122. package/types/agent/telemetry.d.ts +190 -0
  123. package/types/core/VIB3Engine.d.ts +26 -0
  124. package/types/core/index.d.ts +261 -0
  125. package/types/creative/AestheticMapper.d.ts +72 -0
  126. package/types/creative/ChoreographyPlayer.d.ts +96 -0
  127. package/types/creative/index.d.ts +17 -0
  128. package/types/export/index.d.ts +243 -0
  129. package/types/geometry/index.d.ts +164 -0
  130. package/types/math/index.d.ts +214 -0
  131. package/types/render/LayerPresetManager.d.ts +78 -0
  132. package/types/render/LayerReactivityBridge.d.ts +85 -0
  133. package/types/render/LayerRelationshipGraph.d.ts +174 -0
  134. package/types/render/index.d.ts +3 -0
  135. package/types/scene/index.d.ts +204 -0
  136. package/types/systems/index.d.ts +244 -0
  137. package/types/variations/index.d.ts +62 -0
  138. package/types/viewer/index.d.ts +225 -0
@@ -8,18 +8,19 @@ export class FacetedRendererAdapter extends RendererContract {
8
8
  }
9
9
 
10
10
  init(context = {}) {
11
- const initialized = this.system.initialize(context.canvas ?? null);
12
- if (!initialized) {
13
- throw new Error('Faceted renderer failed to initialize.');
14
- }
11
+ return this.system.init ? this.system.init(context) : true;
15
12
  }
16
13
 
17
- resize() {
18
- this.system.setupCanvasSize();
14
+ resize(width, height, pixelRatio = 1) {
15
+ if (this.system.resize) {
16
+ this.system.resize(width, height, pixelRatio);
17
+ }
19
18
  }
20
19
 
21
- render() {
22
- this.system.renderFrame();
20
+ render(frameState) {
21
+ if (this.system.render) {
22
+ this.system.render(frameState);
23
+ }
23
24
  }
24
25
 
25
26
  setActive(active) {
@@ -27,6 +28,6 @@ export class FacetedRendererAdapter extends RendererContract {
27
28
  }
28
29
 
29
30
  dispose() {
30
- this.system.stop();
31
+ this.system.dispose();
31
32
  }
32
33
  }
@@ -7,16 +7,20 @@ export class HolographicRendererAdapter extends RendererContract {
7
7
  this.system = system;
8
8
  }
9
9
 
10
- init() {
11
- return true;
10
+ init(context = {}) {
11
+ return this.system.init ? this.system.init(context) : true;
12
12
  }
13
13
 
14
- resize() {
15
- // Visualizers handle their own resizing.
14
+ resize(width, height, pixelRatio = 1) {
15
+ if (this.system.resize) {
16
+ this.system.resize(width, height, pixelRatio);
17
+ }
16
18
  }
17
19
 
18
- render() {
19
- this.system.renderFrame();
20
+ render(frameState) {
21
+ if (this.system.render) {
22
+ this.system.render(frameState);
23
+ }
20
24
  }
21
25
 
22
26
  setActive(active) {
@@ -24,6 +28,6 @@ export class HolographicRendererAdapter extends RendererContract {
24
28
  }
25
29
 
26
30
  dispose() {
27
- this.system.setActive(false);
31
+ this.system.dispose();
28
32
  }
29
33
  }
@@ -7,16 +7,20 @@ export class QuantumRendererAdapter extends RendererContract {
7
7
  this.system = system;
8
8
  }
9
9
 
10
- init() {
11
- return true;
10
+ init(context = {}) {
11
+ return this.system.init ? this.system.init(context) : true;
12
12
  }
13
13
 
14
- resize() {
15
- // Canvas sizing is handled by visualizers.
14
+ resize(width, height, pixelRatio = 1) {
15
+ if (this.system.resize) {
16
+ this.system.resize(width, height, pixelRatio);
17
+ }
16
18
  }
17
19
 
18
- render() {
19
- this.system.renderFrame();
20
+ render(frameState) {
21
+ if (this.system.render) {
22
+ this.system.render(frameState);
23
+ }
20
24
  }
21
25
 
22
26
  setActive(active) {
@@ -24,6 +28,6 @@ export class QuantumRendererAdapter extends RendererContract {
24
28
  }
25
29
 
26
30
  dispose() {
27
- this.system.setActive(false);
31
+ this.system.dispose();
28
32
  }
29
33
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * VIB3+ Creative Tooling Module
3
+ * @module creative
4
+ */
5
+
6
+ export { ColorPresetsSystem } from './ColorPresetsSystem.js';
7
+ export { TransitionAnimator } from './TransitionAnimator.js';
8
+ export { PostProcessingPipeline } from './PostProcessingPipeline.js';
9
+ export { ParameterTimeline } from './ParameterTimeline.js';
10
+ export { ChoreographyPlayer } from './ChoreographyPlayer.js';
11
+ export { AestheticMapper } from './AestheticMapper.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
+ }