@vib3code/sdk 2.0.1

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 (258) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +34 -0
  3. package/DOCS/CI_TESTING.md +38 -0
  4. package/DOCS/CLI_ONBOARDING.md +75 -0
  5. package/DOCS/CONTROL_REFERENCE.md +64 -0
  6. package/DOCS/DEV_TRACK_ANALYSIS.md +77 -0
  7. package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +42 -0
  8. package/DOCS/DEV_TRACK_SESSION_2026-01-31.md +220 -0
  9. package/DOCS/ENV_SETUP.md +189 -0
  10. package/DOCS/EXPORT_FORMATS.md +417 -0
  11. package/DOCS/GPU_DISPOSAL_GUIDE.md +21 -0
  12. package/DOCS/LICENSING_TIERS.md +275 -0
  13. package/DOCS/MASTER_PLAN_2026-01-31.md +570 -0
  14. package/DOCS/OBS_SETUP_GUIDE.md +98 -0
  15. package/DOCS/PROJECT_SETUP.md +66 -0
  16. package/DOCS/RENDERER_LIFECYCLE.md +40 -0
  17. package/DOCS/REPO_MANIFEST.md +121 -0
  18. package/DOCS/SESSION_014_PLAN.md +195 -0
  19. package/DOCS/SESSION_LOG_2026-01-07.md +56 -0
  20. package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +72 -0
  21. package/DOCS/SYSTEM_AUDIT_2026-01-30.md +738 -0
  22. package/DOCS/SYSTEM_INVENTORY.md +520 -0
  23. package/DOCS/TELEMETRY_EXPORTS.md +34 -0
  24. package/DOCS/WEBGPU_STATUS.md +38 -0
  25. package/DOCS/XR_BENCHMARKS.md +608 -0
  26. package/LICENSE +21 -0
  27. package/README.md +426 -0
  28. package/docs/.nojekyll +0 -0
  29. package/docs/01-dissolution_of_euclidean_hegemony.html +346 -0
  30. package/docs/02-hyperspatial_ego_death.html +346 -0
  31. package/docs/03-post_cartesian_sublime.html +346 -0
  32. package/docs/04-crystalline_void_meditation.html +346 -0
  33. package/docs/05-quantum_decoherence_ballet.html +346 -0
  34. package/docs/06-dissolution_of_euclidean_hegemony.html +346 -0
  35. package/docs/07-hyperspatial_ego_death.html +346 -0
  36. package/docs/08-post_cartesian_sublime.html +346 -0
  37. package/docs/09-crystalline_void_meditation.html +346 -0
  38. package/docs/10-quantum_decoherence_ballet.html +346 -0
  39. package/docs/11-dissolution_of_euclidean_hegemony.html +346 -0
  40. package/docs/12-hyperspatial_ego_death.html +346 -0
  41. package/docs/13-post_cartesian_sublime.html +346 -0
  42. package/docs/index.html +794 -0
  43. package/docs/test-hub.html +441 -0
  44. package/docs/url-state.js +102 -0
  45. package/docs/vib3-exports/01-quantum-quantum-tetrahedron-lattice.html +489 -0
  46. package/docs/vib3-exports/02-quantum-quantum-hypersphere-matrix.html +489 -0
  47. package/docs/vib3-exports/03-quantum-quantum-hypertetra-fractal.html +489 -0
  48. package/docs/vib3-exports/04-faceted-faceted-crystal-structure.html +407 -0
  49. package/docs/vib3-exports/05-faceted-faceted-klein-bottle.html +407 -0
  50. package/docs/vib3-exports/06-faceted-faceted-hypertetra-torus.html +407 -0
  51. package/docs/vib3-exports/07-holographic-holographic-wave-field.html +457 -0
  52. package/docs/vib3-exports/08-holographic-holographic-hypersphere-sphere.html +457 -0
  53. package/docs/vib3-exports/09-holographic-holographic-hypertetra-crystal.html +457 -0
  54. package/docs/vib3-exports/index.html +238 -0
  55. package/docs/webgpu-live.html +702 -0
  56. package/package.json +367 -0
  57. package/src/advanced/AIPresetGenerator.js +777 -0
  58. package/src/advanced/MIDIController.js +703 -0
  59. package/src/advanced/OffscreenWorker.js +1051 -0
  60. package/src/advanced/WebGPUCompute.js +1051 -0
  61. package/src/advanced/WebXRRenderer.js +680 -0
  62. package/src/agent/cli/AgentCLI.js +615 -0
  63. package/src/agent/cli/index.js +14 -0
  64. package/src/agent/index.js +73 -0
  65. package/src/agent/mcp/MCPServer.js +950 -0
  66. package/src/agent/mcp/index.js +9 -0
  67. package/src/agent/mcp/tools.js +548 -0
  68. package/src/agent/telemetry/EventStream.js +669 -0
  69. package/src/agent/telemetry/Instrumentation.js +618 -0
  70. package/src/agent/telemetry/TelemetryExporters.js +427 -0
  71. package/src/agent/telemetry/TelemetryService.js +464 -0
  72. package/src/agent/telemetry/index.js +52 -0
  73. package/src/benchmarks/BenchmarkRunner.js +381 -0
  74. package/src/benchmarks/MetricsCollector.js +299 -0
  75. package/src/benchmarks/index.js +9 -0
  76. package/src/benchmarks/scenes.js +259 -0
  77. package/src/cli/index.js +675 -0
  78. package/src/config/ApiConfig.js +88 -0
  79. package/src/core/CanvasManager.js +217 -0
  80. package/src/core/ErrorReporter.js +117 -0
  81. package/src/core/ParameterMapper.js +333 -0
  82. package/src/core/Parameters.js +396 -0
  83. package/src/core/RendererContracts.js +200 -0
  84. package/src/core/UnifiedResourceManager.js +370 -0
  85. package/src/core/VIB3Engine.js +636 -0
  86. package/src/core/renderers/FacetedRendererAdapter.js +32 -0
  87. package/src/core/renderers/HolographicRendererAdapter.js +29 -0
  88. package/src/core/renderers/QuantumRendererAdapter.js +29 -0
  89. package/src/core/renderers/RendererLifecycleManager.js +63 -0
  90. package/src/creative/ColorPresetsSystem.js +980 -0
  91. package/src/creative/ParameterTimeline.js +1061 -0
  92. package/src/creative/PostProcessingPipeline.js +1113 -0
  93. package/src/creative/TransitionAnimator.js +683 -0
  94. package/src/export/CSSExporter.js +226 -0
  95. package/src/export/CardGeneratorBase.js +279 -0
  96. package/src/export/ExportManager.js +580 -0
  97. package/src/export/FacetedCardGenerator.js +279 -0
  98. package/src/export/HolographicCardGenerator.js +543 -0
  99. package/src/export/LottieExporter.js +552 -0
  100. package/src/export/QuantumCardGenerator.js +315 -0
  101. package/src/export/SVGExporter.js +519 -0
  102. package/src/export/ShaderExporter.js +903 -0
  103. package/src/export/TradingCardGenerator.js +3055 -0
  104. package/src/export/TradingCardManager.js +181 -0
  105. package/src/export/VIB3PackageExporter.js +559 -0
  106. package/src/export/index.js +14 -0
  107. package/src/export/systems/TradingCardSystemFaceted.js +494 -0
  108. package/src/export/systems/TradingCardSystemHolographic.js +452 -0
  109. package/src/export/systems/TradingCardSystemQuantum.js +411 -0
  110. package/src/faceted/FacetedSystem.js +963 -0
  111. package/src/features/CollectionManager.js +433 -0
  112. package/src/gallery/CollectionManager.js +240 -0
  113. package/src/gallery/GallerySystem.js +485 -0
  114. package/src/geometry/GeometryFactory.js +314 -0
  115. package/src/geometry/GeometryLibrary.js +72 -0
  116. package/src/geometry/buffers/BufferBuilder.js +338 -0
  117. package/src/geometry/buffers/index.js +18 -0
  118. package/src/geometry/generators/Crystal.js +420 -0
  119. package/src/geometry/generators/Fractal.js +298 -0
  120. package/src/geometry/generators/KleinBottle.js +197 -0
  121. package/src/geometry/generators/Sphere.js +192 -0
  122. package/src/geometry/generators/Tesseract.js +160 -0
  123. package/src/geometry/generators/Tetrahedron.js +225 -0
  124. package/src/geometry/generators/Torus.js +304 -0
  125. package/src/geometry/generators/Wave.js +341 -0
  126. package/src/geometry/index.js +142 -0
  127. package/src/geometry/warp/HypersphereCore.js +211 -0
  128. package/src/geometry/warp/HypertetraCore.js +386 -0
  129. package/src/geometry/warp/index.js +57 -0
  130. package/src/holograms/HolographicVisualizer.js +1073 -0
  131. package/src/holograms/RealHolographicSystem.js +966 -0
  132. package/src/holograms/variantRegistry.js +69 -0
  133. package/src/integrations/FigmaPlugin.js +854 -0
  134. package/src/integrations/OBSMode.js +754 -0
  135. package/src/integrations/ThreeJsPackage.js +660 -0
  136. package/src/integrations/TouchDesignerExport.js +552 -0
  137. package/src/integrations/frameworks/Vib3React.js +591 -0
  138. package/src/integrations/frameworks/Vib3Svelte.js +654 -0
  139. package/src/integrations/frameworks/Vib3Vue.js +628 -0
  140. package/src/llm/LLMParameterInterface.js +240 -0
  141. package/src/llm/LLMParameterUI.js +577 -0
  142. package/src/math/Mat4x4.js +708 -0
  143. package/src/math/Projection.js +341 -0
  144. package/src/math/Rotor4D.js +637 -0
  145. package/src/math/Vec4.js +476 -0
  146. package/src/math/constants.js +164 -0
  147. package/src/math/index.js +68 -0
  148. package/src/math/projections.js +54 -0
  149. package/src/math/rotations.js +196 -0
  150. package/src/quantum/QuantumEngine.js +906 -0
  151. package/src/quantum/QuantumVisualizer.js +1103 -0
  152. package/src/reactivity/ReactivityConfig.js +499 -0
  153. package/src/reactivity/ReactivityManager.js +586 -0
  154. package/src/reactivity/SpatialInputSystem.js +1783 -0
  155. package/src/reactivity/index.js +93 -0
  156. package/src/render/CommandBuffer.js +465 -0
  157. package/src/render/MultiCanvasBridge.js +340 -0
  158. package/src/render/RenderCommand.js +514 -0
  159. package/src/render/RenderResourceRegistry.js +523 -0
  160. package/src/render/RenderState.js +552 -0
  161. package/src/render/RenderTarget.js +512 -0
  162. package/src/render/ShaderLoader.js +253 -0
  163. package/src/render/ShaderProgram.js +599 -0
  164. package/src/render/UnifiedRenderBridge.js +496 -0
  165. package/src/render/backends/WebGLBackend.js +1108 -0
  166. package/src/render/backends/WebGPUBackend.js +1409 -0
  167. package/src/render/commands/CommandBufferExecutor.js +607 -0
  168. package/src/render/commands/RenderCommandBuffer.js +661 -0
  169. package/src/render/commands/index.js +17 -0
  170. package/src/render/index.js +367 -0
  171. package/src/scene/Disposable.js +498 -0
  172. package/src/scene/MemoryPool.js +618 -0
  173. package/src/scene/Node4D.js +697 -0
  174. package/src/scene/ResourceManager.js +599 -0
  175. package/src/scene/Scene4D.js +540 -0
  176. package/src/scene/index.js +98 -0
  177. package/src/schemas/error.schema.json +84 -0
  178. package/src/schemas/extension.schema.json +88 -0
  179. package/src/schemas/index.js +214 -0
  180. package/src/schemas/parameters.schema.json +142 -0
  181. package/src/schemas/tool-pack.schema.json +44 -0
  182. package/src/schemas/tool-response.schema.json +127 -0
  183. package/src/shaders/common/fullscreen.vert.glsl +5 -0
  184. package/src/shaders/common/fullscreen.vert.wgsl +17 -0
  185. package/src/shaders/common/geometry24.glsl +65 -0
  186. package/src/shaders/common/geometry24.wgsl +54 -0
  187. package/src/shaders/common/rotation4d.glsl +85 -0
  188. package/src/shaders/common/rotation4d.wgsl +86 -0
  189. package/src/shaders/common/uniforms.glsl +44 -0
  190. package/src/shaders/common/uniforms.wgsl +48 -0
  191. package/src/shaders/faceted/faceted.frag.glsl +129 -0
  192. package/src/shaders/faceted/faceted.frag.wgsl +164 -0
  193. package/src/shaders/holographic/holographic.frag.glsl +406 -0
  194. package/src/shaders/holographic/holographic.frag.wgsl +185 -0
  195. package/src/shaders/quantum/quantum.frag.glsl +513 -0
  196. package/src/shaders/quantum/quantum.frag.wgsl +361 -0
  197. package/src/testing/ParallelTestFramework.js +519 -0
  198. package/src/testing/__snapshots__/exportFormats.test.js.snap +24 -0
  199. package/src/testing/exportFormats.test.js +8 -0
  200. package/src/testing/projections.test.js +14 -0
  201. package/src/testing/rotations.test.js +37 -0
  202. package/src/ui/InteractivityMenu.js +516 -0
  203. package/src/ui/StatusManager.js +96 -0
  204. package/src/ui/adaptive/renderers/webgpu/BufferLayout.ts +252 -0
  205. package/src/ui/adaptive/renderers/webgpu/PolytopeInstanceBuffer.ts +144 -0
  206. package/src/ui/adaptive/renderers/webgpu/TripleBufferedUniform.ts +170 -0
  207. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +735 -0
  208. package/src/ui/adaptive/renderers/webgpu/index.ts +112 -0
  209. package/src/variations/VariationManager.js +431 -0
  210. package/src/viewer/AudioReactivity.js +505 -0
  211. package/src/viewer/CardBending.js +481 -0
  212. package/src/viewer/GalleryUI.js +832 -0
  213. package/src/viewer/ReactivityManager.js +590 -0
  214. package/src/viewer/TradingCardExporter.js +600 -0
  215. package/src/viewer/ViewerPortal.js +374 -0
  216. package/src/viewer/index.js +12 -0
  217. package/src/wasm/WasmLoader.js +296 -0
  218. package/src/wasm/index.js +132 -0
  219. package/tools/agentic/mcpTools.js +88 -0
  220. package/tools/cli/agent-cli.js +92 -0
  221. package/tools/export/formats.js +24 -0
  222. package/tools/math/rotation-baseline.mjs +64 -0
  223. package/tools/shader-sync-verify.js +937 -0
  224. package/tools/telemetry/manifestPipeline.js +141 -0
  225. package/tools/telemetry/telemetryEvents.js +35 -0
  226. package/types/adaptive-sdk.d.ts +185 -0
  227. package/types/advanced/AIPresetGenerator.d.ts +81 -0
  228. package/types/advanced/MIDIController.d.ts +100 -0
  229. package/types/advanced/OffscreenWorker.d.ts +82 -0
  230. package/types/advanced/WebGPUCompute.d.ts +52 -0
  231. package/types/advanced/WebXRRenderer.d.ts +77 -0
  232. package/types/advanced/index.d.ts +46 -0
  233. package/types/core/ErrorReporter.d.ts +50 -0
  234. package/types/core/VIB3Engine.d.ts +204 -0
  235. package/types/creative/ColorPresetsSystem.d.ts +91 -0
  236. package/types/creative/ParameterTimeline.d.ts +74 -0
  237. package/types/creative/PostProcessingPipeline.d.ts +109 -0
  238. package/types/creative/TransitionAnimator.d.ts +71 -0
  239. package/types/creative/index.d.ts +35 -0
  240. package/types/integrations/FigmaPlugin.d.ts +46 -0
  241. package/types/integrations/OBSMode.d.ts +74 -0
  242. package/types/integrations/ThreeJsPackage.d.ts +62 -0
  243. package/types/integrations/TouchDesignerExport.d.ts +36 -0
  244. package/types/integrations/Vib3React.d.ts +74 -0
  245. package/types/integrations/Vib3Svelte.d.ts +63 -0
  246. package/types/integrations/Vib3Vue.d.ts +55 -0
  247. package/types/integrations/index.d.ts +52 -0
  248. package/types/reactivity/SpatialInputSystem.d.ts +173 -0
  249. package/types/reactivity/index.d.ts +394 -0
  250. package/types/render/CommandBuffer.d.ts +169 -0
  251. package/types/render/RenderCommand.d.ts +312 -0
  252. package/types/render/RenderState.d.ts +279 -0
  253. package/types/render/RenderTarget.d.ts +254 -0
  254. package/types/render/ShaderProgram.d.ts +277 -0
  255. package/types/render/UnifiedRenderBridge.d.ts +143 -0
  256. package/types/render/WebGLBackend.d.ts +168 -0
  257. package/types/render/WebGPUBackend.d.ts +186 -0
  258. package/types/render/index.d.ts +141 -0
@@ -0,0 +1,966 @@
1
+ /**
2
+ * REAL Holographic System - Modified for holo-* canvas IDs
3
+ * Uses the elaborate effects from active-holographic-systems-FIXED
4
+ * Audio reactive only - no mouse/touch/scroll interference
5
+ */
6
+ import { HolographicVisualizer } from './HolographicVisualizer.js';
7
+ import { MultiCanvasBridge } from '../render/MultiCanvasBridge.js';
8
+ import { shaderLoader } from '../render/ShaderLoader.js';
9
+
10
+ export class RealHolographicSystem {
11
+ constructor(options = {}) {
12
+ this.visualizers = [];
13
+ this.currentVariant = 0;
14
+ this.baseVariants = 30; // Original 30 variations
15
+ this.totalVariants = 30;
16
+ this.isActive = false;
17
+
18
+ // Canvas override for single-canvas multi-instance mode
19
+ /** @type {HTMLCanvasElement|null} */
20
+ this.canvasOverride = options.canvas || null;
21
+
22
+ // Bridge rendering state
23
+ /** @type {MultiCanvasBridge|null} */
24
+ this._multiCanvasBridge = null;
25
+ /** @type {'direct'|'bridge'} */
26
+ this._renderMode = 'direct';
27
+ /** @type {number} time accumulator for bridge rendering (ms) */
28
+ this._bridgeTime = 0;
29
+
30
+ // Conditional reactivity: Use built-in only if ReactivityManager not active
31
+ this.useBuiltInReactivity = !window.reactivityManager;
32
+
33
+ // Audio reactivity system
34
+ this.audioEnabled = false;
35
+ this.audioContext = null;
36
+ this.analyser = null;
37
+ this.frequencyData = null;
38
+ this.audioData = { bass: 0, mid: 0, high: 0 };
39
+
40
+ // Variant names for display - SEQUENTIAL ORDER
41
+ this.variantNames = [
42
+ // 0-3: TETRAHEDRON variations
43
+ 'TETRAHEDRON LATTICE', 'TETRAHEDRON FIELD', 'TETRAHEDRON MATRIX', 'TETRAHEDRON RESONANCE',
44
+ // 4-7: HYPERCUBE variations
45
+ 'HYPERCUBE LATTICE', 'HYPERCUBE FIELD', 'HYPERCUBE MATRIX', 'HYPERCUBE QUANTUM',
46
+ // 8-11: SPHERE variations
47
+ 'SPHERE LATTICE', 'SPHERE FIELD', 'SPHERE MATRIX', 'SPHERE RESONANCE',
48
+ // 12-15: TORUS variations
49
+ 'TORUS LATTICE', 'TORUS FIELD', 'TORUS MATRIX', 'TORUS QUANTUM',
50
+ // 16-19: KLEIN BOTTLE variations
51
+ 'KLEIN BOTTLE LATTICE', 'KLEIN BOTTLE FIELD', 'KLEIN BOTTLE MATRIX', 'KLEIN BOTTLE QUANTUM',
52
+ // 20-22: FRACTAL variations
53
+ 'FRACTAL LATTICE', 'FRACTAL FIELD', 'FRACTAL QUANTUM',
54
+ // 23-25: WAVE variations
55
+ 'WAVE LATTICE', 'WAVE FIELD', 'WAVE QUANTUM',
56
+ // 26-29: CRYSTAL variations
57
+ 'CRYSTAL LATTICE', 'CRYSTAL FIELD', 'CRYSTAL MATRIX', 'CRYSTAL QUANTUM'
58
+ ];
59
+
60
+ this.initialize();
61
+ }
62
+
63
+ initialize() {
64
+ console.log('๐ŸŽจ Initializing REAL Holographic System for Active Holograms tab...');
65
+ this.createVisualizers();
66
+ this.setupCenterDistanceReactivity(); // NEW: Center-distance grid density changes
67
+ this.updateVariantDisplay();
68
+ this.startRenderLoop();
69
+ }
70
+
71
+ createVisualizers() {
72
+ // Single-canvas override mode: lightweight content-only layer
73
+ if (this.canvasOverride) {
74
+ try {
75
+ const visualizer = new HolographicVisualizer(
76
+ this.canvasOverride, 'content', 1.0, this.currentVariant
77
+ );
78
+ if (visualizer.gl) {
79
+ this.visualizers.push(visualizer);
80
+ console.log('โœ… Created holographic single-canvas visualizer (content layer)');
81
+ } else {
82
+ console.warn('โš ๏ธ No WebGL context for holographic canvasOverride');
83
+ }
84
+ } catch (error) {
85
+ console.warn('Failed to create holographic single-canvas visualizer:', error);
86
+ }
87
+ return;
88
+ }
89
+
90
+ // Create the 5 visualizers using HOLO canvas IDs
91
+ const layers = [
92
+ { id: 'holo-background-canvas', role: 'background', reactivity: 0.5 },
93
+ { id: 'holo-shadow-canvas', role: 'shadow', reactivity: 0.7 },
94
+ { id: 'holo-content-canvas', role: 'content', reactivity: 0.9 },
95
+ { id: 'holo-highlight-canvas', role: 'highlight', reactivity: 1.1 },
96
+ { id: 'holo-accent-canvas', role: 'accent', reactivity: 1.5 }
97
+ ];
98
+
99
+ let successfulLayers = 0;
100
+ layers.forEach(layer => {
101
+ try {
102
+ // Check if canvas element exists
103
+ const canvas = document.getElementById(layer.id);
104
+ if (!canvas) {
105
+ console.error(`โŒ Canvas not found: ${layer.id}`);
106
+ return;
107
+ }
108
+
109
+ console.log(`๐Ÿ” Creating holographic visualizer for: ${layer.id}`);
110
+ const visualizer = new HolographicVisualizer(layer.id, layer.role, layer.reactivity, this.currentVariant);
111
+
112
+ if (visualizer.gl) {
113
+ this.visualizers.push(visualizer);
114
+ successfulLayers++;
115
+ console.log(`โœ… Created REAL holographic layer: ${layer.role} (${layer.id})`);
116
+ } else {
117
+ console.error(`โŒ No WebGL context for: ${layer.id}`);
118
+ }
119
+ } catch (error) {
120
+ console.error(`โŒ Failed to create REAL holographic layer ${layer.id}:`, error);
121
+ }
122
+ });
123
+
124
+ console.log(`โœ… Created ${successfulLayers}/5 REAL holographic layers`);
125
+
126
+ if (successfulLayers === 0) {
127
+ console.error('๐Ÿšจ NO HOLOGRAPHIC VISUALIZERS CREATED! Check canvas elements and WebGL support.');
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Initialize the Holographic system through UnifiedRenderBridge / MultiCanvasBridge.
133
+ * Wires all 5 layers through the bridge for WebGL/WebGPU abstraction.
134
+ * Falls back to direct WebGL if bridge initialization fails.
135
+ *
136
+ * @param {object} [options]
137
+ * @param {boolean} [options.preferWebGPU=true]
138
+ * @param {boolean} [options.debug=false]
139
+ * @returns {Promise<boolean>} True if bridge mode activated
140
+ */
141
+ async initWithBridge(options = {}) {
142
+ try {
143
+ const bridge = await this.createMultiCanvasBridge(options);
144
+ if (bridge && bridge.initialized) {
145
+ this._renderMode = 'bridge';
146
+ this._bridgeTime = 0;
147
+ console.log(`Holographic System initialized via ${bridge.backendType} bridge (${bridge.layerCount} layers)`);
148
+ return true;
149
+ }
150
+ console.warn('Holographic bridge init returned no bridge, staying in direct mode');
151
+ return false;
152
+ } catch (e) {
153
+ console.error('Holographic bridge init failed, staying in direct mode:', e);
154
+ this._renderMode = 'direct';
155
+ return false;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Create a MultiCanvasBridge for WebGPU rendering.
161
+ * Returns a configured bridge with holographic shaders compiled on all layers.
162
+ *
163
+ * @param {object} [options]
164
+ * @param {boolean} [options.preferWebGPU=true]
165
+ * @returns {Promise<MultiCanvasBridge|null>}
166
+ */
167
+ async createMultiCanvasBridge(options = {}) {
168
+ const canvasMap = {};
169
+ const layerIds = {
170
+ background: 'holo-background-canvas',
171
+ shadow: 'holo-shadow-canvas',
172
+ content: 'holo-content-canvas',
173
+ highlight: 'holo-highlight-canvas',
174
+ accent: 'holo-accent-canvas'
175
+ };
176
+
177
+ for (const [role, id] of Object.entries(layerIds)) {
178
+ const el = document.getElementById(id);
179
+ if (el) canvasMap[role] = el;
180
+ }
181
+
182
+ if (Object.keys(canvasMap).length === 0) return null;
183
+
184
+ const bridge = new MultiCanvasBridge();
185
+ await bridge.initialize({ canvases: canvasMap, preferWebGPU: options.preferWebGPU !== false });
186
+
187
+ // Load external shader files, fall back to inline if unavailable
188
+ let sources = {
189
+ glslVertex: 'attribute vec2 a_position;\nvoid main() { gl_Position = vec4(a_position, 0.0, 1.0); }',
190
+ glslFragment: null,
191
+ wgslFragment: null
192
+ };
193
+
194
+ try {
195
+ const external = await shaderLoader.loadShaderPair('holographic', 'holographic/holographic.frag');
196
+ if (external.glslVertex) sources.glslVertex = external.glslVertex;
197
+ if (external.glslFragment) sources.glslFragment = external.glslFragment;
198
+ if (external.wgslFragment) sources.wgslFragment = external.wgslFragment;
199
+ } catch (loadErr) {
200
+ console.warn('Holographic external shader load failed, using inline fallback');
201
+ }
202
+
203
+ if (sources.glslFragment || sources.wgslFragment) {
204
+ const result = bridge.compileShaderAll('holographic', sources);
205
+ if (result.failed.length > 0) {
206
+ console.warn(`Holographic shader compilation failed on layers: ${result.failed.join(', ')}`);
207
+ }
208
+ }
209
+
210
+ this._multiCanvasBridge = bridge;
211
+ return bridge;
212
+ }
213
+
214
+ /**
215
+ * Build the VIB3+ standard uniform object from current parameters and audio data.
216
+ * Used by bridge rendering to send uniforms to external shader programs.
217
+ * @private
218
+ * @returns {object}
219
+ */
220
+ _buildSharedUniforms() {
221
+ const params = this.getParameters();
222
+ const audio = this.audioData || { bass: 0, mid: 0, high: 0 };
223
+
224
+ return {
225
+ u_time: this._bridgeTime,
226
+ u_resolution: null, // Set per-layer by MultiCanvasBridge
227
+ u_geometry: params.geometry || 0,
228
+ u_rot4dXY: params.rot4dXY || 0,
229
+ u_rot4dXZ: params.rot4dXZ || 0,
230
+ u_rot4dYZ: params.rot4dYZ || 0,
231
+ u_rot4dXW: params.rot4dXW || 0,
232
+ u_rot4dYW: params.rot4dYW || 0,
233
+ u_rot4dZW: params.rot4dZW || 0,
234
+ u_dimension: params.dimension || 3.5,
235
+ u_gridDensity: params.gridDensity || 15,
236
+ u_morphFactor: params.morphFactor || 1.0,
237
+ u_chaos: params.chaos || 0.2,
238
+ u_speed: params.speed || 1.0,
239
+ u_hue: params.hue || 320,
240
+ u_intensity: params.intensity || 0.6,
241
+ u_saturation: params.saturation || 0.8,
242
+ u_mouseIntensity: 0,
243
+ u_clickIntensity: this.colorBurstIntensity || 0,
244
+ u_bass: audio.bass || 0,
245
+ u_mid: audio.mid || 0,
246
+ u_high: audio.high || 0
247
+ };
248
+ }
249
+
250
+ /**
251
+ * Render a single frame via the MultiCanvasBridge.
252
+ * Sets shared uniforms and renders all 5 layers with the external holographic shader.
253
+ * @private
254
+ */
255
+ _renderBridgeFrame() {
256
+ if (!this._multiCanvasBridge || !this._multiCanvasBridge.initialized) return;
257
+
258
+ this._bridgeTime += 16; // ~60fps increment
259
+
260
+ const uniforms = this._buildSharedUniforms();
261
+
262
+ // Set canvas resolution per layer before rendering
263
+ for (const layerName of this._multiCanvasBridge.layerNames) {
264
+ const bridge = this._multiCanvasBridge.getBridge(layerName);
265
+ if (bridge && bridge.canvas) {
266
+ this._multiCanvasBridge.setLayerUniforms(layerName, {
267
+ u_resolution: [bridge.canvas.width, bridge.canvas.height]
268
+ });
269
+ }
270
+ }
271
+
272
+ this._multiCanvasBridge.setSharedUniforms(uniforms);
273
+ this._multiCanvasBridge.renderAll('holographic', { clearColor: [0, 0, 0, 0] });
274
+ }
275
+
276
+ setActive(active) {
277
+ this.isActive = active;
278
+
279
+ if (active) {
280
+ // Show holographic layers (skip in single-canvas override mode)
281
+ if (!this.canvasOverride) {
282
+ const holoLayers = document.getElementById('holographicLayers');
283
+ if (holoLayers) {
284
+ holoLayers.style.display = 'block';
285
+ }
286
+ }
287
+
288
+ // Start audio only if globally enabled and not already started
289
+ if (!this.audioEnabled && window.audioEnabled === true) {
290
+ this.initAudio();
291
+ }
292
+ console.log('๐ŸŒŒ REAL Active Holograms ACTIVATED with audio reactivity');
293
+ } else {
294
+ // Hide holographic layers (skip in single-canvas override mode)
295
+ if (!this.canvasOverride) {
296
+ const holoLayers = document.getElementById('holographicLayers');
297
+ if (holoLayers) {
298
+ holoLayers.style.display = 'none';
299
+ }
300
+ }
301
+ console.log('๐ŸŒŒ REAL Active Holograms DEACTIVATED');
302
+ }
303
+ }
304
+
305
+
306
+ updateVariantDisplay() {
307
+ // This will be called by the main UI system
308
+ const variantName = this.variantNames[this.currentVariant];
309
+ return {
310
+ variant: this.currentVariant,
311
+ name: variantName,
312
+ geometryType: Math.floor(this.currentVariant / 4)
313
+ };
314
+ }
315
+
316
+ nextVariant() {
317
+ this.updateVariant(this.currentVariant + 1);
318
+ }
319
+
320
+ previousVariant() {
321
+ this.updateVariant(this.currentVariant - 1);
322
+ }
323
+
324
+ randomVariant() {
325
+ const randomIndex = Math.floor(Math.random() * this.totalVariants);
326
+ this.updateVariant(randomIndex);
327
+ }
328
+
329
+ setVariant(variant) {
330
+ this.updateVariant(variant);
331
+ }
332
+
333
+ updateParameter(param, value) {
334
+ // Store custom parameter overrides
335
+ if (!this.customParams) {
336
+ this.customParams = {};
337
+ }
338
+ this.customParams[param] = value;
339
+
340
+ console.log(`๐ŸŒŒ Updating holographic ${param}: ${value} (${this.visualizers.length} visualizers)`);
341
+
342
+ // CRITICAL FIX: Call updateParameters method on ALL visualizers for immediate render
343
+ this.visualizers.forEach((visualizer, index) => {
344
+ try {
345
+ if (visualizer.updateParameters) {
346
+ // Use new updateParameters method with proper parameter mapping
347
+ const params = {};
348
+ params[param] = value;
349
+ visualizer.updateParameters(params);
350
+ console.log(`โœ… Updated holographic layer ${index} (${visualizer.role}) with ${param}=${value}`);
351
+ } else {
352
+ console.warn(`โš ๏ธ Holographic layer ${index} missing updateParameters method, using fallback`);
353
+ // Fallback for older method (direct parameter setting)
354
+ if (visualizer.variantParams) {
355
+ visualizer.variantParams[param] = value;
356
+
357
+ // If it's a geometry type change, regenerate role params with new geometry
358
+ if (param === 'geometryType') {
359
+ visualizer.roleParams = visualizer.generateRoleParams(visualizer.role);
360
+ }
361
+
362
+ // Force manual render for older visualizers
363
+ if (visualizer.render) {
364
+ visualizer.render();
365
+ }
366
+ }
367
+ }
368
+ } catch (error) {
369
+ console.error(`โŒ Failed to update holographic layer ${index}:`, error);
370
+ }
371
+ });
372
+
373
+ console.log(`๐Ÿ”„ Holographic parameter update complete: ${param}=${value}`);
374
+ }
375
+
376
+ // Override updateVariant to preserve custom parameters
377
+ updateVariant(newVariant) {
378
+ if (newVariant < 0) newVariant = this.totalVariants - 1;
379
+ if (newVariant >= this.totalVariants) newVariant = 0;
380
+
381
+ this.currentVariant = newVariant;
382
+
383
+ // Update all visualizers with new variant parameters
384
+ this.visualizers.forEach(visualizer => {
385
+ visualizer.variant = this.currentVariant;
386
+ visualizer.variantParams = visualizer.generateVariantParams(this.currentVariant);
387
+ visualizer.roleParams = visualizer.generateRoleParams(visualizer.role);
388
+
389
+ // Apply any custom parameter overrides
390
+ if (this.customParams) {
391
+ Object.keys(this.customParams).forEach(param => {
392
+ visualizer.variantParams[param] = this.customParams[param];
393
+ });
394
+ }
395
+ });
396
+
397
+ this.updateVariantDisplay();
398
+ console.log(`๐Ÿ”„ REAL Holograms switched to variant ${this.currentVariant + 1}: ${this.variantNames[this.currentVariant]}`);
399
+ }
400
+
401
+ getCurrentVariantInfo() {
402
+ return {
403
+ variant: this.currentVariant,
404
+ name: this.variantNames[this.currentVariant],
405
+ geometryType: Math.floor(this.currentVariant / 4)
406
+ };
407
+ }
408
+
409
+ /**
410
+ * Get current parameters for saving/export (CRITICAL for gallery saving)
411
+ */
412
+ getParameters() {
413
+ // Collect parameters from UI sliders - same as other systems
414
+ const params = {
415
+ geometry: Math.floor(this.currentVariant / 4), // Extract geometry from variant
416
+ gridDensity: parseFloat(document.getElementById('gridDensity')?.value || 15),
417
+ morphFactor: parseFloat(document.getElementById('morphFactor')?.value || 1.0),
418
+ chaos: parseFloat(document.getElementById('chaos')?.value || 0.2),
419
+ speed: parseFloat(document.getElementById('speed')?.value || 1.0),
420
+ hue: parseFloat(document.getElementById('hue')?.value || 320),
421
+ intensity: parseFloat(document.getElementById('intensity')?.value || 0.6),
422
+ saturation: parseFloat(document.getElementById('saturation')?.value || 0.8),
423
+ rot4dXW: parseFloat(document.getElementById('rot4dXW')?.value || 0.0),
424
+ rot4dYW: parseFloat(document.getElementById('rot4dYW')?.value || 0.0),
425
+ rot4dZW: parseFloat(document.getElementById('rot4dZW')?.value || 0.0),
426
+ variant: this.currentVariant
427
+ };
428
+
429
+ // Apply any custom parameter overrides
430
+ if (this.customParams) {
431
+ Object.assign(params, this.customParams);
432
+ }
433
+
434
+ console.log('๐ŸŒŒ Holographic system getParameters:', params);
435
+ return params;
436
+ }
437
+
438
+ async initAudio() {
439
+ try {
440
+ this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
441
+
442
+ if (this.audioContext.state === 'suspended') {
443
+ await this.audioContext.resume();
444
+ }
445
+
446
+ this.analyser = this.audioContext.createAnalyser();
447
+ this.analyser.fftSize = 256;
448
+ this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount);
449
+
450
+ const constraints = {
451
+ audio: {
452
+ echoCancellation: false,
453
+ noiseSuppression: false,
454
+ autoGainControl: false,
455
+ sampleRate: 44100
456
+ }
457
+ };
458
+
459
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
460
+ this._audioStream = stream;
461
+ const source = this.audioContext.createMediaStreamSource(stream);
462
+ source.connect(this.analyser);
463
+
464
+ this.audioEnabled = true;
465
+ console.log('REAL Holograms audio reactivity enabled');
466
+ } catch (error) {
467
+ console.error('REAL Holograms audio initialization failed:', error);
468
+ }
469
+ }
470
+
471
+ // NEW: Disable holographic audio (respects global audio toggle)
472
+ disableAudio() {
473
+ if (this.audioEnabled) {
474
+ this.audioEnabled = false;
475
+ // Stop audio stream tracks to release microphone
476
+ if (this._audioStream) {
477
+ this._audioStream.getTracks().forEach(track => track.stop());
478
+ this._audioStream = null;
479
+ }
480
+ if (this.audioContext) {
481
+ this.audioContext.close().catch(() => {});
482
+ this.audioContext = null;
483
+ }
484
+ this.analyser = null;
485
+ this.frequencyData = null;
486
+ this.audioData = { bass: 0, mid: 0, high: 0 };
487
+ console.log('REAL Holograms audio reactivity disabled');
488
+ }
489
+ }
490
+
491
+ updateAudio() {
492
+ if (!this.audioEnabled || !this.analyser || !this.isActive || window.audioEnabled === false) return;
493
+
494
+ this.analyser.getByteFrequencyData(this.frequencyData);
495
+
496
+ const bassEnd = Math.floor(this.frequencyData.length * 0.1);
497
+ const midEnd = Math.floor(this.frequencyData.length * 0.4);
498
+
499
+ let bass = 0, mid = 0, high = 0;
500
+
501
+ for (let i = 0; i < bassEnd; i++) {
502
+ bass += this.frequencyData[i];
503
+ }
504
+ bass /= (bassEnd * 255);
505
+
506
+ for (let i = bassEnd; i < midEnd; i++) {
507
+ mid += this.frequencyData[i];
508
+ }
509
+ mid /= ((midEnd - bassEnd) * 255);
510
+
511
+ for (let i = midEnd; i < this.frequencyData.length; i++) {
512
+ high += this.frequencyData[i];
513
+ }
514
+ high /= ((this.frequencyData.length - midEnd) * 255);
515
+
516
+ // Enhanced audio processing for better visual response
517
+ const smoothedAudio = {
518
+ bass: this.smoothAudioValue(bass, 'bass'),
519
+ mid: this.smoothAudioValue(mid, 'mid'),
520
+ high: this.smoothAudioValue(high, 'high'),
521
+ energy: (bass + mid + high) / 3,
522
+ rhythm: this.detectRhythm(bass),
523
+ melody: this.detectMelody(mid, high)
524
+ };
525
+
526
+ this.audioData = smoothedAudio;
527
+
528
+ // Apply NEW AUDIO REACTIVITY GRID SETTINGS if available
529
+ if (window.audioReactivitySettings) {
530
+ this.applyAudioReactivityGrid(smoothedAudio);
531
+ }
532
+
533
+ // Apply audio reactivity to all visualizers
534
+ this.visualizers.forEach(visualizer => {
535
+ visualizer.updateAudio(this.audioData);
536
+ });
537
+ }
538
+
539
+ smoothAudioValue(currentValue, type) {
540
+ if (!this.audioSmoothing) {
541
+ this.audioSmoothing = { bass: 0, mid: 0, high: 0 };
542
+ }
543
+
544
+ const smoothingFactor = 0.4;
545
+ this.audioSmoothing[type] = this.audioSmoothing[type] * smoothingFactor + currentValue * (1 - smoothingFactor);
546
+
547
+ const threshold = 0.05;
548
+ return this.audioSmoothing[type] > threshold ? this.audioSmoothing[type] : 0;
549
+ }
550
+
551
+ detectRhythm(bassLevel) {
552
+ if (!this.previousBass) this.previousBass = 0;
553
+ const beatDetected = bassLevel > this.previousBass + 0.2;
554
+ this.previousBass = bassLevel;
555
+ return beatDetected ? 1.0 : 0.0;
556
+ }
557
+
558
+ detectMelody(midLevel, highLevel) {
559
+ const melodicActivity = (midLevel + highLevel) / 2;
560
+ return melodicActivity > 0.3 ? melodicActivity : 0.0;
561
+ }
562
+
563
+ applyAudioReactivityGrid(audioData) {
564
+ const settings = window.audioReactivitySettings;
565
+ if (!settings || settings.activeVisualModes.size === 0) return;
566
+
567
+ // Get sensitivity multiplier
568
+ const sensitivityMultiplier = settings.sensitivity[settings.activeSensitivity];
569
+
570
+ // Apply audio changes to different visual modes
571
+ settings.activeVisualModes.forEach(modeKey => {
572
+ const [sensitivity, visualMode] = modeKey.split('-');
573
+ const paramList = settings.visualModes[visualMode];
574
+
575
+ if (!paramList) return;
576
+
577
+ // Calculate audio intensity with sensitivity
578
+ const audioIntensity = (audioData.energy * sensitivityMultiplier);
579
+ const bassIntensity = (audioData.bass * sensitivityMultiplier);
580
+ const rhythmIntensity = (audioData.rhythm * sensitivityMultiplier);
581
+
582
+ paramList.forEach(param => {
583
+ let currentValue = 0;
584
+
585
+ switch (param) {
586
+ case 'hue':
587
+ // Color: Audio-reactive hue cycling
588
+ if (!this.audioHueBase) this.audioHueBase = 320;
589
+ this.audioHueBase += audioIntensity * 5; // Smooth color shifts
590
+ currentValue = this.audioHueBase % 360;
591
+ break;
592
+
593
+ case 'saturation':
594
+ // Color: Beat-responsive saturation
595
+ currentValue = Math.min(1.0, 0.6 + (rhythmIntensity * 0.4));
596
+ break;
597
+
598
+ case 'intensity':
599
+ // Color: Energy-responsive brightness
600
+ currentValue = Math.min(1.0, 0.4 + (audioIntensity * 0.6));
601
+ break;
602
+
603
+ case 'morphFactor':
604
+ // Geometry: Audio-morphing shapes
605
+ currentValue = Math.min(2.0, 1.0 + (bassIntensity * 1.0));
606
+ break;
607
+
608
+ case 'gridDensity':
609
+ // Geometry: Beat-responsive density
610
+ currentValue = Math.min(100, 15 + (rhythmIntensity * 50));
611
+ break;
612
+
613
+ case 'chaos':
614
+ // Geometry: Energy-chaos correlation
615
+ currentValue = Math.min(1.0, audioIntensity * 0.8);
616
+ break;
617
+
618
+ case 'speed':
619
+ // Movement: Tempo-responsive animation
620
+ currentValue = Math.min(3.0, 1.0 + (audioIntensity * 2.0));
621
+ break;
622
+
623
+ case 'rot4dXW':
624
+ // Movement: Bass-driven rotation
625
+ if (!this.audioRotationXW) this.audioRotationXW = 0;
626
+ this.audioRotationXW += bassIntensity * 0.1;
627
+ currentValue = this.audioRotationXW % (Math.PI * 2);
628
+ break;
629
+
630
+ case 'rot4dYW':
631
+ // Movement: Mid-frequency rotation
632
+ if (!this.audioRotationYW) this.audioRotationYW = 0;
633
+ this.audioRotationYW += audioData.mid * sensitivityMultiplier * 0.08;
634
+ currentValue = this.audioRotationYW % (Math.PI * 2);
635
+ break;
636
+
637
+ case 'rot4dZW':
638
+ // Movement: High-frequency rotation
639
+ if (!this.audioRotationZW) this.audioRotationZW = 0;
640
+ this.audioRotationZW += audioData.high * sensitivityMultiplier * 0.06;
641
+ currentValue = this.audioRotationZW % (Math.PI * 2);
642
+ break;
643
+ }
644
+
645
+ // Apply the parameter change
646
+ if (window.updateParameter && currentValue !== undefined) {
647
+ window.updateParameter(param, currentValue.toFixed(2));
648
+ }
649
+ });
650
+ });
651
+ }
652
+
653
+ setupCenterDistanceReactivity() {
654
+ // AUDIO ONLY - No mouse/touch/scroll interference
655
+ // Holographic system is purely audio-reactive now
656
+ console.log('โœจ Holographic system: AUDIO-ONLY mode (no mouse/touch reactivity)');
657
+
658
+ if (this.canvasOverride) {
659
+ console.log('โœจ Holographic reactivity skipped (single-canvas override mode)');
660
+ return;
661
+ }
662
+
663
+ // If ReactivityManager is active, it handles all interactivity
664
+ if (!this.useBuiltInReactivity) {
665
+ console.log('โœจ Holographic built-in reactivity DISABLED - ReactivityManager active');
666
+ return;
667
+ }
668
+
669
+ // NO EVENT LISTENERS - Audio reactivity only
670
+ console.log('๐ŸŽต Holographic system will respond to audio input only');
671
+ }
672
+
673
+ updateHolographicShimmer(x, y) {
674
+ // HOLOGRAPHIC TRADING CARD SHIMMER EFFECTS
675
+ // Calculate position-based shimmer like real holographic cards
676
+
677
+ // Create iridescent shimmer based on viewing angle (mouse position)
678
+ const angleX = (x - 0.5) * Math.PI; // -ฯ€/2 to ฯ€/2
679
+ const angleY = (y - 0.5) * Math.PI;
680
+
681
+ // Holographic rainbow shimmer - shifts through spectrum based on angle
682
+ const baseHue = 320; // Start with magenta-pink
683
+ const shimmerRange = 120; // Cover 120 degrees of spectrum
684
+ const hueShimmer = Math.sin(angleX * 2) * Math.cos(angleY * 2) * shimmerRange;
685
+ const shimmerHue = (baseHue + hueShimmer + 360) % 360;
686
+
687
+ // Iridescent intensity - varies with viewing angle like real holograms
688
+ const shimmerIntensity = 0.4 + (0.5 * Math.abs(Math.sin(angleX) * Math.cos(angleY)));
689
+
690
+ // Holographic saturation pulse - high saturation for vivid colors
691
+ const saturationPulse = 0.7 + (0.3 * Math.abs(Math.cos(angleX * 1.5) * Math.sin(angleY * 1.5)));
692
+
693
+ // Subtle depth illusion - slight morph based on angle (much more subtle than faceted)
694
+ const depthMorph = 1.0 + (0.15 * Math.sin(angleX * 0.8) * Math.cos(angleY * 0.8));
695
+
696
+ // Update holographic shimmer parameters
697
+ if (window.updateParameter) {
698
+ window.updateParameter('hue', Math.round(shimmerHue));
699
+ window.updateParameter('intensity', shimmerIntensity.toFixed(2));
700
+ window.updateParameter('saturation', saturationPulse.toFixed(2));
701
+ window.updateParameter('morphFactor', depthMorph.toFixed(2));
702
+ }
703
+
704
+ console.log(`โœจ Holographic shimmer: angle=(${angleX.toFixed(2)}, ${angleY.toFixed(2)}) โ†’ Hue=${Math.round(shimmerHue)}, Intensity=${shimmerIntensity.toFixed(2)}`);
705
+ }
706
+
707
+ triggerHolographicColorBurst(x, y) {
708
+ // DRAMATIC HOLOGRAPHIC COLOR BURST (like Quantum's dramatic click effects)
709
+
710
+ // Calculate energy based on click position
711
+ const centerX = 0.5;
712
+ const centerY = 0.5;
713
+ const distanceFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);
714
+ const normalizedDistance = Math.min(distanceFromCenter / 0.707, 1.0);
715
+
716
+ // QUANTUM-STYLE DRAMATIC EFFECTS
717
+ this.colorBurstIntensity = 1.0; // Full burst intensity
718
+
719
+ // Multi-parameter dramatic effects that decay back
720
+ this.burstHueShift = 180; // Dramatic hue shift across spectrum
721
+ this.burstIntensityBoost = 0.7; // Major intensity boost
722
+ this.burstSaturationSpike = 0.8; // Vivid color spike
723
+ this.burstChaosEffect = 0.6; // Chaos/morph burst effect
724
+ this.burstSpeedBoost = 1.8; // Animation speed burst
725
+
726
+ console.log(`๐ŸŒˆ๐Ÿ’ฅ HOLOGRAPHIC COLOR BURST: position=(${x.toFixed(2)}, ${y.toFixed(2)}), distance=${distanceFromCenter.toFixed(3)}`);
727
+ }
728
+
729
+ startHolographicColorBurstLoop() {
730
+ const burstAnimation = () => {
731
+ // DRAMATIC HOLOGRAPHIC COLOR BURST ANIMATION (like Quantum's multi-parameter effects)
732
+ let hasActiveEffects = false;
733
+
734
+ if (this.colorBurstIntensity > 0.01) {
735
+ hasActiveEffects = true;
736
+
737
+ // Phase-based burst animation with color cycling
738
+ const burstPhase = this.colorBurstIntensity;
739
+
740
+ // HUE BURST: Cycle through rainbow spectrum
741
+ if (this.burstHueShift > 1) {
742
+ const baseHue = 320; // Holographic magenta base
743
+ const currentHueShift = this.burstHueShift * Math.sin(burstPhase * Math.PI * 2);
744
+ const burstHue = (baseHue + currentHueShift) % 360;
745
+
746
+ if (window.updateParameter) {
747
+ window.updateParameter('hue', Math.round(burstHue));
748
+ }
749
+ this.burstHueShift *= 0.93; // Smooth decay
750
+ }
751
+
752
+ // INTENSITY BURST: Dramatic brightness flash
753
+ if (this.burstIntensityBoost > 0.01) {
754
+ const baseIntensity = 0.5;
755
+ const burstIntensity = Math.min(1.0, baseIntensity + this.burstIntensityBoost * burstPhase);
756
+
757
+ if (window.updateParameter) {
758
+ window.updateParameter('intensity', burstIntensity.toFixed(2));
759
+ }
760
+ this.burstIntensityBoost *= 0.92;
761
+ }
762
+
763
+ // SATURATION SPIKE: Vivid color explosion
764
+ if (this.burstSaturationSpike > 0.01) {
765
+ const baseSaturation = 0.8;
766
+ const burstSaturation = Math.min(1.0, baseSaturation + this.burstSaturationSpike * burstPhase);
767
+
768
+ if (window.updateParameter) {
769
+ window.updateParameter('saturation', burstSaturation.toFixed(2));
770
+ }
771
+ this.burstSaturationSpike *= 0.91;
772
+ }
773
+
774
+ // CHAOS/MORPH EFFECT: Geometric distortion burst
775
+ if (this.burstChaosEffect > 0.01) {
776
+ const baseChaos = 0.2;
777
+ const burstChaos = baseChaos + this.burstChaosEffect * burstPhase;
778
+
779
+ if (window.updateParameter) {
780
+ window.updateParameter('chaos', burstChaos.toFixed(2));
781
+ }
782
+ this.burstChaosEffect *= 0.90;
783
+ }
784
+
785
+ // SPEED BOOST: Animation acceleration
786
+ if (this.burstSpeedBoost > 0.01) {
787
+ const baseSpeed = 1.0;
788
+ const burstSpeed = baseSpeed + this.burstSpeedBoost * burstPhase;
789
+
790
+ if (window.updateParameter) {
791
+ window.updateParameter('speed', burstSpeed.toFixed(2));
792
+ }
793
+ this.burstSpeedBoost *= 0.89;
794
+ }
795
+
796
+ // Master intensity decay
797
+ this.colorBurstIntensity *= 0.94;
798
+ }
799
+
800
+ if (this.isActive) {
801
+ requestAnimationFrame(burstAnimation);
802
+ }
803
+ };
804
+
805
+ burstAnimation();
806
+ }
807
+
808
+ startRenderLoop() {
809
+ const render = () => {
810
+ if (this.isActive) {
811
+ // Update audio reactivity
812
+ this.updateAudio();
813
+
814
+ if (this._renderMode === 'bridge') {
815
+ this._renderBridgeFrame();
816
+ } else {
817
+ // Direct mode: render all visualizers
818
+ this.visualizers.forEach(visualizer => {
819
+ visualizer.render();
820
+ });
821
+ }
822
+ }
823
+
824
+ requestAnimationFrame(render);
825
+ };
826
+
827
+ render();
828
+ console.log(`๐ŸŽฌ REAL Holographic render loop started (${this._renderMode} mode)`);
829
+ }
830
+
831
+ getVariantName(variant = this.currentVariant) {
832
+ return this.variantNames[variant] || 'UNKNOWN';
833
+ }
834
+
835
+ destroy() {
836
+ // Dispose bridge if active
837
+ if (this._multiCanvasBridge) {
838
+ this._multiCanvasBridge.dispose();
839
+ this._multiCanvasBridge = null;
840
+ }
841
+ this._renderMode = 'direct';
842
+
843
+ this.visualizers.forEach(visualizer => {
844
+ if (visualizer.destroy) {
845
+ visualizer.destroy();
846
+ }
847
+ });
848
+ this.visualizers = [];
849
+
850
+ if (this.audioContext) {
851
+ this.audioContext.close();
852
+ }
853
+
854
+ console.log('๐Ÿงน REAL Holographic System destroyed');
855
+ }
856
+
857
+ // ============================================
858
+ // RendererContract Compliance Methods
859
+ // ============================================
860
+
861
+ /**
862
+ * Initialize the renderer (RendererContract.init)
863
+ * For Holographic, initialization happens in constructor.
864
+ * This method allows re-initialization with a new context, including
865
+ * a canvas override for single-canvas multi-instance mode.
866
+ *
867
+ * @param {Object} [context] - Optional context
868
+ * @param {HTMLCanvasElement} [context.canvas] - Canvas element override
869
+ * @param {string} [context.canvasId] - Canvas ID to look up
870
+ * @returns {boolean} Success status
871
+ */
872
+ init(context = {}) {
873
+ const canvasEl = context.canvas ||
874
+ (context.canvasId ? document.getElementById(context.canvasId) : null);
875
+
876
+ if (canvasEl) {
877
+ this.canvasOverride = canvasEl;
878
+ // Tear down existing visualizers before re-init
879
+ this.visualizers.forEach(v => v.destroy && v.destroy());
880
+ this.visualizers = [];
881
+ }
882
+
883
+ // If already initialized (and no new canvas), just return success
884
+ if (this.visualizers.length > 0) {
885
+ return true;
886
+ }
887
+ // Otherwise initialize
888
+ this.initialize();
889
+ return this.visualizers.length > 0;
890
+ }
891
+
892
+ /**
893
+ * Handle canvas resize (RendererContract.resize)
894
+ * @param {number} width - New width in pixels
895
+ * @param {number} height - New height in pixels
896
+ * @param {number} [pixelRatio=1] - Device pixel ratio
897
+ */
898
+ resize(width, height, pixelRatio = 1) {
899
+ if (this._renderMode === 'bridge' && this._multiCanvasBridge) {
900
+ this._multiCanvasBridge.resizeAll(width, height, pixelRatio);
901
+ } else {
902
+ this.visualizers.forEach(visualizer => {
903
+ if (visualizer.canvas && visualizer.gl) {
904
+ visualizer.canvas.width = width * pixelRatio;
905
+ visualizer.canvas.height = height * pixelRatio;
906
+ visualizer.canvas.style.width = `${width}px`;
907
+ visualizer.canvas.style.height = `${height}px`;
908
+ visualizer.gl.viewport(0, 0, visualizer.canvas.width, visualizer.canvas.height);
909
+ }
910
+ });
911
+ }
912
+ console.log(`๐ŸŒŒ Holographic resized to ${width}x${height} @${pixelRatio}x`);
913
+ }
914
+
915
+ /**
916
+ * Render a single frame (RendererContract.render)
917
+ * @param {Object} [frameState] - Frame state with time, params, audio
918
+ */
919
+ render(frameState = {}) {
920
+ // Apply frameState parameters if provided
921
+ if (frameState.params) {
922
+ Object.keys(frameState.params).forEach(param => {
923
+ this.updateParameter(param, frameState.params[param]);
924
+ });
925
+ }
926
+
927
+ // Apply audio data if provided
928
+ if (frameState.audio) {
929
+ this.audioData = frameState.audio;
930
+ }
931
+
932
+ if (this._renderMode === 'bridge') {
933
+ this._renderBridgeFrame();
934
+ } else {
935
+ // Render all visualizers in direct mode
936
+ this.visualizers.forEach(visualizer => {
937
+ if (visualizer.render) {
938
+ visualizer.render();
939
+ }
940
+ });
941
+ }
942
+ }
943
+
944
+ /**
945
+ * Get the current rendering backend type.
946
+ * @returns {'direct-webgl'|string}
947
+ */
948
+ getBackendType() {
949
+ if (this._renderMode === 'bridge' && this._multiCanvasBridge) {
950
+ return this._multiCanvasBridge.backendType || 'bridge';
951
+ }
952
+ return 'direct-webgl';
953
+ }
954
+
955
+ /**
956
+ * Clean up all resources (RendererContract.dispose)
957
+ * Alias for destroy() for contract compliance
958
+ */
959
+ dispose() {
960
+ // Disable audio first
961
+ this.disableAudio();
962
+
963
+ // Call existing destroy
964
+ this.destroy();
965
+ }
966
+ }