@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.
- package/CHANGELOG.md +118 -0
- package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +34 -0
- package/DOCS/CI_TESTING.md +38 -0
- package/DOCS/CLI_ONBOARDING.md +75 -0
- package/DOCS/CONTROL_REFERENCE.md +64 -0
- package/DOCS/DEV_TRACK_ANALYSIS.md +77 -0
- package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +42 -0
- package/DOCS/DEV_TRACK_SESSION_2026-01-31.md +220 -0
- package/DOCS/ENV_SETUP.md +189 -0
- package/DOCS/EXPORT_FORMATS.md +417 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +21 -0
- package/DOCS/LICENSING_TIERS.md +275 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +570 -0
- package/DOCS/OBS_SETUP_GUIDE.md +98 -0
- package/DOCS/PROJECT_SETUP.md +66 -0
- package/DOCS/RENDERER_LIFECYCLE.md +40 -0
- package/DOCS/REPO_MANIFEST.md +121 -0
- package/DOCS/SESSION_014_PLAN.md +195 -0
- package/DOCS/SESSION_LOG_2026-01-07.md +56 -0
- package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +72 -0
- package/DOCS/SYSTEM_AUDIT_2026-01-30.md +738 -0
- package/DOCS/SYSTEM_INVENTORY.md +520 -0
- package/DOCS/TELEMETRY_EXPORTS.md +34 -0
- package/DOCS/WEBGPU_STATUS.md +38 -0
- package/DOCS/XR_BENCHMARKS.md +608 -0
- package/LICENSE +21 -0
- package/README.md +426 -0
- package/docs/.nojekyll +0 -0
- package/docs/01-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/02-hyperspatial_ego_death.html +346 -0
- package/docs/03-post_cartesian_sublime.html +346 -0
- package/docs/04-crystalline_void_meditation.html +346 -0
- package/docs/05-quantum_decoherence_ballet.html +346 -0
- package/docs/06-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/07-hyperspatial_ego_death.html +346 -0
- package/docs/08-post_cartesian_sublime.html +346 -0
- package/docs/09-crystalline_void_meditation.html +346 -0
- package/docs/10-quantum_decoherence_ballet.html +346 -0
- package/docs/11-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/12-hyperspatial_ego_death.html +346 -0
- package/docs/13-post_cartesian_sublime.html +346 -0
- package/docs/index.html +794 -0
- package/docs/test-hub.html +441 -0
- package/docs/url-state.js +102 -0
- package/docs/vib3-exports/01-quantum-quantum-tetrahedron-lattice.html +489 -0
- package/docs/vib3-exports/02-quantum-quantum-hypersphere-matrix.html +489 -0
- package/docs/vib3-exports/03-quantum-quantum-hypertetra-fractal.html +489 -0
- package/docs/vib3-exports/04-faceted-faceted-crystal-structure.html +407 -0
- package/docs/vib3-exports/05-faceted-faceted-klein-bottle.html +407 -0
- package/docs/vib3-exports/06-faceted-faceted-hypertetra-torus.html +407 -0
- package/docs/vib3-exports/07-holographic-holographic-wave-field.html +457 -0
- package/docs/vib3-exports/08-holographic-holographic-hypersphere-sphere.html +457 -0
- package/docs/vib3-exports/09-holographic-holographic-hypertetra-crystal.html +457 -0
- package/docs/vib3-exports/index.html +238 -0
- package/docs/webgpu-live.html +702 -0
- package/package.json +367 -0
- package/src/advanced/AIPresetGenerator.js +777 -0
- package/src/advanced/MIDIController.js +703 -0
- package/src/advanced/OffscreenWorker.js +1051 -0
- package/src/advanced/WebGPUCompute.js +1051 -0
- package/src/advanced/WebXRRenderer.js +680 -0
- package/src/agent/cli/AgentCLI.js +615 -0
- package/src/agent/cli/index.js +14 -0
- package/src/agent/index.js +73 -0
- package/src/agent/mcp/MCPServer.js +950 -0
- package/src/agent/mcp/index.js +9 -0
- package/src/agent/mcp/tools.js +548 -0
- package/src/agent/telemetry/EventStream.js +669 -0
- package/src/agent/telemetry/Instrumentation.js +618 -0
- package/src/agent/telemetry/TelemetryExporters.js +427 -0
- package/src/agent/telemetry/TelemetryService.js +464 -0
- package/src/agent/telemetry/index.js +52 -0
- package/src/benchmarks/BenchmarkRunner.js +381 -0
- package/src/benchmarks/MetricsCollector.js +299 -0
- package/src/benchmarks/index.js +9 -0
- package/src/benchmarks/scenes.js +259 -0
- package/src/cli/index.js +675 -0
- package/src/config/ApiConfig.js +88 -0
- package/src/core/CanvasManager.js +217 -0
- package/src/core/ErrorReporter.js +117 -0
- package/src/core/ParameterMapper.js +333 -0
- package/src/core/Parameters.js +396 -0
- package/src/core/RendererContracts.js +200 -0
- package/src/core/UnifiedResourceManager.js +370 -0
- package/src/core/VIB3Engine.js +636 -0
- package/src/core/renderers/FacetedRendererAdapter.js +32 -0
- package/src/core/renderers/HolographicRendererAdapter.js +29 -0
- package/src/core/renderers/QuantumRendererAdapter.js +29 -0
- package/src/core/renderers/RendererLifecycleManager.js +63 -0
- package/src/creative/ColorPresetsSystem.js +980 -0
- package/src/creative/ParameterTimeline.js +1061 -0
- package/src/creative/PostProcessingPipeline.js +1113 -0
- package/src/creative/TransitionAnimator.js +683 -0
- package/src/export/CSSExporter.js +226 -0
- package/src/export/CardGeneratorBase.js +279 -0
- package/src/export/ExportManager.js +580 -0
- package/src/export/FacetedCardGenerator.js +279 -0
- package/src/export/HolographicCardGenerator.js +543 -0
- package/src/export/LottieExporter.js +552 -0
- package/src/export/QuantumCardGenerator.js +315 -0
- package/src/export/SVGExporter.js +519 -0
- package/src/export/ShaderExporter.js +903 -0
- package/src/export/TradingCardGenerator.js +3055 -0
- package/src/export/TradingCardManager.js +181 -0
- package/src/export/VIB3PackageExporter.js +559 -0
- package/src/export/index.js +14 -0
- package/src/export/systems/TradingCardSystemFaceted.js +494 -0
- package/src/export/systems/TradingCardSystemHolographic.js +452 -0
- package/src/export/systems/TradingCardSystemQuantum.js +411 -0
- package/src/faceted/FacetedSystem.js +963 -0
- package/src/features/CollectionManager.js +433 -0
- package/src/gallery/CollectionManager.js +240 -0
- package/src/gallery/GallerySystem.js +485 -0
- package/src/geometry/GeometryFactory.js +314 -0
- package/src/geometry/GeometryLibrary.js +72 -0
- package/src/geometry/buffers/BufferBuilder.js +338 -0
- package/src/geometry/buffers/index.js +18 -0
- package/src/geometry/generators/Crystal.js +420 -0
- package/src/geometry/generators/Fractal.js +298 -0
- package/src/geometry/generators/KleinBottle.js +197 -0
- package/src/geometry/generators/Sphere.js +192 -0
- package/src/geometry/generators/Tesseract.js +160 -0
- package/src/geometry/generators/Tetrahedron.js +225 -0
- package/src/geometry/generators/Torus.js +304 -0
- package/src/geometry/generators/Wave.js +341 -0
- package/src/geometry/index.js +142 -0
- package/src/geometry/warp/HypersphereCore.js +211 -0
- package/src/geometry/warp/HypertetraCore.js +386 -0
- package/src/geometry/warp/index.js +57 -0
- package/src/holograms/HolographicVisualizer.js +1073 -0
- package/src/holograms/RealHolographicSystem.js +966 -0
- package/src/holograms/variantRegistry.js +69 -0
- package/src/integrations/FigmaPlugin.js +854 -0
- package/src/integrations/OBSMode.js +754 -0
- package/src/integrations/ThreeJsPackage.js +660 -0
- package/src/integrations/TouchDesignerExport.js +552 -0
- package/src/integrations/frameworks/Vib3React.js +591 -0
- package/src/integrations/frameworks/Vib3Svelte.js +654 -0
- package/src/integrations/frameworks/Vib3Vue.js +628 -0
- package/src/llm/LLMParameterInterface.js +240 -0
- package/src/llm/LLMParameterUI.js +577 -0
- package/src/math/Mat4x4.js +708 -0
- package/src/math/Projection.js +341 -0
- package/src/math/Rotor4D.js +637 -0
- package/src/math/Vec4.js +476 -0
- package/src/math/constants.js +164 -0
- package/src/math/index.js +68 -0
- package/src/math/projections.js +54 -0
- package/src/math/rotations.js +196 -0
- package/src/quantum/QuantumEngine.js +906 -0
- package/src/quantum/QuantumVisualizer.js +1103 -0
- package/src/reactivity/ReactivityConfig.js +499 -0
- package/src/reactivity/ReactivityManager.js +586 -0
- package/src/reactivity/SpatialInputSystem.js +1783 -0
- package/src/reactivity/index.js +93 -0
- package/src/render/CommandBuffer.js +465 -0
- package/src/render/MultiCanvasBridge.js +340 -0
- package/src/render/RenderCommand.js +514 -0
- package/src/render/RenderResourceRegistry.js +523 -0
- package/src/render/RenderState.js +552 -0
- package/src/render/RenderTarget.js +512 -0
- package/src/render/ShaderLoader.js +253 -0
- package/src/render/ShaderProgram.js +599 -0
- package/src/render/UnifiedRenderBridge.js +496 -0
- package/src/render/backends/WebGLBackend.js +1108 -0
- package/src/render/backends/WebGPUBackend.js +1409 -0
- package/src/render/commands/CommandBufferExecutor.js +607 -0
- package/src/render/commands/RenderCommandBuffer.js +661 -0
- package/src/render/commands/index.js +17 -0
- package/src/render/index.js +367 -0
- package/src/scene/Disposable.js +498 -0
- package/src/scene/MemoryPool.js +618 -0
- package/src/scene/Node4D.js +697 -0
- package/src/scene/ResourceManager.js +599 -0
- package/src/scene/Scene4D.js +540 -0
- package/src/scene/index.js +98 -0
- package/src/schemas/error.schema.json +84 -0
- package/src/schemas/extension.schema.json +88 -0
- package/src/schemas/index.js +214 -0
- package/src/schemas/parameters.schema.json +142 -0
- package/src/schemas/tool-pack.schema.json +44 -0
- package/src/schemas/tool-response.schema.json +127 -0
- package/src/shaders/common/fullscreen.vert.glsl +5 -0
- package/src/shaders/common/fullscreen.vert.wgsl +17 -0
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +85 -0
- package/src/shaders/common/rotation4d.wgsl +86 -0
- package/src/shaders/common/uniforms.glsl +44 -0
- package/src/shaders/common/uniforms.wgsl +48 -0
- package/src/shaders/faceted/faceted.frag.glsl +129 -0
- package/src/shaders/faceted/faceted.frag.wgsl +164 -0
- package/src/shaders/holographic/holographic.frag.glsl +406 -0
- package/src/shaders/holographic/holographic.frag.wgsl +185 -0
- package/src/shaders/quantum/quantum.frag.glsl +513 -0
- package/src/shaders/quantum/quantum.frag.wgsl +361 -0
- package/src/testing/ParallelTestFramework.js +519 -0
- package/src/testing/__snapshots__/exportFormats.test.js.snap +24 -0
- package/src/testing/exportFormats.test.js +8 -0
- package/src/testing/projections.test.js +14 -0
- package/src/testing/rotations.test.js +37 -0
- package/src/ui/InteractivityMenu.js +516 -0
- package/src/ui/StatusManager.js +96 -0
- package/src/ui/adaptive/renderers/webgpu/BufferLayout.ts +252 -0
- package/src/ui/adaptive/renderers/webgpu/PolytopeInstanceBuffer.ts +144 -0
- package/src/ui/adaptive/renderers/webgpu/TripleBufferedUniform.ts +170 -0
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +735 -0
- package/src/ui/adaptive/renderers/webgpu/index.ts +112 -0
- package/src/variations/VariationManager.js +431 -0
- package/src/viewer/AudioReactivity.js +505 -0
- package/src/viewer/CardBending.js +481 -0
- package/src/viewer/GalleryUI.js +832 -0
- package/src/viewer/ReactivityManager.js +590 -0
- package/src/viewer/TradingCardExporter.js +600 -0
- package/src/viewer/ViewerPortal.js +374 -0
- package/src/viewer/index.js +12 -0
- package/src/wasm/WasmLoader.js +296 -0
- package/src/wasm/index.js +132 -0
- package/tools/agentic/mcpTools.js +88 -0
- package/tools/cli/agent-cli.js +92 -0
- package/tools/export/formats.js +24 -0
- package/tools/math/rotation-baseline.mjs +64 -0
- package/tools/shader-sync-verify.js +937 -0
- package/tools/telemetry/manifestPipeline.js +141 -0
- package/tools/telemetry/telemetryEvents.js +35 -0
- package/types/adaptive-sdk.d.ts +185 -0
- package/types/advanced/AIPresetGenerator.d.ts +81 -0
- package/types/advanced/MIDIController.d.ts +100 -0
- package/types/advanced/OffscreenWorker.d.ts +82 -0
- package/types/advanced/WebGPUCompute.d.ts +52 -0
- package/types/advanced/WebXRRenderer.d.ts +77 -0
- package/types/advanced/index.d.ts +46 -0
- package/types/core/ErrorReporter.d.ts +50 -0
- package/types/core/VIB3Engine.d.ts +204 -0
- package/types/creative/ColorPresetsSystem.d.ts +91 -0
- package/types/creative/ParameterTimeline.d.ts +74 -0
- package/types/creative/PostProcessingPipeline.d.ts +109 -0
- package/types/creative/TransitionAnimator.d.ts +71 -0
- package/types/creative/index.d.ts +35 -0
- package/types/integrations/FigmaPlugin.d.ts +46 -0
- package/types/integrations/OBSMode.d.ts +74 -0
- package/types/integrations/ThreeJsPackage.d.ts +62 -0
- package/types/integrations/TouchDesignerExport.d.ts +36 -0
- package/types/integrations/Vib3React.d.ts +74 -0
- package/types/integrations/Vib3Svelte.d.ts +63 -0
- package/types/integrations/Vib3Vue.d.ts +55 -0
- package/types/integrations/index.d.ts +52 -0
- package/types/reactivity/SpatialInputSystem.d.ts +173 -0
- package/types/reactivity/index.d.ts +394 -0
- package/types/render/CommandBuffer.d.ts +169 -0
- package/types/render/RenderCommand.d.ts +312 -0
- package/types/render/RenderState.d.ts +279 -0
- package/types/render/RenderTarget.d.ts +254 -0
- package/types/render/ShaderProgram.d.ts +277 -0
- package/types/render/UnifiedRenderBridge.d.ts +143 -0
- package/types/render/WebGLBackend.d.ts +168 -0
- package/types/render/WebGPUBackend.d.ts +186 -0
- package/types/render/index.d.ts +141 -0
|
@@ -0,0 +1,906 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VIB34D Quantum Engine
|
|
3
|
+
* Manages the enhanced quantum system with complex 3D lattice functions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { QuantumHolographicVisualizer } from './QuantumVisualizer.js';
|
|
7
|
+
import { ParameterManager } from '../core/Parameters.js';
|
|
8
|
+
import { GeometryLibrary } from '../geometry/GeometryLibrary.js';
|
|
9
|
+
import { MultiCanvasBridge } from '../render/MultiCanvasBridge.js';
|
|
10
|
+
import { shaderLoader } from '../render/ShaderLoader.js';
|
|
11
|
+
|
|
12
|
+
export class QuantumEngine {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
console.log('🔮 Initializing VIB34D Quantum Engine...');
|
|
15
|
+
|
|
16
|
+
this.visualizers = [];
|
|
17
|
+
this.parameters = new ParameterManager();
|
|
18
|
+
this.isActive = false;
|
|
19
|
+
this.autoStart = options.autoStart ?? true;
|
|
20
|
+
|
|
21
|
+
// Canvas override for single-canvas multi-instance mode
|
|
22
|
+
/** @type {HTMLCanvasElement|null} */
|
|
23
|
+
this.canvasOverride = options.canvas || null;
|
|
24
|
+
|
|
25
|
+
// Bridge rendering state
|
|
26
|
+
/** @type {MultiCanvasBridge|null} */
|
|
27
|
+
this._multiCanvasBridge = null;
|
|
28
|
+
/** @type {'direct'|'bridge'} */
|
|
29
|
+
this._renderMode = 'direct';
|
|
30
|
+
/** @type {number} time accumulator for bridge rendering (ms) */
|
|
31
|
+
this._bridgeTime = 0;
|
|
32
|
+
|
|
33
|
+
// Conditional reactivity: Use built-in only if ReactivityManager not active
|
|
34
|
+
this.useBuiltInReactivity = !window.reactivityManager;
|
|
35
|
+
|
|
36
|
+
// Gesture velocity reactivity system for Quantum
|
|
37
|
+
this.lastMousePosition = { x: 0.5, y: 0.5 };
|
|
38
|
+
this.mouseVelocity = { x: 0, y: 0 };
|
|
39
|
+
this.velocityHistory = [];
|
|
40
|
+
this.maxVelocityHistory = 10;
|
|
41
|
+
|
|
42
|
+
// Base parameter values for gesture modulation
|
|
43
|
+
this.baseHue = 280; // Purple-blue for quantum
|
|
44
|
+
this.baseMorphFactor = 1.0;
|
|
45
|
+
|
|
46
|
+
// Initialize with quantum-enhanced defaults
|
|
47
|
+
this.parameters.setParameter('hue', this.baseHue);
|
|
48
|
+
this.parameters.setParameter('intensity', 0.7); // Higher intensity
|
|
49
|
+
this.parameters.setParameter('saturation', 0.9); // More vivid
|
|
50
|
+
this.parameters.setParameter('gridDensity', 20); // Denser patterns
|
|
51
|
+
this.parameters.setParameter('morphFactor', this.baseMorphFactor);
|
|
52
|
+
|
|
53
|
+
this.init();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the quantum system
|
|
58
|
+
*/
|
|
59
|
+
init() {
|
|
60
|
+
this.createVisualizers();
|
|
61
|
+
this.setupAudioReactivity();
|
|
62
|
+
this.setupGestureVelocityReactivity(); // Additional gesture system
|
|
63
|
+
if (this.autoStart) {
|
|
64
|
+
this.startRenderLoop();
|
|
65
|
+
}
|
|
66
|
+
console.log('✨ Quantum Engine initialized with audio + gesture velocity reactivity');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create quantum visualizers for all 5 layers, or a single content-layer
|
|
71
|
+
* visualizer when canvasOverride is provided.
|
|
72
|
+
*/
|
|
73
|
+
createVisualizers() {
|
|
74
|
+
// Single-canvas override mode: lightweight content-only layer
|
|
75
|
+
if (this.canvasOverride) {
|
|
76
|
+
try {
|
|
77
|
+
const visualizer = new QuantumHolographicVisualizer(
|
|
78
|
+
this.canvasOverride, 'content', 1.0, 0
|
|
79
|
+
);
|
|
80
|
+
if (visualizer.gl) {
|
|
81
|
+
this.visualizers.push(visualizer);
|
|
82
|
+
console.log('🌌 Created quantum single-canvas visualizer (content layer)');
|
|
83
|
+
} else {
|
|
84
|
+
console.warn('⚠️ No WebGL context for quantum canvasOverride');
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn('Failed to create quantum single-canvas visualizer:', error);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const layers = [
|
|
93
|
+
{ id: 'quantum-background-canvas', role: 'background', reactivity: 0.4 },
|
|
94
|
+
{ id: 'quantum-shadow-canvas', role: 'shadow', reactivity: 0.6 },
|
|
95
|
+
{ id: 'quantum-content-canvas', role: 'content', reactivity: 1.0 },
|
|
96
|
+
{ id: 'quantum-highlight-canvas', role: 'highlight', reactivity: 1.3 },
|
|
97
|
+
{ id: 'quantum-accent-canvas', role: 'accent', reactivity: 1.6 }
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
layers.forEach(layer => {
|
|
101
|
+
try {
|
|
102
|
+
// Canvas elements should already exist in HTML
|
|
103
|
+
const canvas = document.getElementById(layer.id);
|
|
104
|
+
if (!canvas) {
|
|
105
|
+
console.warn(`⚠️ Canvas ${layer.id} not found in DOM - skipping`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const visualizer = new QuantumHolographicVisualizer(layer.id, layer.role, layer.reactivity, 0);
|
|
110
|
+
if (visualizer.gl) {
|
|
111
|
+
this.visualizers.push(visualizer);
|
|
112
|
+
console.log(`🌌 Created quantum layer: ${layer.role}`);
|
|
113
|
+
} else {
|
|
114
|
+
console.warn(`⚠️ No WebGL context for quantum layer ${layer.id}`);
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn(`Failed to create quantum layer ${layer.id}:`, error);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
console.log(`✅ Created ${this.visualizers.length} quantum visualizers with enhanced effects`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Initialize the Quantum system through UnifiedRenderBridge / MultiCanvasBridge.
|
|
126
|
+
* This wires all 5 layers through the bridge for WebGL/WebGPU abstraction.
|
|
127
|
+
* Falls back to direct WebGL if bridge initialization fails.
|
|
128
|
+
*
|
|
129
|
+
* @param {object} [options]
|
|
130
|
+
* @param {boolean} [options.preferWebGPU=true] - Try WebGPU first, fall back to WebGL
|
|
131
|
+
* @param {boolean} [options.debug=false]
|
|
132
|
+
* @returns {Promise<boolean>} True if bridge mode activated
|
|
133
|
+
*/
|
|
134
|
+
async initWithBridge(options = {}) {
|
|
135
|
+
try {
|
|
136
|
+
const bridge = await this.createMultiCanvasBridge(options);
|
|
137
|
+
if (bridge && bridge.initialized) {
|
|
138
|
+
this._renderMode = 'bridge';
|
|
139
|
+
this._bridgeTime = 0;
|
|
140
|
+
console.log(`Quantum System initialized via ${bridge.backendType} bridge (${bridge.layerCount} layers)`);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
console.warn('Quantum bridge init returned no bridge, staying in direct mode');
|
|
144
|
+
return false;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.error('Quantum bridge init failed, staying in direct mode:', e);
|
|
147
|
+
this._renderMode = 'direct';
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Create a MultiCanvasBridge for WebGPU rendering.
|
|
154
|
+
* Returns a configured bridge with quantum shaders compiled on all layers.
|
|
155
|
+
*
|
|
156
|
+
* @param {object} [options]
|
|
157
|
+
* @param {boolean} [options.preferWebGPU=true]
|
|
158
|
+
* @returns {Promise<MultiCanvasBridge|null>}
|
|
159
|
+
*/
|
|
160
|
+
async createMultiCanvasBridge(options = {}) {
|
|
161
|
+
const canvasMap = {};
|
|
162
|
+
const layerIds = {
|
|
163
|
+
background: 'quantum-background-canvas',
|
|
164
|
+
shadow: 'quantum-shadow-canvas',
|
|
165
|
+
content: 'quantum-content-canvas',
|
|
166
|
+
highlight: 'quantum-highlight-canvas',
|
|
167
|
+
accent: 'quantum-accent-canvas'
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
for (const [role, id] of Object.entries(layerIds)) {
|
|
171
|
+
const el = document.getElementById(id);
|
|
172
|
+
if (el) canvasMap[role] = el;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (Object.keys(canvasMap).length === 0) return null;
|
|
176
|
+
|
|
177
|
+
const bridge = new MultiCanvasBridge();
|
|
178
|
+
await bridge.initialize({ canvases: canvasMap, preferWebGPU: options.preferWebGPU !== false });
|
|
179
|
+
|
|
180
|
+
// Load external shader files, fall back to inline sources if unavailable
|
|
181
|
+
let sources = {
|
|
182
|
+
glslVertex: 'attribute vec2 a_position;\nvoid main() { gl_Position = vec4(a_position, 0.0, 1.0); }',
|
|
183
|
+
glslFragment: null,
|
|
184
|
+
wgslFragment: null
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const external = await shaderLoader.loadShaderPair('quantum', 'quantum/quantum.frag');
|
|
189
|
+
if (external.glslVertex) sources.glslVertex = external.glslVertex;
|
|
190
|
+
if (external.glslFragment) sources.glslFragment = external.glslFragment;
|
|
191
|
+
if (external.wgslFragment) sources.wgslFragment = external.wgslFragment;
|
|
192
|
+
} catch (loadErr) {
|
|
193
|
+
console.warn('Quantum external shader load failed, using inline fallback');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (sources.glslFragment || sources.wgslFragment) {
|
|
197
|
+
const result = bridge.compileShaderAll('quantum', sources);
|
|
198
|
+
if (result.failed.length > 0) {
|
|
199
|
+
console.warn(`Quantum shader compilation failed on layers: ${result.failed.join(', ')}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
this._multiCanvasBridge = bridge;
|
|
204
|
+
return bridge;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Build the VIB3+ standard uniform object from current parameters.
|
|
209
|
+
* Used by bridge rendering to send uniforms to external shader programs.
|
|
210
|
+
* @private
|
|
211
|
+
* @returns {object}
|
|
212
|
+
*/
|
|
213
|
+
_buildSharedUniforms() {
|
|
214
|
+
const params = this.parameters.getAllParameters();
|
|
215
|
+
const audioData = window.audioReactive || { bass: 0, mid: 0, high: 0 };
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
u_time: this._bridgeTime,
|
|
219
|
+
u_resolution: null, // Set per-layer by MultiCanvasBridge
|
|
220
|
+
u_geometry: params.geometry || 0,
|
|
221
|
+
u_rot4dXY: params.rot4dXY || 0,
|
|
222
|
+
u_rot4dXZ: params.rot4dXZ || 0,
|
|
223
|
+
u_rot4dYZ: params.rot4dYZ || 0,
|
|
224
|
+
u_rot4dXW: params.rot4dXW || 0,
|
|
225
|
+
u_rot4dYW: params.rot4dYW || 0,
|
|
226
|
+
u_rot4dZW: params.rot4dZW || 0,
|
|
227
|
+
u_dimension: params.dimension || 3.5,
|
|
228
|
+
u_gridDensity: params.gridDensity || 20,
|
|
229
|
+
u_morphFactor: params.morphFactor || 1.0,
|
|
230
|
+
u_chaos: params.chaos || 0.2,
|
|
231
|
+
u_speed: params.speed || 1.0,
|
|
232
|
+
u_hue: params.hue || 280,
|
|
233
|
+
u_intensity: params.intensity || 0.7,
|
|
234
|
+
u_saturation: params.saturation || 0.9,
|
|
235
|
+
u_mouseIntensity: 0,
|
|
236
|
+
u_clickIntensity: this.clickFlashIntensity || 0,
|
|
237
|
+
u_bass: audioData.bass || 0,
|
|
238
|
+
u_mid: audioData.mid || 0,
|
|
239
|
+
u_high: audioData.high || 0
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Render a single frame via the MultiCanvasBridge.
|
|
245
|
+
* Sets shared uniforms and renders all 5 layers with the external quantum shader.
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
_renderBridgeFrame() {
|
|
249
|
+
if (!this._multiCanvasBridge || !this._multiCanvasBridge.initialized) return;
|
|
250
|
+
|
|
251
|
+
this._bridgeTime += 16; // ~60fps increment
|
|
252
|
+
|
|
253
|
+
const uniforms = this._buildSharedUniforms();
|
|
254
|
+
|
|
255
|
+
// Set canvas resolution per layer before rendering
|
|
256
|
+
for (const layerName of this._multiCanvasBridge.layerNames) {
|
|
257
|
+
const bridge = this._multiCanvasBridge.getBridge(layerName);
|
|
258
|
+
if (bridge && bridge.canvas) {
|
|
259
|
+
this._multiCanvasBridge.setLayerUniforms(layerName, {
|
|
260
|
+
u_resolution: [bridge.canvas.width, bridge.canvas.height]
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this._multiCanvasBridge.setSharedUniforms(uniforms);
|
|
266
|
+
this._multiCanvasBridge.renderAll('quantum', { clearColor: [0, 0, 0, 0] });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Set system active/inactive
|
|
271
|
+
*/
|
|
272
|
+
setActive(active) {
|
|
273
|
+
this.isActive = active;
|
|
274
|
+
|
|
275
|
+
if (active) {
|
|
276
|
+
// Show quantum layers (skip in single-canvas override mode)
|
|
277
|
+
if (!this.canvasOverride) {
|
|
278
|
+
const quantumLayers = document.getElementById('quantumLayers');
|
|
279
|
+
if (quantumLayers) {
|
|
280
|
+
quantumLayers.style.display = 'block';
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Enable audio if global audio is enabled
|
|
285
|
+
if (window.audioEnabled && !this.audioEnabled) {
|
|
286
|
+
this.enableAudio();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
console.log('🔮 Quantum System ACTIVATED - Audio frequency reactivity mode');
|
|
290
|
+
} else {
|
|
291
|
+
// Hide quantum layers (skip in single-canvas override mode)
|
|
292
|
+
if (!this.canvasOverride) {
|
|
293
|
+
const quantumLayers = document.getElementById('quantumLayers');
|
|
294
|
+
if (quantumLayers) {
|
|
295
|
+
quantumLayers.style.display = 'none';
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
console.log('🔮 Quantum System DEACTIVATED');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Method to be called when global audio is toggled
|
|
303
|
+
toggleAudio(enabled) {
|
|
304
|
+
if (enabled && this.isActive && !this.audioEnabled) {
|
|
305
|
+
this.enableAudio();
|
|
306
|
+
} else if (!enabled && this.audioEnabled) {
|
|
307
|
+
this.audioEnabled = false;
|
|
308
|
+
// Stop audio stream tracks to release microphone
|
|
309
|
+
if (this._audioStream) {
|
|
310
|
+
this._audioStream.getTracks().forEach(track => track.stop());
|
|
311
|
+
this._audioStream = null;
|
|
312
|
+
}
|
|
313
|
+
if (this.audioContext) {
|
|
314
|
+
this.audioContext.close().catch(() => {});
|
|
315
|
+
this.audioContext = null;
|
|
316
|
+
}
|
|
317
|
+
this.analyser = null;
|
|
318
|
+
this.frequencyData = null;
|
|
319
|
+
console.log('Quantum audio reactivity disabled');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Setup audio frequency reactivity for Quantum system
|
|
325
|
+
*/
|
|
326
|
+
setupAudioReactivity() {
|
|
327
|
+
console.log('🌌 Setting up Quantum audio frequency reactivity');
|
|
328
|
+
// Audio setup will be triggered when audio is enabled
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Setup enhanced multi-parameter reactivity for Quantum system
|
|
333
|
+
*/
|
|
334
|
+
setupGestureVelocityReactivity() {
|
|
335
|
+
if (!this.useBuiltInReactivity) {
|
|
336
|
+
console.log('🌌 Quantum built-in reactivity DISABLED - ReactivityManager active');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (this.canvasOverride) {
|
|
340
|
+
console.log('🌌 Quantum gesture reactivity skipped (single-canvas override mode)');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
console.log('🌌 Setting up Quantum: velocity + click + scroll + multi-parameter reactivity');
|
|
345
|
+
|
|
346
|
+
// Enhanced state for smooth effects
|
|
347
|
+
this.clickFlashIntensity = 0;
|
|
348
|
+
this.scrollMorph = 1.0; // Base morph factor
|
|
349
|
+
this.velocitySmoothing = 0.8; // Smoother velocity transitions
|
|
350
|
+
|
|
351
|
+
const quantumCanvases = [
|
|
352
|
+
'quantum-background-canvas', 'quantum-shadow-canvas', 'quantum-content-canvas',
|
|
353
|
+
'quantum-highlight-canvas', 'quantum-accent-canvas'
|
|
354
|
+
];
|
|
355
|
+
|
|
356
|
+
quantumCanvases.forEach(canvasId => {
|
|
357
|
+
const canvas = document.getElementById(canvasId);
|
|
358
|
+
if (!canvas) return;
|
|
359
|
+
|
|
360
|
+
// Mouse movement -> smooth velocity + multiple parameters
|
|
361
|
+
canvas.addEventListener('mousemove', (e) => {
|
|
362
|
+
if (!this.isActive) return;
|
|
363
|
+
|
|
364
|
+
const rect = canvas.getBoundingClientRect();
|
|
365
|
+
const mouseX = (e.clientX - rect.left) / rect.width;
|
|
366
|
+
const mouseY = (e.clientY - rect.top) / rect.height;
|
|
367
|
+
|
|
368
|
+
this.updateEnhancedQuantumParameters(mouseX, mouseY);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Touch movement -> same enhanced parameters
|
|
372
|
+
canvas.addEventListener('touchmove', (e) => {
|
|
373
|
+
if (!this.isActive) return;
|
|
374
|
+
e.preventDefault();
|
|
375
|
+
|
|
376
|
+
if (e.touches.length > 0) {
|
|
377
|
+
const touch = e.touches[0];
|
|
378
|
+
const rect = canvas.getBoundingClientRect();
|
|
379
|
+
const touchX = (touch.clientX - rect.left) / rect.width;
|
|
380
|
+
const touchY = (touch.clientY - rect.top) / rect.height;
|
|
381
|
+
|
|
382
|
+
this.updateEnhancedQuantumParameters(touchX, touchY);
|
|
383
|
+
}
|
|
384
|
+
}, { passive: false });
|
|
385
|
+
|
|
386
|
+
// Click -> quantum flash effect
|
|
387
|
+
canvas.addEventListener('click', (e) => {
|
|
388
|
+
if (!this.isActive) return;
|
|
389
|
+
this.triggerQuantumClick();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Touch end -> quantum flash effect
|
|
393
|
+
canvas.addEventListener('touchend', (e) => {
|
|
394
|
+
if (!this.isActive) return;
|
|
395
|
+
this.triggerQuantumClick();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Wheel -> quantum morphing scroll effect
|
|
399
|
+
canvas.addEventListener('wheel', (e) => {
|
|
400
|
+
if (!this.isActive) return;
|
|
401
|
+
e.preventDefault();
|
|
402
|
+
this.updateQuantumScroll(e.deltaY);
|
|
403
|
+
}, { passive: false });
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Start smooth animation loops
|
|
407
|
+
this.startQuantumEffectLoops();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
updateEnhancedQuantumParameters(x, y) {
|
|
411
|
+
// Calculate velocity from position change (smoother)
|
|
412
|
+
const deltaX = x - this.lastMousePosition.x;
|
|
413
|
+
const deltaY = y - this.lastMousePosition.y;
|
|
414
|
+
const velocity = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
415
|
+
|
|
416
|
+
// Smooth velocity history (reduced from 10 to 5 for responsiveness)
|
|
417
|
+
this.velocityHistory.push(velocity);
|
|
418
|
+
if (this.velocityHistory.length > 5) {
|
|
419
|
+
this.velocityHistory.shift();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Calculate smoother average velocity
|
|
423
|
+
const avgVelocity = this.velocityHistory.reduce((sum, v) => sum + v, 0) / this.velocityHistory.length;
|
|
424
|
+
|
|
425
|
+
// EXPERIMENTAL QUANTUM MOUSE MAPPING: X-axis rotation + hemispheric colors
|
|
426
|
+
|
|
427
|
+
// X-AXIS: Direct rotation mapping (smooth 4D rotation)
|
|
428
|
+
// Map mouse X (0-1) to rotation angle (-π to π for full rotation range)
|
|
429
|
+
const rotationAngle = (x - 0.5) * Math.PI * 2; // -2π to 2π range
|
|
430
|
+
const rot4dXW = rotationAngle * 0.5; // Smooth XW rotation
|
|
431
|
+
const rot4dYW = rotationAngle * 0.3; // Complementary YW rotation
|
|
432
|
+
const rot4dZW = rotationAngle * 0.2; // Subtle ZW rotation
|
|
433
|
+
|
|
434
|
+
// Y-AXIS: Maintains current behavior (density/complexity)
|
|
435
|
+
const gridDensity = 10 + (y * 90); // Y position: 10-100 range (unchanged)
|
|
436
|
+
|
|
437
|
+
// HEMISPHERIC COLOR MAPPING: Distance from center affects color zones
|
|
438
|
+
const centerX = 0.5;
|
|
439
|
+
const centerY = 0.5;
|
|
440
|
+
const distanceFromCenter = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
|
|
441
|
+
const normalizedDistance = Math.min(1.0, distanceFromCenter * Math.sqrt(2)); // 0-1 range
|
|
442
|
+
|
|
443
|
+
// Color hemisphere mapping
|
|
444
|
+
const leftHemisphere = x < 0.5;
|
|
445
|
+
const topHemisphere = y < 0.5;
|
|
446
|
+
|
|
447
|
+
let baseHue;
|
|
448
|
+
if (leftHemisphere && topHemisphere) {
|
|
449
|
+
baseHue = 240; // Blue quadrant
|
|
450
|
+
} else if (!leftHemisphere && topHemisphere) {
|
|
451
|
+
baseHue = 300; // Purple quadrant
|
|
452
|
+
} else if (leftHemisphere && !topHemisphere) {
|
|
453
|
+
baseHue = 180; // Cyan quadrant
|
|
454
|
+
} else {
|
|
455
|
+
baseHue = 320; // Magenta quadrant
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Distance affects hue variation (center = pure color, edges = shifted)
|
|
459
|
+
const hueVariation = normalizedDistance * 60; // 0-60 degree shift
|
|
460
|
+
const hue = (baseHue + hueVariation) % 360;
|
|
461
|
+
|
|
462
|
+
// Other parameters influenced by movement
|
|
463
|
+
const chaos = Math.min(1.0, avgVelocity * 30); // Velocity affects chaos
|
|
464
|
+
const speed = 0.5 + Math.min(2.5, avgVelocity * 15); // Movement speed
|
|
465
|
+
const intensity = 0.3 + (normalizedDistance * 0.7); // Distance affects brightness
|
|
466
|
+
|
|
467
|
+
// Update all parameters for rich visual feedback
|
|
468
|
+
if (window.updateParameter) {
|
|
469
|
+
// Rotation parameters (new experimental mapping)
|
|
470
|
+
window.updateParameter('rot4dXW', rot4dXW.toFixed(3));
|
|
471
|
+
window.updateParameter('rot4dYW', rot4dYW.toFixed(3));
|
|
472
|
+
window.updateParameter('rot4dZW', rot4dZW.toFixed(3));
|
|
473
|
+
|
|
474
|
+
// Traditional parameters
|
|
475
|
+
window.updateParameter('chaos', chaos.toFixed(2));
|
|
476
|
+
window.updateParameter('speed', speed.toFixed(2));
|
|
477
|
+
window.updateParameter('gridDensity', Math.round(gridDensity));
|
|
478
|
+
window.updateParameter('intensity', intensity.toFixed(2));
|
|
479
|
+
window.updateParameter('hue', Math.round(hue));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Update last position
|
|
483
|
+
this.lastMousePosition.x = x;
|
|
484
|
+
this.lastMousePosition.y = y;
|
|
485
|
+
|
|
486
|
+
console.log(`🌌 Quantum EXPERIMENTAL: X=${x.toFixed(2)}→Rot=${rotationAngle.toFixed(2)}, Y=${y.toFixed(2)}→Density=${Math.round(gridDensity)}, Dist=${normalizedDistance.toFixed(2)}→Hue=${Math.round(hue)}, Hemisphere=${leftHemisphere ? 'L' : 'R'}${topHemisphere ? 'T' : 'B'}`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
triggerQuantumClick() {
|
|
490
|
+
// DRAMATIC QUANTUM ENERGY BURST (multi-parameter)
|
|
491
|
+
this.clickFlashIntensity = 1.0;
|
|
492
|
+
|
|
493
|
+
// Additional dramatic quantum effects that decay back
|
|
494
|
+
this.quantumChaosBlast = 0.7; // Chaos energy burst
|
|
495
|
+
this.quantumSpeedWave = 2.0; // Speed wave effect
|
|
496
|
+
this.quantumHueShift = 60; // Color explosion shift
|
|
497
|
+
|
|
498
|
+
console.log('💥 Quantum energy burst: flash + chaos + speed + hue explosion');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
updateQuantumScroll(deltaY) {
|
|
502
|
+
// Scroll affects morph factor smoothly
|
|
503
|
+
const scrollSpeed = 0.02;
|
|
504
|
+
const scrollDirection = deltaY > 0 ? 1 : -1;
|
|
505
|
+
|
|
506
|
+
this.scrollMorph += scrollDirection * scrollSpeed;
|
|
507
|
+
this.scrollMorph = Math.max(0.2, Math.min(2.0, this.scrollMorph)); // Clamp 0.2-2.0
|
|
508
|
+
|
|
509
|
+
// Update morph factor
|
|
510
|
+
if (window.updateParameter) {
|
|
511
|
+
window.updateParameter('morphFactor', this.scrollMorph.toFixed(2));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
console.log(`🌀 Quantum scroll morph: ${this.scrollMorph.toFixed(2)}`);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
startQuantumEffectLoops() {
|
|
518
|
+
const quantumEffects = () => {
|
|
519
|
+
let hasActiveEffects = false;
|
|
520
|
+
|
|
521
|
+
// QUANTUM FLASH EFFECT (saturation + morph)
|
|
522
|
+
if (this.clickFlashIntensity > 0.01) {
|
|
523
|
+
hasActiveEffects = true;
|
|
524
|
+
|
|
525
|
+
// Flash affects saturation - quantum shimmer effect
|
|
526
|
+
const flashSaturation = 0.9 + (this.clickFlashIntensity * 0.1); // 0.9-1.0 boost
|
|
527
|
+
const flashMorph = this.scrollMorph + (this.clickFlashIntensity * 0.5); // Morph boost
|
|
528
|
+
|
|
529
|
+
if (window.updateParameter) {
|
|
530
|
+
window.updateParameter('saturation', flashSaturation.toFixed(2));
|
|
531
|
+
window.updateParameter('morphFactor', flashMorph.toFixed(2));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Smooth decay
|
|
535
|
+
this.clickFlashIntensity *= 0.91;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// DRAMATIC CHAOS BLAST EFFECT (fluid decay)
|
|
539
|
+
if (this.quantumChaosBlast > 0.01) {
|
|
540
|
+
hasActiveEffects = true;
|
|
541
|
+
|
|
542
|
+
const baseChaos = 0.3; // Quantum default chaos
|
|
543
|
+
const currentChaos = baseChaos + this.quantumChaosBlast;
|
|
544
|
+
|
|
545
|
+
if (window.updateParameter) {
|
|
546
|
+
window.updateParameter('chaos', Math.min(1.0, currentChaos).toFixed(2));
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Smooth decay
|
|
550
|
+
this.quantumChaosBlast *= 0.88; // Slightly faster than faceted for quantum energy feel
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// DRAMATIC SPEED WAVE EFFECT (fluid decay)
|
|
554
|
+
if (this.quantumSpeedWave > 0.01) {
|
|
555
|
+
hasActiveEffects = true;
|
|
556
|
+
|
|
557
|
+
const baseSpeed = 1.0; // Quantum default speed
|
|
558
|
+
const currentSpeed = baseSpeed + this.quantumSpeedWave;
|
|
559
|
+
|
|
560
|
+
if (window.updateParameter) {
|
|
561
|
+
window.updateParameter('speed', Math.min(3.0, currentSpeed).toFixed(2));
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Smooth wave decay
|
|
565
|
+
this.quantumSpeedWave *= 0.89;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// QUANTUM HUE EXPLOSION EFFECT (fluid decay)
|
|
569
|
+
if (this.quantumHueShift > 1) {
|
|
570
|
+
hasActiveEffects = true;
|
|
571
|
+
|
|
572
|
+
const baseHue = 280; // Quantum purple-blue
|
|
573
|
+
const currentHue = (baseHue + this.quantumHueShift) % 360;
|
|
574
|
+
|
|
575
|
+
if (window.updateParameter) {
|
|
576
|
+
window.updateParameter('hue', Math.round(currentHue));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Smooth color return
|
|
580
|
+
this.quantumHueShift *= 0.90;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (this.isActive) {
|
|
584
|
+
requestAnimationFrame(quantumEffects);
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
quantumEffects();
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async enableAudio() {
|
|
592
|
+
if (this.audioEnabled) return;
|
|
593
|
+
|
|
594
|
+
try {
|
|
595
|
+
// Request microphone access
|
|
596
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
597
|
+
|
|
598
|
+
// Create audio context and analyser
|
|
599
|
+
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
600
|
+
this.analyser = this.audioContext.createAnalyser();
|
|
601
|
+
|
|
602
|
+
// Configure analyser for frequency analysis
|
|
603
|
+
this.analyser.fftSize = 256;
|
|
604
|
+
this.analyser.smoothingTimeConstant = 0.8;
|
|
605
|
+
this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount);
|
|
606
|
+
|
|
607
|
+
// Store stream reference for cleanup
|
|
608
|
+
this._audioStream = stream;
|
|
609
|
+
|
|
610
|
+
// Connect microphone to analyser
|
|
611
|
+
const source = this.audioContext.createMediaStreamSource(stream);
|
|
612
|
+
source.connect(this.analyser);
|
|
613
|
+
|
|
614
|
+
this.audioEnabled = true;
|
|
615
|
+
console.log('Quantum audio reactivity enabled');
|
|
616
|
+
|
|
617
|
+
} catch (error) {
|
|
618
|
+
console.error('❌ Failed to enable Quantum audio:', error);
|
|
619
|
+
this.audioEnabled = false;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Update parameter across all quantum visualizers with enhanced integration
|
|
625
|
+
*/
|
|
626
|
+
updateParameter(param, value) {
|
|
627
|
+
// Update internal parameter manager
|
|
628
|
+
this.parameters.setParameter(param, value);
|
|
629
|
+
|
|
630
|
+
// CRITICAL: Apply to all quantum visualizers with immediate render
|
|
631
|
+
this.visualizers.forEach(visualizer => {
|
|
632
|
+
if (visualizer.updateParameters) {
|
|
633
|
+
const params = {};
|
|
634
|
+
params[param] = value;
|
|
635
|
+
visualizer.updateParameters(params);
|
|
636
|
+
} else {
|
|
637
|
+
// Fallback: direct parameter update with manual render
|
|
638
|
+
if (visualizer.params) {
|
|
639
|
+
visualizer.params[param] = value;
|
|
640
|
+
if (visualizer.render) {
|
|
641
|
+
visualizer.render();
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
console.log(`🔮 Updated quantum ${param}: ${value}`);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Update multiple parameters
|
|
652
|
+
*/
|
|
653
|
+
updateParameters(params) {
|
|
654
|
+
Object.keys(params).forEach(param => {
|
|
655
|
+
this.updateParameter(param, params[param]);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Update mouse interaction
|
|
661
|
+
*/
|
|
662
|
+
updateInteraction(x, y, intensity) {
|
|
663
|
+
this.visualizers.forEach(visualizer => {
|
|
664
|
+
if (visualizer.updateInteraction) {
|
|
665
|
+
visualizer.updateInteraction(x, y, intensity);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Get current parameters for saving/export
|
|
672
|
+
*/
|
|
673
|
+
getParameters() {
|
|
674
|
+
return this.parameters.getAllParameters();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Set parameters from loaded/imported data
|
|
679
|
+
*/
|
|
680
|
+
setParameters(params) {
|
|
681
|
+
Object.keys(params).forEach(param => {
|
|
682
|
+
this.parameters.setParameter(param, params[param]);
|
|
683
|
+
});
|
|
684
|
+
this.updateParameters(params);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Start the render loop
|
|
689
|
+
*/
|
|
690
|
+
startRenderLoop() {
|
|
691
|
+
if (window.mobileDebug) {
|
|
692
|
+
window.mobileDebug.log(`🎬 Quantum Engine: Starting render loop with ${this.visualizers?.length} visualizers, isActive=${this.isActive}`);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const render = () => {
|
|
696
|
+
this.renderFrame();
|
|
697
|
+
|
|
698
|
+
requestAnimationFrame(render);
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
render();
|
|
702
|
+
console.log('🎬 Quantum render loop started');
|
|
703
|
+
|
|
704
|
+
if (window.mobileDebug) {
|
|
705
|
+
window.mobileDebug.log(`✅ Quantum Engine: Render loop started, will render when isActive=true`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Render a single frame.
|
|
711
|
+
* Dispatches to bridge mode or direct mode based on current _renderMode.
|
|
712
|
+
*/
|
|
713
|
+
renderFrame() {
|
|
714
|
+
if (this.isActive) {
|
|
715
|
+
if (this._renderMode === 'bridge') {
|
|
716
|
+
this._renderBridgeFrame();
|
|
717
|
+
} else {
|
|
718
|
+
this._renderDirectFrame();
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Mobile debug: Log render activity periodically
|
|
722
|
+
if (window.mobileDebug && !this._renderActivityLogged) {
|
|
723
|
+
window.mobileDebug.log(`🎬 Quantum Engine: Actively rendering (${this._renderMode} mode)`);
|
|
724
|
+
this._renderActivityLogged = true;
|
|
725
|
+
}
|
|
726
|
+
} else if (window.mobileDebug && !this._inactiveWarningLogged) {
|
|
727
|
+
window.mobileDebug.log(`⚠️ Quantum Engine: Not rendering because isActive=false`);
|
|
728
|
+
this._inactiveWarningLogged = true;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Render a single frame using direct WebGL visualizers (original path).
|
|
734
|
+
* @private
|
|
735
|
+
*/
|
|
736
|
+
_renderDirectFrame() {
|
|
737
|
+
const currentParams = this.parameters.getAllParameters();
|
|
738
|
+
|
|
739
|
+
this.visualizers.forEach(visualizer => {
|
|
740
|
+
if (visualizer.updateParameters && visualizer.render) {
|
|
741
|
+
visualizer.updateParameters(currentParams);
|
|
742
|
+
visualizer.render();
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Update audio reactivity (for universal reactivity system)
|
|
749
|
+
*/
|
|
750
|
+
// Audio reactivity now handled directly in visualizer render loops
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Update click effects (for universal reactivity system)
|
|
754
|
+
*/
|
|
755
|
+
updateClick(intensity) {
|
|
756
|
+
this.visualizers.forEach(visualizer => {
|
|
757
|
+
if (visualizer.triggerClick) {
|
|
758
|
+
visualizer.triggerClick(0.5, 0.5, intensity); // Click at center with intensity
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Update scroll effects (for universal reactivity system)
|
|
765
|
+
*/
|
|
766
|
+
updateScroll(velocity) {
|
|
767
|
+
this.visualizers.forEach(visualizer => {
|
|
768
|
+
if (visualizer.updateScroll) {
|
|
769
|
+
visualizer.updateScroll(velocity);
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Clean up resources
|
|
776
|
+
*/
|
|
777
|
+
destroy() {
|
|
778
|
+
this.isActive = false;
|
|
779
|
+
|
|
780
|
+
// Disconnect from universal reactivity
|
|
781
|
+
if (window.universalReactivity) {
|
|
782
|
+
window.universalReactivity.disconnectSystem('quantum');
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Stop audio stream tracks to release microphone
|
|
786
|
+
if (this._audioStream) {
|
|
787
|
+
this._audioStream.getTracks().forEach(track => track.stop());
|
|
788
|
+
this._audioStream = null;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Close audio context
|
|
792
|
+
if (this.audioContext) {
|
|
793
|
+
this.audioContext.close().catch(() => {});
|
|
794
|
+
this.audioContext = null;
|
|
795
|
+
}
|
|
796
|
+
this.audioEnabled = false;
|
|
797
|
+
this.analyser = null;
|
|
798
|
+
this.frequencyData = null;
|
|
799
|
+
|
|
800
|
+
// Dispose bridge if active
|
|
801
|
+
if (this._multiCanvasBridge) {
|
|
802
|
+
this._multiCanvasBridge.dispose();
|
|
803
|
+
this._multiCanvasBridge = null;
|
|
804
|
+
}
|
|
805
|
+
this._renderMode = 'direct';
|
|
806
|
+
|
|
807
|
+
// Destroy all visualizers
|
|
808
|
+
this.visualizers.forEach(visualizer => {
|
|
809
|
+
if (visualizer.destroy) {
|
|
810
|
+
visualizer.destroy();
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
this.visualizers = [];
|
|
814
|
+
console.log('Quantum Engine destroyed');
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// ============================================
|
|
818
|
+
// RendererContract Compliance Methods
|
|
819
|
+
// ============================================
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Initialize or re-initialize with optional canvas override (RendererContract.init).
|
|
823
|
+
* Accepts the same context shape as FacetedSystem for consistency:
|
|
824
|
+
* { canvas: HTMLCanvasElement } or { canvasId: 'my-canvas' }
|
|
825
|
+
*
|
|
826
|
+
* @param {Object} [context]
|
|
827
|
+
* @param {HTMLCanvasElement} [context.canvas] - Canvas element override
|
|
828
|
+
* @param {string} [context.canvasId] - Canvas ID to look up
|
|
829
|
+
* @param {boolean} [context.preferWebGPU] - Try WebGPU bridge
|
|
830
|
+
* @returns {Promise<boolean>|boolean} Success status
|
|
831
|
+
*/
|
|
832
|
+
initWithCanvas(context = {}) {
|
|
833
|
+
const canvasEl = context.canvas ||
|
|
834
|
+
(context.canvasId ? document.getElementById(context.canvasId) : null);
|
|
835
|
+
|
|
836
|
+
if (canvasEl) {
|
|
837
|
+
this.canvasOverride = canvasEl;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Tear down any existing visualizers before re-init
|
|
841
|
+
this.visualizers.forEach(v => v.destroy && v.destroy());
|
|
842
|
+
this.visualizers = [];
|
|
843
|
+
|
|
844
|
+
this.createVisualizers();
|
|
845
|
+
|
|
846
|
+
if (!this.autoStart) return this.visualizers.length > 0;
|
|
847
|
+
this.startRenderLoop();
|
|
848
|
+
return this.visualizers.length > 0;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Handle canvas resize (RendererContract.resize)
|
|
853
|
+
* @param {number} width - New width in pixels
|
|
854
|
+
* @param {number} height - New height in pixels
|
|
855
|
+
* @param {number} [pixelRatio=1] - Device pixel ratio
|
|
856
|
+
*/
|
|
857
|
+
resize(width, height, pixelRatio = 1) {
|
|
858
|
+
if (this._renderMode === 'bridge' && this._multiCanvasBridge) {
|
|
859
|
+
this._multiCanvasBridge.resizeAll(width, height, pixelRatio);
|
|
860
|
+
} else {
|
|
861
|
+
this.visualizers.forEach(visualizer => {
|
|
862
|
+
if (visualizer.canvas && visualizer.gl) {
|
|
863
|
+
visualizer.canvas.width = width * pixelRatio;
|
|
864
|
+
visualizer.canvas.height = height * pixelRatio;
|
|
865
|
+
visualizer.canvas.style.width = `${width}px`;
|
|
866
|
+
visualizer.canvas.style.height = `${height}px`;
|
|
867
|
+
visualizer.gl.viewport(0, 0, visualizer.canvas.width, visualizer.canvas.height);
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
console.log(`🔮 Quantum resized to ${width}x${height} @${pixelRatio}x`);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Render a single frame (RendererContract.render)
|
|
876
|
+
* @param {Object} [frameState] - Frame state with time, params, audio
|
|
877
|
+
*/
|
|
878
|
+
render(frameState = {}) {
|
|
879
|
+
// Apply frameState parameters if provided
|
|
880
|
+
if (frameState.params) {
|
|
881
|
+
this.updateParameters(frameState.params);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Delegate to existing renderFrame
|
|
885
|
+
this.renderFrame();
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Get the current rendering backend type.
|
|
890
|
+
* @returns {'direct-webgl'|string}
|
|
891
|
+
*/
|
|
892
|
+
getBackendType() {
|
|
893
|
+
if (this._renderMode === 'bridge' && this._multiCanvasBridge) {
|
|
894
|
+
return this._multiCanvasBridge.backendType || 'bridge';
|
|
895
|
+
}
|
|
896
|
+
return 'direct-webgl';
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Clean up all resources (RendererContract.dispose)
|
|
901
|
+
* Alias for destroy() for contract compliance
|
|
902
|
+
*/
|
|
903
|
+
dispose() {
|
|
904
|
+
this.destroy();
|
|
905
|
+
}
|
|
906
|
+
}
|