@vib3code/sdk 2.0.1 → 2.0.3-canary.0a63e71

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 (192) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +245 -0
  3. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  4. package/DOCS/ARCHITECTURE.md +1 -0
  5. package/DOCS/CI_TESTING.md +2 -0
  6. package/DOCS/CLI_ONBOARDING.md +3 -1
  7. package/DOCS/CONTROL_REFERENCE.md +2 -0
  8. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +119 -0
  9. package/DOCS/ENV_SETUP.md +2 -0
  10. package/DOCS/EPIC_SCROLL_EVENTS.md +775 -0
  11. package/DOCS/EXPANSION_DESIGN.md +979 -0
  12. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  13. package/DOCS/EXPORT_FORMATS.md +2 -0
  14. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  15. package/DOCS/HANDOFF_LANDING_PAGE.md +156 -0
  16. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +495 -0
  17. package/DOCS/LICENSING_TIERS.md +2 -0
  18. package/DOCS/MASTER_PLAN_2026-01-31.md +4 -2
  19. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +939 -0
  20. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  21. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  22. package/DOCS/PRODUCT_STRATEGY.md +65 -0
  23. package/DOCS/PROJECT_SETUP.md +2 -0
  24. package/DOCS/README.md +105 -0
  25. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +99 -0
  26. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  27. package/DOCS/REPO_MANIFEST.md +2 -0
  28. package/DOCS/ROADMAP.md +113 -0
  29. package/DOCS/SCROLL_TIMELINE_v3.md +271 -0
  30. package/DOCS/SITE_REFACTOR_PLAN.md +102 -0
  31. package/DOCS/STATUS.md +26 -0
  32. package/DOCS/SYSTEM_INVENTORY.md +37 -32
  33. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +87 -0
  35. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +135 -0
  36. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +97 -0
  37. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +88 -0
  38. package/DOCS/WEBGPU_STATUS.md +121 -38
  39. package/DOCS/XR_BENCHMARKS.md +2 -0
  40. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -0
  41. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -0
  42. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -0
  43. package/DOCS/archive/SESSION_014_PLAN.md +1 -0
  44. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -0
  45. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -0
  46. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -0
  47. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -0
  48. package/DOCS/{DEV_TRACK_SESSION_2026-01-31.md → dev-tracks/DEV_TRACK_SESSION_2026-01-31.md} +3 -1
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +233 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +129 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
  52. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -0
  53. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  54. package/DOCS/dev-tracks/README.md +12 -0
  55. package/README.md +26 -13
  56. package/cpp/CMakeLists.txt +236 -0
  57. package/cpp/bindings/embind.cpp +269 -0
  58. package/cpp/build.sh +129 -0
  59. package/cpp/geometry/Crystal.cpp +103 -0
  60. package/cpp/geometry/Fractal.cpp +136 -0
  61. package/cpp/geometry/GeometryGenerator.cpp +262 -0
  62. package/cpp/geometry/KleinBottle.cpp +71 -0
  63. package/cpp/geometry/Sphere.cpp +134 -0
  64. package/cpp/geometry/Tesseract.cpp +94 -0
  65. package/cpp/geometry/Tetrahedron.cpp +83 -0
  66. package/cpp/geometry/Torus.cpp +65 -0
  67. package/cpp/geometry/WarpFunctions.cpp +238 -0
  68. package/cpp/geometry/Wave.cpp +85 -0
  69. package/cpp/include/vib3_ffi.h +238 -0
  70. package/cpp/math/Mat4x4.cpp +409 -0
  71. package/cpp/math/Mat4x4.hpp +209 -0
  72. package/cpp/math/Projection.cpp +142 -0
  73. package/cpp/math/Projection.hpp +148 -0
  74. package/cpp/math/Rotor4D.cpp +322 -0
  75. package/cpp/math/Rotor4D.hpp +204 -0
  76. package/cpp/math/Vec4.cpp +303 -0
  77. package/cpp/math/Vec4.hpp +225 -0
  78. package/cpp/src/vib3_ffi.cpp +607 -0
  79. package/cpp/tests/Geometry_test.cpp +213 -0
  80. package/cpp/tests/Mat4x4_test.cpp +494 -0
  81. package/cpp/tests/Projection_test.cpp +298 -0
  82. package/cpp/tests/Rotor4D_test.cpp +423 -0
  83. package/cpp/tests/Vec4_test.cpp +489 -0
  84. package/docs/webgpu-live.html +1 -1
  85. package/package.json +41 -30
  86. package/src/agent/index.js +1 -3
  87. package/src/agent/mcp/MCPServer.js +1220 -144
  88. package/src/agent/mcp/index.js +1 -1
  89. package/src/agent/mcp/stdio-server.js +264 -0
  90. package/src/agent/mcp/tools.js +498 -31
  91. package/src/cli/index.js +431 -47
  92. package/src/core/CanvasManager.js +97 -204
  93. package/src/core/ErrorReporter.js +1 -1
  94. package/src/core/Parameters.js +1 -1
  95. package/src/core/VIB3Engine.js +93 -4
  96. package/src/core/VitalitySystem.js +53 -0
  97. package/src/core/index.js +18 -0
  98. package/src/core/renderers/FacetedRendererAdapter.js +10 -9
  99. package/src/core/renderers/HolographicRendererAdapter.js +13 -9
  100. package/src/core/renderers/QuantumRendererAdapter.js +11 -7
  101. package/src/creative/AestheticMapper.js +628 -0
  102. package/src/creative/ChoreographyPlayer.js +481 -0
  103. package/src/creative/index.js +11 -0
  104. package/src/experimental/GameLoop.js +72 -0
  105. package/src/experimental/LatticePhysics.js +100 -0
  106. package/src/experimental/LiveDirector.js +143 -0
  107. package/src/experimental/PlayerController4D.js +154 -0
  108. package/src/experimental/VIB3Actor.js +138 -0
  109. package/src/experimental/VIB3Compositor.js +117 -0
  110. package/src/experimental/VIB3Link.js +122 -0
  111. package/src/experimental/VIB3Orchestrator.js +146 -0
  112. package/src/experimental/VIB3Universe.js +109 -0
  113. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  114. package/src/export/TradingCardManager.js +3 -4
  115. package/src/export/index.js +11 -1
  116. package/src/faceted/FacetedSystem.js +260 -394
  117. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  118. package/src/geometry/generators/Crystal.js +2 -2
  119. package/src/geometry/warp/HypersphereCore.js +53 -24
  120. package/src/holograms/HolographicVisualizer.js +84 -98
  121. package/src/holograms/RealHolographicSystem.js +194 -43
  122. package/src/math/Mat4x4.js +308 -105
  123. package/src/math/Rotor4D.js +124 -40
  124. package/src/math/Vec4.js +200 -103
  125. package/src/math/index.js +7 -7
  126. package/src/polychora/PolychoraSystem.js +77 -0
  127. package/src/quantum/QuantumEngine.js +103 -66
  128. package/src/quantum/QuantumVisualizer.js +31 -22
  129. package/src/reactivity/index.js +3 -5
  130. package/src/render/LayerPresetManager.js +372 -0
  131. package/src/render/LayerReactivityBridge.js +344 -0
  132. package/src/render/LayerRelationshipGraph.js +610 -0
  133. package/src/render/MultiCanvasBridge.js +148 -25
  134. package/src/render/ShaderLoader.js +38 -0
  135. package/src/render/ShaderProgram.js +4 -4
  136. package/src/render/UnifiedRenderBridge.js +4 -1
  137. package/src/render/backends/WebGPUBackend.js +8 -4
  138. package/src/render/index.js +27 -2
  139. package/src/scene/Node4D.js +74 -24
  140. package/src/scene/index.js +4 -4
  141. package/src/shaders/common/geometry24.glsl +65 -0
  142. package/src/shaders/common/geometry24.wgsl +54 -0
  143. package/src/shaders/common/rotation4d.glsl +4 -4
  144. package/src/shaders/common/rotation4d.wgsl +2 -2
  145. package/src/shaders/common/uniforms.wgsl +15 -8
  146. package/src/shaders/faceted/faceted.frag.glsl +220 -80
  147. package/src/shaders/faceted/faceted.frag.wgsl +144 -90
  148. package/src/shaders/holographic/holographic.frag.glsl +28 -9
  149. package/src/shaders/holographic/holographic.frag.wgsl +112 -41
  150. package/src/shaders/quantum/quantum.frag.glsl +1 -0
  151. package/src/shaders/quantum/quantum.frag.wgsl +6 -4
  152. package/src/testing/ParallelTestFramework.js +2 -2
  153. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  154. package/src/viewer/GalleryUI.js +17 -0
  155. package/src/viewer/ViewerPortal.js +2 -2
  156. package/src/viewer/index.js +1 -1
  157. package/tools/headless-renderer.js +258 -0
  158. package/tools/shader-sync-verify.js +14 -8
  159. package/tools/site-analysis/all-reports.json +32 -0
  160. package/tools/site-analysis/combined-analysis.md +50 -0
  161. package/tools/site-analyzer.mjs +779 -0
  162. package/tools/visual-catalog/capture.js +276 -0
  163. package/tools/visual-catalog/composite.js +138 -0
  164. package/types/adaptive-sdk.d.ts +204 -5
  165. package/types/agent/cli.d.ts +78 -0
  166. package/types/agent/index.d.ts +18 -0
  167. package/types/agent/mcp.d.ts +87 -0
  168. package/types/agent/telemetry.d.ts +190 -0
  169. package/types/core/VIB3Engine.d.ts +26 -0
  170. package/types/core/index.d.ts +261 -0
  171. package/types/creative/AestheticMapper.d.ts +72 -0
  172. package/types/creative/ChoreographyPlayer.d.ts +96 -0
  173. package/types/creative/index.d.ts +17 -0
  174. package/types/export/index.d.ts +243 -0
  175. package/types/geometry/index.d.ts +164 -0
  176. package/types/math/index.d.ts +214 -0
  177. package/types/render/LayerPresetManager.d.ts +78 -0
  178. package/types/render/LayerReactivityBridge.d.ts +85 -0
  179. package/types/render/LayerRelationshipGraph.d.ts +174 -0
  180. package/types/render/index.d.ts +3 -0
  181. package/types/scene/index.d.ts +204 -0
  182. package/types/systems/index.d.ts +244 -0
  183. package/types/variations/index.d.ts +62 -0
  184. package/types/viewer/index.d.ts +225 -0
  185. package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +0 -34
  186. package/DOCS/DEV_TRACK_ANALYSIS.md +0 -77
  187. package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +0 -42
  188. package/DOCS/SESSION_014_PLAN.md +0 -195
  189. package/DOCS/SESSION_LOG_2026-01-07.md +0 -56
  190. package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +0 -72
  191. package/DOCS/SYSTEM_AUDIT_2026-01-30.md +0 -738
  192. /package/src/viewer/{ReactivityManager.js → ViewerInputHandler.js} +0 -0
@@ -0,0 +1,481 @@
1
+ /**
2
+ * ChoreographyPlayer.js - VIB3+ Multi-Scene Choreography Playback Runtime
3
+ *
4
+ * Plays back choreography specifications created by the `create_choreography`
5
+ * MCP tool. Orchestrates system switching, geometry changes, per-scene
6
+ * ParameterTimeline playback, color presets, post-processing, and scene
7
+ * transitions across the full choreography duration.
8
+ *
9
+ * @module creative/ChoreographyPlayer
10
+ * @version 1.0.0
11
+ */
12
+
13
+ import { ParameterTimeline } from './ParameterTimeline.js';
14
+ import { TransitionAnimator } from './TransitionAnimator.js';
15
+
16
+ /**
17
+ * @typedef {Object} ChoreographyScene
18
+ * @property {number} index - Scene index
19
+ * @property {number} time_start - Start time (ms)
20
+ * @property {number} time_end - End time (ms)
21
+ * @property {string} system - Visualization system name
22
+ * @property {number} geometry - Geometry index (0-23)
23
+ * @property {Object} transition_in - Entry transition config
24
+ * @property {Object} tracks - Per-scene parameter timeline tracks
25
+ * @property {string|null} color_preset - Color preset name
26
+ * @property {string[]} post_processing - Active effect names
27
+ * @property {Object|null} audio - Audio reactivity config
28
+ */
29
+
30
+ /**
31
+ * @typedef {Object} ChoreographySpec
32
+ * @property {string} id - Choreography ID
33
+ * @property {string} name - Choreography name
34
+ * @property {number} duration_ms - Total duration
35
+ * @property {number|null} bpm - BPM for beat sync
36
+ * @property {number} scene_count - Number of scenes
37
+ * @property {ChoreographyScene[]} scenes - Scene array
38
+ */
39
+
40
+ /**
41
+ * Plays multi-scene VIB3+ choreographies.
42
+ *
43
+ * Manages the lifecycle of scenes: at each scene boundary, it switches
44
+ * the visualization system, sets geometry, loads per-scene timelines,
45
+ * applies color presets and post-processing, and handles transitions
46
+ * between scenes.
47
+ *
48
+ * @example
49
+ * const player = new ChoreographyPlayer(engine);
50
+ * player.load(choreographySpec);
51
+ * player.play();
52
+ *
53
+ * // Seek to 50%
54
+ * player.seekToPercent(0.5);
55
+ *
56
+ * // Pause / resume
57
+ * player.pause();
58
+ * player.play();
59
+ */
60
+ export class ChoreographyPlayer {
61
+ /**
62
+ * @param {Object} engine - VIB3Engine instance (or any object with
63
+ * setParameter, getParameter, switchSystem, getCurrentSystem methods)
64
+ * @param {Object} [options]
65
+ * @param {Function} [options.onSceneChange] - Callback(sceneIndex, scene) on scene transitions
66
+ * @param {Function} [options.onComplete] - Callback when choreography finishes (once mode)
67
+ * @param {Function} [options.onTick] - Callback(currentTime, totalDuration) each frame
68
+ */
69
+ constructor(engine, options = {}) {
70
+ if (!engine) {
71
+ throw new Error('ChoreographyPlayer requires a VIB3Engine instance');
72
+ }
73
+
74
+ /** @type {Object} */
75
+ this.engine = engine;
76
+
77
+ /** @type {ChoreographySpec|null} */
78
+ this.spec = null;
79
+
80
+ /** @type {boolean} */
81
+ this.playing = false;
82
+
83
+ /** @type {number} Current playback position in ms */
84
+ this.currentTime = 0;
85
+
86
+ /** @type {number} Playback speed multiplier */
87
+ this.playbackSpeed = 1.0;
88
+
89
+ /** @type {'once'|'loop'} */
90
+ this.loopMode = 'once';
91
+
92
+ /** @type {number} Index of currently active scene (-1 if none) */
93
+ this.activeSceneIndex = -1;
94
+
95
+ /** @type {ParameterTimeline|null} Current scene's timeline */
96
+ this._sceneTimeline = null;
97
+
98
+ /** @type {TransitionAnimator} Shared transition animator */
99
+ this._transitionAnimator = new TransitionAnimator(
100
+ (name, value) => this.engine.setParameter(name, value),
101
+ (name) => this.engine.getParameter?.(name) ?? 0
102
+ );
103
+
104
+ /** @type {number|null} requestAnimationFrame ID */
105
+ this._frameId = null;
106
+
107
+ /** @type {number} Last frame timestamp */
108
+ this._lastFrameTime = 0;
109
+
110
+ // Callbacks
111
+ this._onSceneChange = options.onSceneChange || null;
112
+ this._onComplete = options.onComplete || null;
113
+ this._onTick = options.onTick || null;
114
+ }
115
+
116
+ // ─────────────────────────────────────────────────────────────────────────
117
+ // Public API
118
+ // ─────────────────────────────────────────────────────────────────────────
119
+
120
+ /**
121
+ * Load a choreography specification.
122
+ *
123
+ * @param {ChoreographySpec} spec - Choreography data (from create_choreography MCP tool
124
+ * or parsed from choreography_json)
125
+ * @returns {boolean} true if loaded successfully
126
+ */
127
+ load(spec) {
128
+ if (!spec || !Array.isArray(spec.scenes) || spec.scenes.length === 0) {
129
+ console.warn('ChoreographyPlayer: Invalid spec — needs scenes array');
130
+ return false;
131
+ }
132
+
133
+ this.stop();
134
+
135
+ this.spec = {
136
+ id: spec.id || `choreo_${Date.now()}`,
137
+ name: spec.name || 'Untitled',
138
+ duration_ms: spec.duration_ms || this._inferDuration(spec.scenes),
139
+ bpm: spec.bpm || null,
140
+ scene_count: spec.scenes.length,
141
+ scenes: spec.scenes.map((s, i) => ({
142
+ index: s.index ?? i,
143
+ time_start: s.time_start ?? 0,
144
+ time_end: s.time_end ?? spec.duration_ms,
145
+ system: s.system || 'quantum',
146
+ geometry: s.geometry ?? 0,
147
+ transition_in: s.transition_in || { type: 'cut', duration: 0 },
148
+ tracks: s.tracks || {},
149
+ color_preset: s.color_preset || null,
150
+ post_processing: s.post_processing || [],
151
+ audio: s.audio || null
152
+ }))
153
+ };
154
+
155
+ // Sort scenes by start time
156
+ this.spec.scenes.sort((a, b) => a.time_start - b.time_start);
157
+
158
+ this.currentTime = 0;
159
+ this.activeSceneIndex = -1;
160
+
161
+ return true;
162
+ }
163
+
164
+ /**
165
+ * Start or resume playback.
166
+ */
167
+ play() {
168
+ if (!this.spec) {
169
+ console.warn('ChoreographyPlayer: No choreography loaded');
170
+ return;
171
+ }
172
+
173
+ if (this.playing) return;
174
+
175
+ this.playing = true;
176
+ this._lastFrameTime = performance.now();
177
+
178
+ // Enter the current scene if not already in one
179
+ this._evaluateScene(this.currentTime);
180
+
181
+ this._tick();
182
+ }
183
+
184
+ /**
185
+ * Pause playback (maintains position).
186
+ */
187
+ pause() {
188
+ this.playing = false;
189
+ if (this._frameId !== null) {
190
+ cancelAnimationFrame(this._frameId);
191
+ this._frameId = null;
192
+ }
193
+ if (this._sceneTimeline) {
194
+ this._sceneTimeline.pause();
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Stop playback and reset to beginning.
200
+ */
201
+ stop() {
202
+ this.pause();
203
+ this.currentTime = 0;
204
+ this.activeSceneIndex = -1;
205
+ if (this._sceneTimeline) {
206
+ this._sceneTimeline.stop();
207
+ this._sceneTimeline = null;
208
+ }
209
+ this._transitionAnimator.cancelAll();
210
+ }
211
+
212
+ /**
213
+ * Seek to an absolute time position.
214
+ * @param {number} timeMs - Time in milliseconds
215
+ */
216
+ seek(timeMs) {
217
+ if (!this.spec) return;
218
+ this.currentTime = Math.max(0, Math.min(timeMs, this.spec.duration_ms));
219
+ this._evaluateScene(this.currentTime);
220
+ }
221
+
222
+ /**
223
+ * Seek to a percentage of the total duration.
224
+ * @param {number} percent - 0.0 to 1.0
225
+ */
226
+ seekToPercent(percent) {
227
+ if (!this.spec) return;
228
+ this.seek(Math.max(0, Math.min(1, percent)) * this.spec.duration_ms);
229
+ }
230
+
231
+ /**
232
+ * Get current playback state.
233
+ * @returns {Object} State summary
234
+ */
235
+ getState() {
236
+ const scene = this.spec?.scenes[this.activeSceneIndex] ?? null;
237
+ return {
238
+ playing: this.playing,
239
+ currentTime: this.currentTime,
240
+ duration: this.spec?.duration_ms ?? 0,
241
+ progress: this.spec ? this.currentTime / this.spec.duration_ms : 0,
242
+ activeScene: scene ? {
243
+ index: scene.index,
244
+ system: scene.system,
245
+ geometry: scene.geometry,
246
+ time_start: scene.time_start,
247
+ time_end: scene.time_end,
248
+ scene_progress: scene.time_end > scene.time_start
249
+ ? (this.currentTime - scene.time_start) / (scene.time_end - scene.time_start)
250
+ : 0
251
+ } : null,
252
+ sceneCount: this.spec?.scene_count ?? 0,
253
+ playbackSpeed: this.playbackSpeed
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Clean up resources.
259
+ */
260
+ destroy() {
261
+ this.stop();
262
+ this._transitionAnimator.destroy?.() || this._transitionAnimator.cancelAll();
263
+ this.spec = null;
264
+ }
265
+
266
+ // ─────────────────────────────────────────────────────────────────────────
267
+ // Internal
268
+ // ─────────────────────────────────────────────────────────────────────────
269
+
270
+ /**
271
+ * Main animation loop.
272
+ */
273
+ _tick() {
274
+ if (!this.playing) return;
275
+
276
+ const now = performance.now();
277
+ const delta = (now - this._lastFrameTime) * this.playbackSpeed;
278
+ this._lastFrameTime = now;
279
+
280
+ this.currentTime += delta;
281
+
282
+ // Handle end-of-choreography
283
+ if (this.currentTime >= this.spec.duration_ms) {
284
+ if (this.loopMode === 'loop') {
285
+ this.currentTime = this.currentTime % this.spec.duration_ms;
286
+ this.activeSceneIndex = -1; // Force re-evaluation
287
+ } else {
288
+ this.currentTime = this.spec.duration_ms;
289
+ this.playing = false;
290
+ if (this._onComplete) this._onComplete();
291
+ return;
292
+ }
293
+ }
294
+
295
+ // Evaluate which scene we should be in
296
+ this._evaluateScene(this.currentTime);
297
+
298
+ // Update scene timeline position (relative to scene start)
299
+ if (this._sceneTimeline && this._sceneTimeline.playing) {
300
+ const scene = this.spec.scenes[this.activeSceneIndex];
301
+ const sceneLocalTime = this.currentTime - scene.time_start;
302
+ this._sceneTimeline.seek(sceneLocalTime);
303
+ }
304
+
305
+ // Tick callback
306
+ if (this._onTick) {
307
+ this._onTick(this.currentTime, this.spec.duration_ms);
308
+ }
309
+
310
+ this._frameId = requestAnimationFrame(() => this._tick());
311
+ }
312
+
313
+ /**
314
+ * Determine which scene should be active at the given time,
315
+ * and transition if needed.
316
+ */
317
+ _evaluateScene(timeMs) {
318
+ if (!this.spec) return;
319
+
320
+ // Find the scene that contains this time
321
+ let targetIndex = -1;
322
+ for (let i = 0; i < this.spec.scenes.length; i++) {
323
+ const scene = this.spec.scenes[i];
324
+ if (timeMs >= scene.time_start && timeMs < scene.time_end) {
325
+ targetIndex = i;
326
+ break;
327
+ }
328
+ }
329
+
330
+ // If no scene found and we're at the very end, use the last scene
331
+ if (targetIndex === -1 && timeMs >= this.spec.duration_ms && this.spec.scenes.length > 0) {
332
+ targetIndex = this.spec.scenes.length - 1;
333
+ }
334
+
335
+ // Scene change needed?
336
+ if (targetIndex !== this.activeSceneIndex && targetIndex >= 0) {
337
+ this._enterScene(targetIndex);
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Enter a new scene — switch system, geometry, load timeline, apply presets.
343
+ */
344
+ async _enterScene(sceneIndex) {
345
+ const scene = this.spec.scenes[sceneIndex];
346
+ const previousIndex = this.activeSceneIndex;
347
+ this.activeSceneIndex = sceneIndex;
348
+
349
+ // Stop previous scene timeline
350
+ if (this._sceneTimeline) {
351
+ this._sceneTimeline.stop();
352
+ this._sceneTimeline = null;
353
+ }
354
+
355
+ // 1. Handle scene transition (crossfade, etc.)
356
+ const transition = scene.transition_in;
357
+ if (transition && transition.type !== 'cut' && transition.duration > 0 && previousIndex >= 0) {
358
+ // For non-cut transitions, we do a smooth crossfade via intensity
359
+ this._transitionAnimator.transition(
360
+ { intensity: 0 },
361
+ transition.duration / 2,
362
+ 'easeIn',
363
+ () => {
364
+ // Midpoint: switch system/geometry while faded out
365
+ this._applyCoreSceneState(scene);
366
+ this._transitionAnimator.transition(
367
+ { intensity: scene.tracks?.intensity?.[0]?.value ?? 0.5 },
368
+ transition.duration / 2,
369
+ 'easeOut'
370
+ );
371
+ }
372
+ );
373
+ } else {
374
+ // Cut: immediately apply
375
+ await this._applyCoreSceneState(scene);
376
+ }
377
+
378
+ // 2. Build and start per-scene ParameterTimeline
379
+ if (scene.tracks && Object.keys(scene.tracks).length > 0) {
380
+ const sceneDuration = scene.time_end - scene.time_start;
381
+ this._sceneTimeline = new ParameterTimeline(
382
+ (name, value) => this.engine.setParameter(name, value)
383
+ );
384
+ this._sceneTimeline.setDuration(sceneDuration);
385
+ this._sceneTimeline.setLoopMode('once');
386
+
387
+ if (this.spec.bpm) {
388
+ this._sceneTimeline.bpm = this.spec.bpm;
389
+ }
390
+
391
+ for (const [param, keyframes] of Object.entries(scene.tracks)) {
392
+ this._sceneTimeline.addTrack(param);
393
+ if (Array.isArray(keyframes)) {
394
+ for (const kf of keyframes) {
395
+ this._sceneTimeline.addKeyframe(
396
+ param,
397
+ kf.time ?? 0,
398
+ kf.value ?? 0,
399
+ kf.easing || 'easeInOut'
400
+ );
401
+ }
402
+ }
403
+ }
404
+
405
+ // Seek to the correct position within the scene
406
+ const sceneLocalTime = this.currentTime - scene.time_start;
407
+ this._sceneTimeline.seek(Math.max(0, sceneLocalTime));
408
+ if (this.playing) {
409
+ this._sceneTimeline.play();
410
+ }
411
+ }
412
+
413
+ // 3. Notify callback
414
+ if (this._onSceneChange) {
415
+ this._onSceneChange(sceneIndex, scene);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Apply the core state of a scene: system, geometry, color preset.
421
+ */
422
+ async _applyCoreSceneState(scene) {
423
+ // Switch system if different
424
+ const currentSystem = this.engine.getCurrentSystem?.() || this.engine.currentSystemName;
425
+ if (scene.system && scene.system !== currentSystem) {
426
+ if (this.engine.switchSystem) {
427
+ await this.engine.switchSystem(scene.system);
428
+ }
429
+ }
430
+
431
+ // Set geometry
432
+ if (scene.geometry !== undefined) {
433
+ this.engine.setParameter('geometry', scene.geometry);
434
+ }
435
+
436
+ // Apply color preset (simplified — maps preset name to hue/sat/intensity)
437
+ if (scene.color_preset) {
438
+ const colors = ChoreographyPlayer.COLOR_PRESET_MAP[scene.color_preset];
439
+ if (colors) {
440
+ this.engine.setParameter('hue', colors.hue);
441
+ this.engine.setParameter('saturation', colors.saturation);
442
+ this.engine.setParameter('intensity', colors.intensity);
443
+ }
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Infer total duration from scene end times.
449
+ */
450
+ _inferDuration(scenes) {
451
+ return Math.max(...scenes.map(s => s.time_end || 0), 10000);
452
+ }
453
+
454
+ /**
455
+ * Color preset lookup (matches MCPServer.applyColorPreset).
456
+ */
457
+ static COLOR_PRESET_MAP = {
458
+ Ocean: { hue: 200, saturation: 0.8, intensity: 0.6 },
459
+ Lava: { hue: 15, saturation: 0.9, intensity: 0.8 },
460
+ Neon: { hue: 300, saturation: 1.0, intensity: 0.9 },
461
+ Monochrome: { hue: 0, saturation: 0.0, intensity: 0.6 },
462
+ Sunset: { hue: 30, saturation: 0.85, intensity: 0.7 },
463
+ Aurora: { hue: 140, saturation: 0.7, intensity: 0.6 },
464
+ Cyberpunk: { hue: 280, saturation: 0.9, intensity: 0.8 },
465
+ Forest: { hue: 120, saturation: 0.6, intensity: 0.5 },
466
+ Desert: { hue: 40, saturation: 0.5, intensity: 0.7 },
467
+ Galaxy: { hue: 260, saturation: 0.8, intensity: 0.4 },
468
+ Ice: { hue: 190, saturation: 0.5, intensity: 0.8 },
469
+ Fire: { hue: 10, saturation: 1.0, intensity: 0.9 },
470
+ Toxic: { hue: 100, saturation: 0.9, intensity: 0.7 },
471
+ Royal: { hue: 270, saturation: 0.7, intensity: 0.5 },
472
+ Pastel: { hue: 330, saturation: 0.3, intensity: 0.8 },
473
+ Retro: { hue: 50, saturation: 0.7, intensity: 0.6 },
474
+ Midnight: { hue: 240, saturation: 0.6, intensity: 0.3 },
475
+ Tropical: { hue: 160, saturation: 0.8, intensity: 0.7 },
476
+ Ethereal: { hue: 220, saturation: 0.4, intensity: 0.7 },
477
+ Volcanic: { hue: 5, saturation: 0.95, intensity: 0.6 },
478
+ Holographic: { hue: 180, saturation: 0.6, intensity: 0.8 },
479
+ Vaporwave: { hue: 310, saturation: 0.7, intensity: 0.7 }
480
+ };
481
+ }
@@ -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
+ }