@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,1103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VIB34D Quantum Holographic Visualizer
|
|
3
|
+
* Enhanced WebGL renderer with complex 3D lattice functions and holographic effects
|
|
4
|
+
* This is the superior system with volumetric lighting, particles, and RGB glitch effects
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { GeometryLibrary } from '../geometry/GeometryLibrary.js';
|
|
8
|
+
|
|
9
|
+
export class QuantumHolographicVisualizer {
|
|
10
|
+
constructor(canvasIdOrElement, role, reactivity, variant) {
|
|
11
|
+
this.canvas = (canvasIdOrElement instanceof HTMLCanvasElement)
|
|
12
|
+
? canvasIdOrElement
|
|
13
|
+
: document.getElementById(canvasIdOrElement);
|
|
14
|
+
this.role = role;
|
|
15
|
+
this.reactivity = reactivity;
|
|
16
|
+
this.variant = variant;
|
|
17
|
+
|
|
18
|
+
// CRITICAL FIX: Define contextOptions as instance property to match SmartCanvasPool
|
|
19
|
+
this.contextOptions = {
|
|
20
|
+
alpha: true,
|
|
21
|
+
depth: true,
|
|
22
|
+
stencil: false,
|
|
23
|
+
antialias: false, // Disable antialiasing on mobile for performance
|
|
24
|
+
premultipliedAlpha: true,
|
|
25
|
+
preserveDrawingBuffer: false,
|
|
26
|
+
powerPreference: 'high-performance',
|
|
27
|
+
failIfMajorPerformanceCaveat: false // Don't fail on mobile
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// CRITICAL FIX: Don't create context here - let SmartCanvasPool handle it
|
|
31
|
+
// Try WebGL2 first (better mobile support), then WebGL1
|
|
32
|
+
this.gl = this.canvas.getContext('webgl2', this.contextOptions) ||
|
|
33
|
+
this.canvas.getContext('webgl', this.contextOptions) ||
|
|
34
|
+
this.canvas.getContext('experimental-webgl', this.contextOptions);
|
|
35
|
+
|
|
36
|
+
if (!this.gl) {
|
|
37
|
+
console.error(`WebGL not supported for ${canvasId}`);
|
|
38
|
+
if (window.mobileDebug) {
|
|
39
|
+
window.mobileDebug.log(`❌ ${canvasId}: WebGL context creation failed`);
|
|
40
|
+
}
|
|
41
|
+
// Show user-friendly error instead of white screen
|
|
42
|
+
this.showWebGLError();
|
|
43
|
+
return;
|
|
44
|
+
} else {
|
|
45
|
+
if (window.mobileDebug) {
|
|
46
|
+
const version = this.gl.getParameter(this.gl.VERSION);
|
|
47
|
+
window.mobileDebug.log(`✅ ${canvasId}: WebGL context created - ${version}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.mouseX = 0.5;
|
|
52
|
+
this.mouseY = 0.5;
|
|
53
|
+
this.mouseIntensity = 0.0;
|
|
54
|
+
this.clickIntensity = 0.0;
|
|
55
|
+
this.startTime = Date.now();
|
|
56
|
+
this._contextLost = false;
|
|
57
|
+
|
|
58
|
+
// WebGL context loss/restore handlers
|
|
59
|
+
this._onContextLost = (e) => {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
this._contextLost = true;
|
|
62
|
+
console.warn(`WebGL context lost for ${canvasId}`);
|
|
63
|
+
};
|
|
64
|
+
this._onContextRestored = () => {
|
|
65
|
+
console.log(`WebGL context restored for ${canvasId}`);
|
|
66
|
+
this._contextLost = false;
|
|
67
|
+
try {
|
|
68
|
+
this.init();
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(`Failed to reinit after context restore for ${canvasId}:`, err);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
this.canvas.addEventListener('webglcontextlost', this._onContextLost);
|
|
74
|
+
this.canvas.addEventListener('webglcontextrestored', this._onContextRestored);
|
|
75
|
+
|
|
76
|
+
// Default parameters
|
|
77
|
+
this.params = {
|
|
78
|
+
geometry: 0,
|
|
79
|
+
gridDensity: 15,
|
|
80
|
+
morphFactor: 1.0,
|
|
81
|
+
chaos: 0.2,
|
|
82
|
+
speed: 1.0,
|
|
83
|
+
hue: 200,
|
|
84
|
+
intensity: 0.5,
|
|
85
|
+
saturation: 0.8,
|
|
86
|
+
dimension: 3.5,
|
|
87
|
+
rot4dXY: 0.0,
|
|
88
|
+
rot4dXZ: 0.0,
|
|
89
|
+
rot4dYZ: 0.0,
|
|
90
|
+
rot4dXW: 0.0,
|
|
91
|
+
rot4dYW: 0.0,
|
|
92
|
+
rot4dZW: 0.0
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
this.init();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* CRITICAL FIX: Ensure canvas is properly sized before creating WebGL context
|
|
100
|
+
*/
|
|
101
|
+
async ensureCanvasSizedThenInitWebGL() {
|
|
102
|
+
// Set proper canvas dimensions for mobile - with fallbacks
|
|
103
|
+
let rect = this.canvas.getBoundingClientRect();
|
|
104
|
+
const devicePixelRatio = Math.min(window.devicePixelRatio || 1, 2); // Cap at 2x for performance
|
|
105
|
+
|
|
106
|
+
// If canvas has no dimensions, wait for layout or use viewport
|
|
107
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
108
|
+
// Wait for layout with promise
|
|
109
|
+
await new Promise(resolve => {
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
rect = this.canvas.getBoundingClientRect();
|
|
112
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
113
|
+
// Use viewport dimensions as fallback
|
|
114
|
+
const viewWidth = window.innerWidth;
|
|
115
|
+
const viewHeight = window.innerHeight;
|
|
116
|
+
this.canvas.width = viewWidth * devicePixelRatio;
|
|
117
|
+
this.canvas.height = viewHeight * devicePixelRatio;
|
|
118
|
+
|
|
119
|
+
if (window.mobileDebug) {
|
|
120
|
+
window.mobileDebug.log(`📐 Quantum Canvas ${this.canvas.id}: Using viewport fallback ${this.canvas.width}x${this.canvas.height}`);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
this.canvas.width = rect.width * devicePixelRatio;
|
|
124
|
+
this.canvas.height = rect.height * devicePixelRatio;
|
|
125
|
+
|
|
126
|
+
if (window.mobileDebug) {
|
|
127
|
+
window.mobileDebug.log(`📐 Quantum Canvas ${this.canvas.id}: Layout ready ${this.canvas.width}x${this.canvas.height}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
resolve();
|
|
131
|
+
}, 100);
|
|
132
|
+
});
|
|
133
|
+
} else {
|
|
134
|
+
this.canvas.width = rect.width * devicePixelRatio;
|
|
135
|
+
this.canvas.height = rect.height * devicePixelRatio;
|
|
136
|
+
|
|
137
|
+
if (window.mobileDebug) {
|
|
138
|
+
window.mobileDebug.log(`📐 Quantum Canvas ${this.canvas.id}: ${this.canvas.width}x${this.canvas.height} (DPR: ${devicePixelRatio})`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// NOW create WebGL context with properly sized canvas
|
|
143
|
+
this.createWebGLContext();
|
|
144
|
+
|
|
145
|
+
// Initialize rendering pipeline
|
|
146
|
+
if (this.gl) {
|
|
147
|
+
this.init();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create WebGL context after canvas is properly sized
|
|
153
|
+
*/
|
|
154
|
+
createWebGLContext() {
|
|
155
|
+
// CRITICAL FIX: Check if context already exists from SmartCanvasPool
|
|
156
|
+
let existingContext = this.canvas.getContext('webgl2') ||
|
|
157
|
+
this.canvas.getContext('webgl') ||
|
|
158
|
+
this.canvas.getContext('experimental-webgl');
|
|
159
|
+
|
|
160
|
+
if (existingContext && !existingContext.isContextLost()) {
|
|
161
|
+
console.log(`🔄 Reusing existing WebGL context for ${this.canvas.id}`);
|
|
162
|
+
this.gl = existingContext;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Try WebGL2 first (better mobile support), then WebGL1
|
|
167
|
+
this.gl = this.canvas.getContext('webgl2', this.contextOptions) ||
|
|
168
|
+
this.canvas.getContext('webgl', this.contextOptions) ||
|
|
169
|
+
this.canvas.getContext('experimental-webgl', this.contextOptions);
|
|
170
|
+
|
|
171
|
+
if (!this.gl) {
|
|
172
|
+
console.error(`WebGL not supported for ${this.canvas.id}`);
|
|
173
|
+
if (window.mobileDebug) {
|
|
174
|
+
window.mobileDebug.log(`❌ Quantum ${this.canvas.id}: WebGL context creation failed (size: ${this.canvas.width}x${this.canvas.height})`);
|
|
175
|
+
}
|
|
176
|
+
// Show user-friendly error instead of white screen
|
|
177
|
+
this.showWebGLError();
|
|
178
|
+
return;
|
|
179
|
+
} else {
|
|
180
|
+
if (window.mobileDebug) {
|
|
181
|
+
const version = this.gl.getParameter(this.gl.VERSION);
|
|
182
|
+
window.mobileDebug.log(`✅ Quantum ${this.canvas.id}: WebGL context created - ${version} (size: ${this.canvas.width}x${this.canvas.height})`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Initialize WebGL rendering pipeline
|
|
189
|
+
*/
|
|
190
|
+
init() {
|
|
191
|
+
this.initShaders();
|
|
192
|
+
this.initBuffers();
|
|
193
|
+
this.resize();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Reinitialize WebGL context and resources after SmartCanvasPool context recreation
|
|
198
|
+
*/
|
|
199
|
+
reinitializeContext() {
|
|
200
|
+
console.log(`🔄 Reinitializing WebGL context for ${this.canvas.id}`);
|
|
201
|
+
|
|
202
|
+
// CRITICAL FIX: Clear old WebGL references first
|
|
203
|
+
this.program = null;
|
|
204
|
+
this.buffer = null;
|
|
205
|
+
this.uniforms = null;
|
|
206
|
+
this.gl = null;
|
|
207
|
+
|
|
208
|
+
// CRITICAL FIX: Don't create new context - SmartCanvasPool already did this
|
|
209
|
+
// Just get the existing context that SmartCanvasPool created
|
|
210
|
+
this.gl = this.canvas.getContext('webgl2') ||
|
|
211
|
+
this.canvas.getContext('webgl') ||
|
|
212
|
+
this.canvas.getContext('experimental-webgl');
|
|
213
|
+
|
|
214
|
+
if (!this.gl) {
|
|
215
|
+
console.error(`❌ No WebGL context available for ${this.canvas.id} - SmartCanvasPool should have created one`);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (this.gl.isContextLost()) {
|
|
220
|
+
console.error(`❌ WebGL context is lost for ${this.canvas.id}`);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Reinitialize all WebGL resources with the existing context
|
|
225
|
+
try {
|
|
226
|
+
this.initShaders();
|
|
227
|
+
this.initBuffers();
|
|
228
|
+
this.resize();
|
|
229
|
+
|
|
230
|
+
console.log(`✅ WebGL context reinitialized for ${this.canvas.id}`);
|
|
231
|
+
return true;
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error(`❌ Failed to reinitialize WebGL resources for ${this.canvas.id}:`, error);
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Initialize shaders with complex 3D lattice functions and holographic effects
|
|
240
|
+
*/
|
|
241
|
+
initShaders() {
|
|
242
|
+
const vertexShaderSource = `attribute vec2 a_position;
|
|
243
|
+
void main() {
|
|
244
|
+
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
245
|
+
}`;
|
|
246
|
+
|
|
247
|
+
// Mobile-friendly precision - try highp, fallback to mediump
|
|
248
|
+
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
249
|
+
const precision = isMobile ? 'mediump' : 'highp';
|
|
250
|
+
|
|
251
|
+
const fragmentShaderSource = `
|
|
252
|
+
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
|
253
|
+
precision highp float;
|
|
254
|
+
#else
|
|
255
|
+
precision mediump float;
|
|
256
|
+
#endif
|
|
257
|
+
|
|
258
|
+
uniform vec2 u_resolution;
|
|
259
|
+
uniform float u_time;
|
|
260
|
+
uniform vec2 u_mouse;
|
|
261
|
+
uniform float u_geometry;
|
|
262
|
+
uniform float u_gridDensity;
|
|
263
|
+
uniform float u_morphFactor;
|
|
264
|
+
uniform float u_chaos;
|
|
265
|
+
uniform float u_speed;
|
|
266
|
+
uniform float u_hue;
|
|
267
|
+
uniform float u_intensity;
|
|
268
|
+
uniform float u_saturation;
|
|
269
|
+
uniform float u_dimension;
|
|
270
|
+
uniform float u_rot4dXY;
|
|
271
|
+
uniform float u_rot4dXZ;
|
|
272
|
+
uniform float u_rot4dYZ;
|
|
273
|
+
uniform float u_rot4dXW;
|
|
274
|
+
uniform float u_rot4dYW;
|
|
275
|
+
uniform float u_rot4dZW;
|
|
276
|
+
uniform float u_mouseIntensity;
|
|
277
|
+
uniform float u_clickIntensity;
|
|
278
|
+
uniform float u_roleIntensity;
|
|
279
|
+
|
|
280
|
+
// 6D rotation matrices - 3D space rotations (XY, XZ, YZ)
|
|
281
|
+
mat4 rotateXY(float theta) {
|
|
282
|
+
float c = cos(theta);
|
|
283
|
+
float s = sin(theta);
|
|
284
|
+
return mat4(c, -s, 0.0, 0.0, s, c, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
mat4 rotateXZ(float theta) {
|
|
288
|
+
float c = cos(theta);
|
|
289
|
+
float s = sin(theta);
|
|
290
|
+
return mat4(c, 0.0, s, 0.0, 0.0, 1.0, 0.0, 0.0, -s, 0.0, c, 0.0, 0.0, 0.0, 0.0, 1.0);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
mat4 rotateYZ(float theta) {
|
|
294
|
+
float c = cos(theta);
|
|
295
|
+
float s = sin(theta);
|
|
296
|
+
return mat4(1.0, 0.0, 0.0, 0.0, 0.0, c, -s, 0.0, 0.0, s, c, 0.0, 0.0, 0.0, 0.0, 1.0);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 4D hyperspace rotations (XW, YW, ZW)
|
|
300
|
+
mat4 rotateXW(float theta) {
|
|
301
|
+
float c = cos(theta);
|
|
302
|
+
float s = sin(theta);
|
|
303
|
+
return mat4(c, 0.0, 0.0, -s, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, s, 0.0, 0.0, c);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
mat4 rotateYW(float theta) {
|
|
307
|
+
float c = cos(theta);
|
|
308
|
+
float s = sin(theta);
|
|
309
|
+
return mat4(1.0, 0.0, 0.0, 0.0, 0.0, c, 0.0, -s, 0.0, 0.0, 1.0, 0.0, 0.0, s, 0.0, c);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
mat4 rotateZW(float theta) {
|
|
313
|
+
float c = cos(theta);
|
|
314
|
+
float s = sin(theta);
|
|
315
|
+
return mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, c, -s, 0.0, 0.0, s, c);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
vec3 project4Dto3D(vec4 p) {
|
|
319
|
+
float w = 2.5 / (2.5 + p.w);
|
|
320
|
+
return vec3(p.x * w, p.y * w, p.z * w);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ========================================
|
|
324
|
+
// POLYTOPE CORE WARP FUNCTIONS (24 Geometries)
|
|
325
|
+
// ========================================
|
|
326
|
+
vec3 warpHypersphereCore(vec3 p, int geometryIndex, vec2 mouseDelta) {
|
|
327
|
+
float radius = length(p);
|
|
328
|
+
float morphBlend = clamp(u_morphFactor * 0.6 + (u_dimension - 3.0) * 0.25, 0.0, 2.0);
|
|
329
|
+
float w = sin(radius * (1.3 + float(geometryIndex) * 0.12) + u_time * 0.0008 * u_speed);
|
|
330
|
+
w *= (0.4 + morphBlend * 0.45);
|
|
331
|
+
|
|
332
|
+
vec4 p4d = vec4(p * (1.0 + morphBlend * 0.2), w);
|
|
333
|
+
p4d = rotateXY(u_rot4dXY) * p4d;
|
|
334
|
+
p4d = rotateXZ(u_rot4dXZ) * p4d;
|
|
335
|
+
p4d = rotateYZ(u_rot4dYZ) * p4d;
|
|
336
|
+
p4d = rotateXW(u_rot4dXW) * p4d;
|
|
337
|
+
p4d = rotateYW(u_rot4dYW) * p4d;
|
|
338
|
+
p4d = rotateZW(u_rot4dZW) * p4d;
|
|
339
|
+
|
|
340
|
+
vec3 projected = project4Dto3D(p4d);
|
|
341
|
+
return mix(p, projected, clamp(0.45 + morphBlend * 0.35, 0.0, 1.0));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
vec3 warpHypertetraCore(vec3 p, int geometryIndex, vec2 mouseDelta) {
|
|
345
|
+
vec3 c1 = normalize(vec3(1.0, 1.0, 1.0));
|
|
346
|
+
vec3 c2 = normalize(vec3(-1.0, -1.0, 1.0));
|
|
347
|
+
vec3 c3 = normalize(vec3(-1.0, 1.0, -1.0));
|
|
348
|
+
vec3 c4 = normalize(vec3(1.0, -1.0, -1.0));
|
|
349
|
+
|
|
350
|
+
float morphBlend = clamp(u_morphFactor * 0.8 + (u_dimension - 3.0) * 0.2, 0.0, 2.0);
|
|
351
|
+
float basisMix = dot(p, c1) * 0.14 + dot(p, c2) * 0.1 + dot(p, c3) * 0.08;
|
|
352
|
+
float w = sin(basisMix * 5.5 + u_time * 0.0009 * u_speed);
|
|
353
|
+
w *= cos(dot(p, c4) * 4.2 - u_time * 0.0007 * u_speed);
|
|
354
|
+
w *= (0.5 + morphBlend * 0.4);
|
|
355
|
+
|
|
356
|
+
vec3 offset = vec3(dot(p, c1), dot(p, c2), dot(p, c3)) * 0.1 * morphBlend;
|
|
357
|
+
vec4 p4d = vec4(p + offset, w);
|
|
358
|
+
p4d = rotateXY(u_rot4dXY) * p4d;
|
|
359
|
+
p4d = rotateXZ(u_rot4dXZ) * p4d;
|
|
360
|
+
p4d = rotateYZ(u_rot4dYZ) * p4d;
|
|
361
|
+
p4d = rotateXW(u_rot4dXW) * p4d;
|
|
362
|
+
p4d = rotateYW(u_rot4dYW) * p4d;
|
|
363
|
+
p4d = rotateZW(u_rot4dZW) * p4d;
|
|
364
|
+
|
|
365
|
+
vec3 projected = project4Dto3D(p4d);
|
|
366
|
+
|
|
367
|
+
float planeInfluence = min(min(abs(dot(p, c1)), abs(dot(p, c2))), min(abs(dot(p, c3)), abs(dot(p, c4))));
|
|
368
|
+
vec3 blended = mix(p, projected, clamp(0.45 + morphBlend * 0.35, 0.0, 1.0));
|
|
369
|
+
return mix(blended, blended * (1.0 - planeInfluence * 0.55), 0.2 + morphBlend * 0.2);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
vec3 applyCoreWarp(vec3 p, float geometryType, vec2 mouseDelta) {
|
|
373
|
+
float totalBase = 8.0;
|
|
374
|
+
float coreFloat = floor(geometryType / totalBase);
|
|
375
|
+
int coreIndex = int(clamp(coreFloat, 0.0, 2.0));
|
|
376
|
+
float baseGeomFloat = mod(geometryType, totalBase);
|
|
377
|
+
int geometryIndex = int(clamp(floor(baseGeomFloat + 0.5), 0.0, totalBase - 1.0));
|
|
378
|
+
|
|
379
|
+
if (coreIndex == 1) {
|
|
380
|
+
return warpHypersphereCore(p, geometryIndex, mouseDelta);
|
|
381
|
+
}
|
|
382
|
+
if (coreIndex == 2) {
|
|
383
|
+
return warpHypertetraCore(p, geometryIndex, mouseDelta);
|
|
384
|
+
}
|
|
385
|
+
return p;
|
|
386
|
+
}
|
|
387
|
+
// ========================================
|
|
388
|
+
|
|
389
|
+
// Complex 3D Lattice Functions - Superior Quantum Shaders
|
|
390
|
+
float tetrahedronLattice(vec3 p, float gridSize) {
|
|
391
|
+
vec3 q = fract(p * gridSize) - 0.5;
|
|
392
|
+
float d1 = length(q);
|
|
393
|
+
float d2 = length(q - vec3(0.4, 0.0, 0.0));
|
|
394
|
+
float d3 = length(q - vec3(0.0, 0.4, 0.0));
|
|
395
|
+
float d4 = length(q - vec3(0.0, 0.0, 0.4));
|
|
396
|
+
float vertices = 1.0 - smoothstep(0.0, 0.04, min(min(d1, d2), min(d3, d4)));
|
|
397
|
+
float edges = 0.0;
|
|
398
|
+
edges = max(edges, 1.0 - smoothstep(0.0, 0.02, abs(length(q.xy) - 0.2)));
|
|
399
|
+
edges = max(edges, 1.0 - smoothstep(0.0, 0.02, abs(length(q.yz) - 0.2)));
|
|
400
|
+
edges = max(edges, 1.0 - smoothstep(0.0, 0.02, abs(length(q.xz) - 0.2)));
|
|
401
|
+
return max(vertices, edges * 0.5);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
float hypercubeLattice(vec3 p, float gridSize) {
|
|
405
|
+
vec3 grid = fract(p * gridSize);
|
|
406
|
+
vec3 edges = min(grid, 1.0 - grid);
|
|
407
|
+
float minEdge = min(min(edges.x, edges.y), edges.z);
|
|
408
|
+
float lattice = 1.0 - smoothstep(0.0, 0.03, minEdge);
|
|
409
|
+
|
|
410
|
+
vec3 centers = abs(grid - 0.5);
|
|
411
|
+
float maxCenter = max(max(centers.x, centers.y), centers.z);
|
|
412
|
+
float vertices = 1.0 - smoothstep(0.45, 0.5, maxCenter);
|
|
413
|
+
|
|
414
|
+
return max(lattice * 0.7, vertices);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
float sphereLattice(vec3 p, float gridSize) {
|
|
418
|
+
vec3 cell = fract(p * gridSize) - 0.5;
|
|
419
|
+
float sphere = 1.0 - smoothstep(0.15, 0.25, length(cell));
|
|
420
|
+
|
|
421
|
+
float rings = 0.0;
|
|
422
|
+
float ringRadius = length(cell.xy);
|
|
423
|
+
rings = max(rings, 1.0 - smoothstep(0.0, 0.02, abs(ringRadius - 0.3)));
|
|
424
|
+
rings = max(rings, 1.0 - smoothstep(0.0, 0.02, abs(ringRadius - 0.2)));
|
|
425
|
+
|
|
426
|
+
return max(sphere, rings * 0.6);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
float torusLattice(vec3 p, float gridSize) {
|
|
430
|
+
vec3 cell = fract(p * gridSize) - 0.5;
|
|
431
|
+
float majorRadius = 0.3;
|
|
432
|
+
float minorRadius = 0.1;
|
|
433
|
+
|
|
434
|
+
float toroidalDist = length(vec2(length(cell.xy) - majorRadius, cell.z));
|
|
435
|
+
float torus = 1.0 - smoothstep(minorRadius - 0.02, minorRadius + 0.02, toroidalDist);
|
|
436
|
+
|
|
437
|
+
float rings = 0.0;
|
|
438
|
+
float angle = atan(cell.y, cell.x);
|
|
439
|
+
rings = sin(angle * 8.0) * 0.02;
|
|
440
|
+
|
|
441
|
+
return max(torus, 0.0) + rings;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
float kleinLattice(vec3 p, float gridSize) {
|
|
445
|
+
vec3 cell = fract(p * gridSize) - 0.5;
|
|
446
|
+
float u = atan(cell.y, cell.x) / 3.14159 + 1.0;
|
|
447
|
+
float v = cell.z + 0.5;
|
|
448
|
+
|
|
449
|
+
float x = (2.0 + cos(u * 0.5)) * cos(u);
|
|
450
|
+
float y = (2.0 + cos(u * 0.5)) * sin(u);
|
|
451
|
+
float z = sin(u * 0.5) + v;
|
|
452
|
+
|
|
453
|
+
vec3 kleinPoint = vec3(x, y, z) * 0.1;
|
|
454
|
+
float dist = length(cell - kleinPoint);
|
|
455
|
+
|
|
456
|
+
return 1.0 - smoothstep(0.1, 0.15, dist);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
float fractalLattice(vec3 p, float gridSize) {
|
|
460
|
+
vec3 cell = fract(p * gridSize);
|
|
461
|
+
cell = abs(cell * 2.0 - 1.0);
|
|
462
|
+
|
|
463
|
+
float dist = length(max(abs(cell) - 0.3, 0.0));
|
|
464
|
+
|
|
465
|
+
// Recursive subdivision
|
|
466
|
+
for(int i = 0; i < 3; i++) {
|
|
467
|
+
cell = abs(cell * 2.0 - 1.0);
|
|
468
|
+
float subdist = length(max(abs(cell) - 0.3, 0.0)) / pow(2.0, float(i + 1));
|
|
469
|
+
dist = min(dist, subdist);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return 1.0 - smoothstep(0.0, 0.05, dist);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
float waveLattice(vec3 p, float gridSize) {
|
|
476
|
+
float time = u_time * 0.001 * u_speed;
|
|
477
|
+
vec3 cell = fract(p * gridSize) - 0.5;
|
|
478
|
+
|
|
479
|
+
float wave1 = sin(p.x * gridSize * 2.0 + time * 2.0);
|
|
480
|
+
float wave2 = sin(p.y * gridSize * 1.8 + time * 1.5);
|
|
481
|
+
float wave3 = sin(p.z * gridSize * 2.2 + time * 1.8);
|
|
482
|
+
|
|
483
|
+
float interference = (wave1 + wave2 + wave3) / 3.0;
|
|
484
|
+
float amplitude = 1.0 - length(cell) * 2.0;
|
|
485
|
+
|
|
486
|
+
return max(0.0, interference * amplitude);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
float crystalLattice(vec3 p, float gridSize) {
|
|
490
|
+
vec3 cell = fract(p * gridSize) - 0.5;
|
|
491
|
+
|
|
492
|
+
// Octahedral crystal structure
|
|
493
|
+
float crystal = max(max(abs(cell.x) + abs(cell.y), abs(cell.y) + abs(cell.z)), abs(cell.x) + abs(cell.z));
|
|
494
|
+
crystal = 1.0 - smoothstep(0.3, 0.4, crystal);
|
|
495
|
+
|
|
496
|
+
// Add crystalline faces
|
|
497
|
+
float faces = 0.0;
|
|
498
|
+
faces = max(faces, 1.0 - smoothstep(0.0, 0.02, abs(abs(cell.x) - 0.35)));
|
|
499
|
+
faces = max(faces, 1.0 - smoothstep(0.0, 0.02, abs(abs(cell.y) - 0.35)));
|
|
500
|
+
faces = max(faces, 1.0 - smoothstep(0.0, 0.02, abs(abs(cell.z) - 0.35)));
|
|
501
|
+
|
|
502
|
+
return max(crystal, faces * 0.5);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Enhanced geometry function with holographic effects (24 GEOMETRIES)
|
|
506
|
+
float geometryFunction(vec4 p) {
|
|
507
|
+
// Decode geometry: base = geometry % 8 (supports 24 geometries)
|
|
508
|
+
float totalBase = 8.0;
|
|
509
|
+
float baseGeomFloat = mod(u_geometry, totalBase);
|
|
510
|
+
int geomType = int(clamp(floor(baseGeomFloat + 0.5), 0.0, totalBase - 1.0));
|
|
511
|
+
|
|
512
|
+
// Project to 3D and apply polytope warp
|
|
513
|
+
vec3 p3d = project4Dto3D(p);
|
|
514
|
+
vec3 warped = applyCoreWarp(p3d, u_geometry, vec2(0.0, 0.0));
|
|
515
|
+
float gridSize = u_gridDensity * 0.08;
|
|
516
|
+
|
|
517
|
+
if (geomType == 0) {
|
|
518
|
+
return tetrahedronLattice(warped, gridSize) * u_morphFactor;
|
|
519
|
+
}
|
|
520
|
+
else if (geomType == 1) {
|
|
521
|
+
return hypercubeLattice(warped, gridSize) * u_morphFactor;
|
|
522
|
+
}
|
|
523
|
+
else if (geomType == 2) {
|
|
524
|
+
return sphereLattice(warped, gridSize) * u_morphFactor;
|
|
525
|
+
}
|
|
526
|
+
else if (geomType == 3) {
|
|
527
|
+
return torusLattice(warped, gridSize) * u_morphFactor;
|
|
528
|
+
}
|
|
529
|
+
else if (geomType == 4) {
|
|
530
|
+
return kleinLattice(warped, gridSize) * u_morphFactor;
|
|
531
|
+
}
|
|
532
|
+
else if (geomType == 5) {
|
|
533
|
+
return fractalLattice(warped, gridSize) * u_morphFactor;
|
|
534
|
+
}
|
|
535
|
+
else if (geomType == 6) {
|
|
536
|
+
return waveLattice(warped, gridSize) * u_morphFactor;
|
|
537
|
+
}
|
|
538
|
+
else if (geomType == 7) {
|
|
539
|
+
return crystalLattice(warped, gridSize) * u_morphFactor;
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
return hypercubeLattice(warped, gridSize) * u_morphFactor;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// HSL to RGB conversion for proper color control
|
|
547
|
+
vec3 hsl2rgb(float h, float s, float l) {
|
|
548
|
+
float c = (1.0 - abs(2.0 * l - 1.0)) * s;
|
|
549
|
+
float hp = h * 6.0; // h is 0-1
|
|
550
|
+
float x = c * (1.0 - abs(mod(hp, 2.0) - 1.0));
|
|
551
|
+
float m = l - c * 0.5;
|
|
552
|
+
vec3 rgb;
|
|
553
|
+
if (hp < 1.0) rgb = vec3(c, x, 0.0);
|
|
554
|
+
else if (hp < 2.0) rgb = vec3(x, c, 0.0);
|
|
555
|
+
else if (hp < 3.0) rgb = vec3(0.0, c, x);
|
|
556
|
+
else if (hp < 4.0) rgb = vec3(0.0, x, c);
|
|
557
|
+
else if (hp < 5.0) rgb = vec3(x, 0.0, c);
|
|
558
|
+
else rgb = vec3(c, 0.0, x);
|
|
559
|
+
return rgb + m;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// LAYER-BY-LAYER COLOR SYSTEM with user hue/saturation control
|
|
563
|
+
// Each layer gets a hue offset from the user-controlled base hue
|
|
564
|
+
vec3 getLayerColorPalette(int layerIndex, float t) {
|
|
565
|
+
float baseHue = u_hue; // 0-1 from JavaScript (user hue / 360)
|
|
566
|
+
float sat = u_saturation;
|
|
567
|
+
|
|
568
|
+
// Per-layer hue offsets for visual variety
|
|
569
|
+
float hueOffset = 0.0;
|
|
570
|
+
float lightness = 0.5;
|
|
571
|
+
|
|
572
|
+
if (layerIndex == 0) {
|
|
573
|
+
// BACKGROUND: Darkened, shifted hue
|
|
574
|
+
hueOffset = 0.0;
|
|
575
|
+
lightness = 0.15;
|
|
576
|
+
sat *= 0.7;
|
|
577
|
+
}
|
|
578
|
+
else if (layerIndex == 1) {
|
|
579
|
+
// SHADOW: Complementary offset, medium-dark
|
|
580
|
+
hueOffset = 0.33;
|
|
581
|
+
lightness = 0.3;
|
|
582
|
+
sat *= 0.9;
|
|
583
|
+
}
|
|
584
|
+
else if (layerIndex == 2) {
|
|
585
|
+
// CONTENT: Primary hue, bright
|
|
586
|
+
hueOffset = 0.0;
|
|
587
|
+
lightness = 0.55;
|
|
588
|
+
}
|
|
589
|
+
else if (layerIndex == 3) {
|
|
590
|
+
// HIGHLIGHT: Analogous offset, bright
|
|
591
|
+
hueOffset = 0.15;
|
|
592
|
+
lightness = 0.6;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
// ACCENT: Triadic offset, vivid
|
|
596
|
+
hueOffset = 0.67;
|
|
597
|
+
lightness = 0.5;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Animate hue gently over time and geometry value
|
|
601
|
+
float animatedHue = fract(baseHue + hueOffset + sin(t * 3.0) * 0.05);
|
|
602
|
+
return hsl2rgb(animatedHue, sat, lightness);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Extreme RGB separation and distortion for each layer
|
|
606
|
+
vec3 extremeRGBSeparation(vec3 baseColor, vec2 uv, float intensity, int layerIndex) {
|
|
607
|
+
vec2 offset = vec2(0.01, 0.005) * intensity;
|
|
608
|
+
|
|
609
|
+
// Different separation patterns per layer
|
|
610
|
+
if (layerIndex == 0) {
|
|
611
|
+
// Background: Minimal separation, smooth
|
|
612
|
+
return baseColor + vec3(
|
|
613
|
+
sin(uv.x * 10.0 + u_time * 0.001) * 0.02,
|
|
614
|
+
cos(uv.y * 8.0 + u_time * 0.0015) * 0.02,
|
|
615
|
+
sin(uv.x * uv.y * 6.0 + u_time * 0.0008) * 0.02
|
|
616
|
+
) * intensity;
|
|
617
|
+
}
|
|
618
|
+
else if (layerIndex == 1) {
|
|
619
|
+
// Shadow: Heavy vertical separation
|
|
620
|
+
float r = baseColor.r + sin(uv.y * 50.0 + u_time * 0.003) * intensity * 0.15;
|
|
621
|
+
float g = baseColor.g + sin((uv.y + 0.1) * 45.0 + u_time * 0.0025) * intensity * 0.12;
|
|
622
|
+
float b = baseColor.b + sin((uv.y - 0.1) * 55.0 + u_time * 0.0035) * intensity * 0.18;
|
|
623
|
+
return vec3(r, g, b);
|
|
624
|
+
}
|
|
625
|
+
else if (layerIndex == 2) {
|
|
626
|
+
// Content: Explosive radial separation
|
|
627
|
+
float dist = length(uv);
|
|
628
|
+
float angle = atan(uv.y, uv.x);
|
|
629
|
+
float r = baseColor.r + sin(dist * 30.0 + angle * 10.0 + u_time * 0.004) * intensity * 0.2;
|
|
630
|
+
float g = baseColor.g + cos(dist * 25.0 + angle * 8.0 + u_time * 0.0035) * intensity * 0.18;
|
|
631
|
+
float b = baseColor.b + sin(dist * 35.0 + angle * 12.0 + u_time * 0.0045) * intensity * 0.22;
|
|
632
|
+
return vec3(r, g, b);
|
|
633
|
+
}
|
|
634
|
+
else if (layerIndex == 3) {
|
|
635
|
+
// Highlight: Lightning-like separation
|
|
636
|
+
float lightning = sin(uv.x * 80.0 + u_time * 0.008) * cos(uv.y * 60.0 + u_time * 0.006);
|
|
637
|
+
float r = baseColor.r + lightning * intensity * 0.25;
|
|
638
|
+
float g = baseColor.g + sin(lightning * 40.0 + u_time * 0.005) * intensity * 0.2;
|
|
639
|
+
float b = baseColor.b + cos(lightning * 30.0 + u_time * 0.007) * intensity * 0.3;
|
|
640
|
+
return vec3(r, g, b);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
// Accent: Chaotic multi-directional separation
|
|
644
|
+
float chaos1 = sin(uv.x * 100.0 + uv.y * 80.0 + u_time * 0.01);
|
|
645
|
+
float chaos2 = cos(uv.x * 70.0 - uv.y * 90.0 + u_time * 0.008);
|
|
646
|
+
float chaos3 = sin(uv.x * uv.y * 150.0 + u_time * 0.012);
|
|
647
|
+
return baseColor + vec3(chaos1, chaos2, chaos3) * intensity * 0.3;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
void main() {
|
|
652
|
+
vec2 uv = (gl_FragCoord.xy - u_resolution.xy * 0.5) / min(u_resolution.x, u_resolution.y);
|
|
653
|
+
|
|
654
|
+
// Enhanced 4D position with holographic depth
|
|
655
|
+
float timeSpeed = u_time * 0.0001 * u_speed;
|
|
656
|
+
vec4 pos = vec4(uv * 3.0, sin(timeSpeed * 3.0), cos(timeSpeed * 2.0));
|
|
657
|
+
pos.xy += (u_mouse - 0.5) * u_mouseIntensity * 2.0;
|
|
658
|
+
|
|
659
|
+
// Apply 6D rotations - 3D space rotations first, then 4D hyperspace
|
|
660
|
+
pos = rotateXY(u_rot4dXY) * pos;
|
|
661
|
+
pos = rotateXZ(u_rot4dXZ) * pos;
|
|
662
|
+
pos = rotateYZ(u_rot4dYZ) * pos;
|
|
663
|
+
pos = rotateXW(u_rot4dXW) * pos;
|
|
664
|
+
pos = rotateYW(u_rot4dYW) * pos;
|
|
665
|
+
pos = rotateZW(u_rot4dZW) * pos;
|
|
666
|
+
|
|
667
|
+
// Calculate enhanced geometry value
|
|
668
|
+
float value = geometryFunction(pos);
|
|
669
|
+
|
|
670
|
+
// Enhanced chaos with holographic effects
|
|
671
|
+
float noise = sin(pos.x * 7.0) * cos(pos.y * 11.0) * sin(pos.z * 13.0);
|
|
672
|
+
value += noise * u_chaos;
|
|
673
|
+
|
|
674
|
+
// Enhanced intensity calculation with holographic glow
|
|
675
|
+
float geometryIntensity = 1.0 - clamp(abs(value * 0.8), 0.0, 1.0);
|
|
676
|
+
geometryIntensity = pow(geometryIntensity, 1.5); // More dramatic falloff
|
|
677
|
+
geometryIntensity += u_clickIntensity * 0.3;
|
|
678
|
+
|
|
679
|
+
// Holographic shimmer effect
|
|
680
|
+
float shimmer = sin(uv.x * 20.0 + timeSpeed * 5.0) * cos(uv.y * 15.0 + timeSpeed * 3.0) * 0.1;
|
|
681
|
+
geometryIntensity += shimmer * geometryIntensity;
|
|
682
|
+
|
|
683
|
+
// Apply user intensity control
|
|
684
|
+
float finalIntensity = geometryIntensity * u_intensity;
|
|
685
|
+
|
|
686
|
+
// LAYER-BY-LAYER COLOR SYSTEM with user hue/saturation/intensity controls
|
|
687
|
+
// Determine canvas layer from role/variant (0=background, 1=shadow, 2=content, 3=highlight, 4=accent)
|
|
688
|
+
int layerIndex = 0;
|
|
689
|
+
if (u_roleIntensity == 0.7) layerIndex = 1; // shadow layer
|
|
690
|
+
else if (u_roleIntensity == 1.0) layerIndex = 2; // content layer
|
|
691
|
+
else if (u_roleIntensity == 0.85) layerIndex = 3; // highlight layer
|
|
692
|
+
else if (u_roleIntensity == 0.6) layerIndex = 4; // accent layer
|
|
693
|
+
|
|
694
|
+
// Get layer-specific base color using user hue/saturation controls
|
|
695
|
+
float colorTime = timeSpeed * 2.0 + value * 3.0;
|
|
696
|
+
vec3 layerColor = getLayerColorPalette(layerIndex, colorTime);
|
|
697
|
+
|
|
698
|
+
// Apply geometry-based intensity modulation per layer
|
|
699
|
+
vec3 extremeBaseColor;
|
|
700
|
+
if (layerIndex == 0) {
|
|
701
|
+
// Background: Subtle, fills empty space
|
|
702
|
+
extremeBaseColor = layerColor * (0.3 + geometryIntensity * 0.4);
|
|
703
|
+
}
|
|
704
|
+
else if (layerIndex == 1) {
|
|
705
|
+
// Shadow: Aggressive, high contrast where geometry is weak
|
|
706
|
+
float shadowIntensity = pow(1.0 - geometryIntensity, 2.0); // Inverted for shadows
|
|
707
|
+
extremeBaseColor = layerColor * (shadowIntensity * 0.8 + 0.1);
|
|
708
|
+
}
|
|
709
|
+
else if (layerIndex == 2) {
|
|
710
|
+
// Content: Dominant, follows geometry strongly
|
|
711
|
+
extremeBaseColor = layerColor * (geometryIntensity * 1.2 + 0.2);
|
|
712
|
+
}
|
|
713
|
+
else if (layerIndex == 3) {
|
|
714
|
+
// Highlight: Electric, peaks only
|
|
715
|
+
float peakIntensity = pow(geometryIntensity, 3.0); // Cubic for sharp peaks
|
|
716
|
+
extremeBaseColor = layerColor * (peakIntensity * 1.5 + 0.1);
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
// Accent: Chaotic, random bursts
|
|
720
|
+
float randomBurst = sin(value * 50.0 + timeSpeed * 10.0) * 0.5 + 0.5;
|
|
721
|
+
extremeBaseColor = layerColor * (randomBurst * geometryIntensity * 2.0 + 0.05);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Apply extreme RGB separation per layer
|
|
725
|
+
vec3 extremeColor = extremeRGBSeparation(extremeBaseColor, uv, finalIntensity, layerIndex);
|
|
726
|
+
|
|
727
|
+
// Layer-specific particle systems with extreme colors
|
|
728
|
+
float extremeParticles = 0.0;
|
|
729
|
+
if (layerIndex == 2 || layerIndex == 3) {
|
|
730
|
+
// Only content and highlight layers get particles
|
|
731
|
+
vec2 particleUV = uv * (layerIndex == 2 ? 12.0 : 20.0);
|
|
732
|
+
vec2 particleID = floor(particleUV);
|
|
733
|
+
vec2 particlePos = fract(particleUV) - 0.5;
|
|
734
|
+
float particleDist = length(particlePos);
|
|
735
|
+
|
|
736
|
+
float particleTime = timeSpeed * (layerIndex == 2 ? 3.0 : 8.0) + dot(particleID, vec2(127.1, 311.7));
|
|
737
|
+
float particleAlpha = sin(particleTime) * 0.5 + 0.5;
|
|
738
|
+
float particleSize = layerIndex == 2 ? 0.2 : 0.1;
|
|
739
|
+
extremeParticles = (1.0 - smoothstep(0.05, particleSize, particleDist)) * particleAlpha * 0.4;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Combine color with particles based on layer
|
|
743
|
+
// Particle color derives from user hue for consistency
|
|
744
|
+
vec3 particleColor = hsl2rgb(fract(u_hue + 0.15), u_saturation * 0.5, 0.85);
|
|
745
|
+
vec3 finalColor;
|
|
746
|
+
if (layerIndex == 0) {
|
|
747
|
+
finalColor = extremeColor;
|
|
748
|
+
}
|
|
749
|
+
else if (layerIndex == 1) {
|
|
750
|
+
finalColor = extremeColor * 0.8;
|
|
751
|
+
}
|
|
752
|
+
else if (layerIndex == 2) {
|
|
753
|
+
finalColor = extremeColor + extremeParticles * particleColor;
|
|
754
|
+
}
|
|
755
|
+
else if (layerIndex == 3) {
|
|
756
|
+
finalColor = extremeColor + extremeParticles * particleColor;
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
finalColor = extremeColor * (1.0 + sin(timeSpeed * 20.0) * 0.3);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Layer-specific alpha intensity with extreme contrast
|
|
763
|
+
float layerAlpha;
|
|
764
|
+
if (layerIndex == 0) layerAlpha = 0.6; // Background: Medium
|
|
765
|
+
else if (layerIndex == 1) layerAlpha = 0.4; // Shadow: Lower
|
|
766
|
+
else if (layerIndex == 2) layerAlpha = 1.0; // Content: Full intensity
|
|
767
|
+
else if (layerIndex == 3) layerAlpha = 0.8; // Highlight: High
|
|
768
|
+
else layerAlpha = 0.3; // Accent: Subtle bursts
|
|
769
|
+
|
|
770
|
+
gl_FragColor = vec4(finalColor, finalIntensity * layerAlpha);
|
|
771
|
+
}`;
|
|
772
|
+
|
|
773
|
+
this.program = this.createProgram(vertexShaderSource, fragmentShaderSource);
|
|
774
|
+
this.uniforms = {
|
|
775
|
+
resolution: this.gl.getUniformLocation(this.program, 'u_resolution'),
|
|
776
|
+
time: this.gl.getUniformLocation(this.program, 'u_time'),
|
|
777
|
+
mouse: this.gl.getUniformLocation(this.program, 'u_mouse'),
|
|
778
|
+
geometry: this.gl.getUniformLocation(this.program, 'u_geometry'),
|
|
779
|
+
gridDensity: this.gl.getUniformLocation(this.program, 'u_gridDensity'),
|
|
780
|
+
morphFactor: this.gl.getUniformLocation(this.program, 'u_morphFactor'),
|
|
781
|
+
chaos: this.gl.getUniformLocation(this.program, 'u_chaos'),
|
|
782
|
+
speed: this.gl.getUniformLocation(this.program, 'u_speed'),
|
|
783
|
+
hue: this.gl.getUniformLocation(this.program, 'u_hue'),
|
|
784
|
+
intensity: this.gl.getUniformLocation(this.program, 'u_intensity'),
|
|
785
|
+
saturation: this.gl.getUniformLocation(this.program, 'u_saturation'),
|
|
786
|
+
dimension: this.gl.getUniformLocation(this.program, 'u_dimension'),
|
|
787
|
+
rot4dXY: this.gl.getUniformLocation(this.program, 'u_rot4dXY'),
|
|
788
|
+
rot4dXZ: this.gl.getUniformLocation(this.program, 'u_rot4dXZ'),
|
|
789
|
+
rot4dYZ: this.gl.getUniformLocation(this.program, 'u_rot4dYZ'),
|
|
790
|
+
rot4dXW: this.gl.getUniformLocation(this.program, 'u_rot4dXW'),
|
|
791
|
+
rot4dYW: this.gl.getUniformLocation(this.program, 'u_rot4dYW'),
|
|
792
|
+
rot4dZW: this.gl.getUniformLocation(this.program, 'u_rot4dZW'),
|
|
793
|
+
mouseIntensity: this.gl.getUniformLocation(this.program, 'u_mouseIntensity'),
|
|
794
|
+
clickIntensity: this.gl.getUniformLocation(this.program, 'u_clickIntensity'),
|
|
795
|
+
roleIntensity: this.gl.getUniformLocation(this.program, 'u_roleIntensity')
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Create WebGL program from shaders
|
|
801
|
+
*/
|
|
802
|
+
createProgram(vertexSource, fragmentSource) {
|
|
803
|
+
const vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexSource);
|
|
804
|
+
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, fragmentSource);
|
|
805
|
+
|
|
806
|
+
if (!vertexShader || !fragmentShader) {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
const program = this.gl.createProgram();
|
|
811
|
+
this.gl.attachShader(program, vertexShader);
|
|
812
|
+
this.gl.attachShader(program, fragmentShader);
|
|
813
|
+
this.gl.linkProgram(program);
|
|
814
|
+
|
|
815
|
+
if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
|
|
816
|
+
const error = this.gl.getProgramInfoLog(program);
|
|
817
|
+
console.error('Program linking failed:', error);
|
|
818
|
+
if (window.mobileDebug) {
|
|
819
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: Shader program link failed - ${error}`);
|
|
820
|
+
}
|
|
821
|
+
return null;
|
|
822
|
+
} else {
|
|
823
|
+
if (window.mobileDebug) {
|
|
824
|
+
window.mobileDebug.log(`✅ ${this.canvas?.id}: Shader program linked successfully`);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
return program;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Create individual shader
|
|
833
|
+
*/
|
|
834
|
+
createShader(type, source) {
|
|
835
|
+
// CRITICAL FIX: Check WebGL context state before shader operations
|
|
836
|
+
if (!this.gl) {
|
|
837
|
+
console.error('❌ Cannot create shader: WebGL context is null');
|
|
838
|
+
if (window.mobileDebug) {
|
|
839
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: Cannot create shader - WebGL context is null`);
|
|
840
|
+
}
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
if (this.gl.isContextLost()) {
|
|
845
|
+
console.error('❌ Cannot create shader: WebGL context is lost');
|
|
846
|
+
if (window.mobileDebug) {
|
|
847
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: Cannot create shader - WebGL context is lost`);
|
|
848
|
+
}
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
try {
|
|
853
|
+
const shader = this.gl.createShader(type);
|
|
854
|
+
|
|
855
|
+
if (!shader) {
|
|
856
|
+
console.error('❌ Failed to create shader object - WebGL context may be invalid');
|
|
857
|
+
if (window.mobileDebug) {
|
|
858
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: Failed to create shader object`);
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
this.gl.shaderSource(shader, source);
|
|
864
|
+
this.gl.compileShader(shader);
|
|
865
|
+
|
|
866
|
+
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
|
867
|
+
const error = this.gl.getShaderInfoLog(shader);
|
|
868
|
+
const shaderType = type === this.gl.VERTEX_SHADER ? 'vertex' : 'fragment';
|
|
869
|
+
|
|
870
|
+
// CRITICAL FIX: Show actual error instead of null
|
|
871
|
+
if (error) {
|
|
872
|
+
console.error(`❌ ${shaderType} shader compilation failed:`, error);
|
|
873
|
+
} else {
|
|
874
|
+
console.error(`❌ ${shaderType} shader compilation failed: WebGL returned no error info (context may be invalid)`);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
console.error('Shader source:', source);
|
|
878
|
+
|
|
879
|
+
if (window.mobileDebug) {
|
|
880
|
+
const errorMsg = error || 'No error info (context may be invalid)';
|
|
881
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: ${shaderType} shader compile failed - ${errorMsg}`);
|
|
882
|
+
// Log first few lines of problematic shader for mobile debugging
|
|
883
|
+
const sourceLines = source.split('\n').slice(0, 5).join('\\n');
|
|
884
|
+
window.mobileDebug.log(`🔍 ${shaderType} shader source start: ${sourceLines}...`);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
this.gl.deleteShader(shader);
|
|
888
|
+
return null;
|
|
889
|
+
} else {
|
|
890
|
+
if (window.mobileDebug) {
|
|
891
|
+
const shaderType = type === this.gl.VERTEX_SHADER ? 'vertex' : 'fragment';
|
|
892
|
+
window.mobileDebug.log(`✅ ${this.canvas?.id}: ${shaderType} shader compiled successfully`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
return shader;
|
|
897
|
+
} catch (error) {
|
|
898
|
+
console.error('❌ Exception during shader creation:', error);
|
|
899
|
+
if (window.mobileDebug) {
|
|
900
|
+
window.mobileDebug.log(`❌ ${this.canvas?.id}: Exception during shader creation - ${error.message}`);
|
|
901
|
+
}
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Initialize vertex buffers
|
|
908
|
+
*/
|
|
909
|
+
initBuffers() {
|
|
910
|
+
const positions = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
|
911
|
+
|
|
912
|
+
this.buffer = this.gl.createBuffer();
|
|
913
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);
|
|
914
|
+
this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW);
|
|
915
|
+
|
|
916
|
+
const positionLocation = this.gl.getAttribLocation(this.program, 'a_position');
|
|
917
|
+
this.gl.enableVertexAttribArray(positionLocation);
|
|
918
|
+
this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Resize canvas and viewport
|
|
923
|
+
*/
|
|
924
|
+
resize() {
|
|
925
|
+
// Mobile-optimized canvas sizing
|
|
926
|
+
const dpr = Math.min(window.devicePixelRatio || 1, 2); // Cap at 2x for mobile performance
|
|
927
|
+
const width = this.canvas.clientWidth;
|
|
928
|
+
const height = this.canvas.clientHeight;
|
|
929
|
+
|
|
930
|
+
// Mobile debug: Check for zero dimensions that would cause invisible rendering
|
|
931
|
+
if (window.mobileDebug && (width === 0 || height === 0) && !this._zeroDimWarned) {
|
|
932
|
+
window.mobileDebug.log(`⚠️ ${this.canvas?.id}: Canvas clientWidth=${width}, clientHeight=${height} - will be invisible`);
|
|
933
|
+
this._zeroDimWarned = true;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// Only resize if dimensions actually changed (mobile optimization)
|
|
937
|
+
if (this.canvas.width !== width * dpr || this.canvas.height !== height * dpr) {
|
|
938
|
+
this.canvas.width = width * dpr;
|
|
939
|
+
this.canvas.height = height * dpr;
|
|
940
|
+
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
941
|
+
|
|
942
|
+
// Mobile debug: Log final canvas dimensions
|
|
943
|
+
if (window.mobileDebug && !this._finalSizeLogged) {
|
|
944
|
+
window.mobileDebug.log(`📐 ${this.canvas?.id}: Final canvas buffer ${this.canvas.width}x${this.canvas.height} (DPR=${dpr})`);
|
|
945
|
+
this._finalSizeLogged = true;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Show user-friendly WebGL error message
|
|
952
|
+
*/
|
|
953
|
+
showWebGLError() {
|
|
954
|
+
if (!this.canvas) return;
|
|
955
|
+
const ctx = this.canvas.getContext('2d');
|
|
956
|
+
if (ctx) {
|
|
957
|
+
ctx.fillStyle = '#000';
|
|
958
|
+
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
959
|
+
ctx.fillStyle = '#64ff96';
|
|
960
|
+
ctx.font = '16px Orbitron, monospace';
|
|
961
|
+
ctx.textAlign = 'center';
|
|
962
|
+
ctx.fillText('WebGL Required', this.canvas.width / 2, this.canvas.height / 2);
|
|
963
|
+
ctx.fillStyle = '#888';
|
|
964
|
+
ctx.font = '12px Orbitron, monospace';
|
|
965
|
+
ctx.fillText('Please enable WebGL in your browser', this.canvas.width / 2, this.canvas.height / 2 + 25);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Update visualization parameters with immediate GPU sync
|
|
971
|
+
*/
|
|
972
|
+
updateParameters(params) {
|
|
973
|
+
if (!params || typeof params !== 'object') return;
|
|
974
|
+
// Filter to only finite numbers to prevent NaN/Infinity reaching GPU uniforms
|
|
975
|
+
for (const [key, value] of Object.entries(params)) {
|
|
976
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
977
|
+
this.params[key] = value;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
// Don't call render() here - engine will call it to prevent infinite loop
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Update mouse interaction state
|
|
985
|
+
*/
|
|
986
|
+
updateInteraction(x, y, intensity) {
|
|
987
|
+
this.mouseX = x;
|
|
988
|
+
this.mouseY = y;
|
|
989
|
+
this.mouseIntensity = intensity;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* Render frame
|
|
994
|
+
*/
|
|
995
|
+
render() {
|
|
996
|
+
if (!this.program || this._contextLost) return;
|
|
997
|
+
if (!this.gl || this.gl.isContextLost()) {
|
|
998
|
+
this._contextLost = true;
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
this.resize();
|
|
1003
|
+
this.gl.useProgram(this.program);
|
|
1004
|
+
|
|
1005
|
+
// CRITICAL FIX: Clear framebuffer before rendering
|
|
1006
|
+
this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
|
1007
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
1008
|
+
|
|
1009
|
+
// Mobile optimization: Log render parameters once per canvas (console only)
|
|
1010
|
+
if (!this._renderParamsLogged) {
|
|
1011
|
+
console.log(`[Mobile] ${this.canvas?.id}: Render params - geometry=${this.params.geometry}, gridDensity=${this.params.gridDensity}, intensity=${this.params.intensity}`);
|
|
1012
|
+
this._renderParamsLogged = true;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Role-specific intensity for quantum effects
|
|
1016
|
+
const roleIntensities = {
|
|
1017
|
+
'background': 0.4,
|
|
1018
|
+
'shadow': 0.6,
|
|
1019
|
+
'content': 1.0,
|
|
1020
|
+
'highlight': 1.3,
|
|
1021
|
+
'accent': 1.6
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
const time = Date.now() - this.startTime;
|
|
1025
|
+
|
|
1026
|
+
// Set uniforms
|
|
1027
|
+
this.gl.uniform2f(this.uniforms.resolution, this.canvas.width, this.canvas.height);
|
|
1028
|
+
this.gl.uniform1f(this.uniforms.time, time);
|
|
1029
|
+
this.gl.uniform2f(this.uniforms.mouse, this.mouseX, this.mouseY);
|
|
1030
|
+
this.gl.uniform1f(this.uniforms.geometry, this.params.geometry);
|
|
1031
|
+
// 🎵 QUANTUM AUDIO REACTIVITY - Direct and effective
|
|
1032
|
+
let gridDensity = this.params.gridDensity;
|
|
1033
|
+
let morphFactor = this.params.morphFactor;
|
|
1034
|
+
let hue = this.params.hue;
|
|
1035
|
+
let chaos = this.params.chaos;
|
|
1036
|
+
|
|
1037
|
+
if (window.audioEnabled && window.audioReactive) {
|
|
1038
|
+
// Quantum audio mapping: Enhanced complex lattice response
|
|
1039
|
+
gridDensity += window.audioReactive.bass * 40; // Bass creates dense lattice structures
|
|
1040
|
+
morphFactor += window.audioReactive.mid * 1.2; // Mid frequencies morph the geometry
|
|
1041
|
+
hue += window.audioReactive.high * 120; // High frequencies shift colors dramatically
|
|
1042
|
+
chaos += window.audioReactive.energy * 0.6; // Overall energy adds chaos/complexity
|
|
1043
|
+
|
|
1044
|
+
// Debug logging every 10 seconds to verify audio reactivity is working
|
|
1045
|
+
if (Date.now() % 10000 < 16) {
|
|
1046
|
+
console.log(`🌌 Quantum audio reactivity: Density+${(window.audioReactive.bass * 40).toFixed(1)} Morph+${(window.audioReactive.mid * 1.2).toFixed(2)} Hue+${(window.audioReactive.high * 120).toFixed(1)} Chaos+${(window.audioReactive.energy * 0.6).toFixed(2)}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
this.gl.uniform1f(this.uniforms.gridDensity, Math.min(100, gridDensity));
|
|
1051
|
+
this.gl.uniform1f(this.uniforms.morphFactor, Math.min(2, morphFactor));
|
|
1052
|
+
this.gl.uniform1f(this.uniforms.chaos, Math.min(1, chaos));
|
|
1053
|
+
this.gl.uniform1f(this.uniforms.speed, this.params.speed);
|
|
1054
|
+
// Hue passed as normalized 0-1 for HSL color control
|
|
1055
|
+
this.gl.uniform1f(this.uniforms.hue, (hue % 360) / 360.0);
|
|
1056
|
+
this.gl.uniform1f(this.uniforms.intensity, this.params.intensity);
|
|
1057
|
+
this.gl.uniform1f(this.uniforms.saturation, this.params.saturation);
|
|
1058
|
+
this.gl.uniform1f(this.uniforms.dimension, this.params.dimension);
|
|
1059
|
+
this.gl.uniform1f(this.uniforms.rot4dXY, this.params.rot4dXY || 0.0);
|
|
1060
|
+
this.gl.uniform1f(this.uniforms.rot4dXZ, this.params.rot4dXZ || 0.0);
|
|
1061
|
+
this.gl.uniform1f(this.uniforms.rot4dYZ, this.params.rot4dYZ || 0.0);
|
|
1062
|
+
this.gl.uniform1f(this.uniforms.rot4dXW, this.params.rot4dXW || 0.0);
|
|
1063
|
+
this.gl.uniform1f(this.uniforms.rot4dYW, this.params.rot4dYW || 0.0);
|
|
1064
|
+
this.gl.uniform1f(this.uniforms.rot4dZW, this.params.rot4dZW || 0.0);
|
|
1065
|
+
this.gl.uniform1f(this.uniforms.mouseIntensity, this.mouseIntensity);
|
|
1066
|
+
this.gl.uniform1f(this.uniforms.clickIntensity, this.clickIntensity);
|
|
1067
|
+
this.gl.uniform1f(this.uniforms.roleIntensity, roleIntensities[this.role] || 1.0);
|
|
1068
|
+
|
|
1069
|
+
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// Audio reactivity now handled directly in render() loop - no complex methods needed
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* Clean up WebGL resources
|
|
1076
|
+
*/
|
|
1077
|
+
destroy() {
|
|
1078
|
+
// Remove context loss listeners
|
|
1079
|
+
if (this.canvas) {
|
|
1080
|
+
if (this._onContextLost) {
|
|
1081
|
+
this.canvas.removeEventListener('webglcontextlost', this._onContextLost);
|
|
1082
|
+
}
|
|
1083
|
+
if (this._onContextRestored) {
|
|
1084
|
+
this.canvas.removeEventListener('webglcontextrestored', this._onContextRestored);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Clean up WebGL resources (guard against lost context)
|
|
1089
|
+
if (this.gl && !this.gl.isContextLost()) {
|
|
1090
|
+
if (this.program) {
|
|
1091
|
+
this.gl.deleteProgram(this.program);
|
|
1092
|
+
}
|
|
1093
|
+
if (this.buffer) {
|
|
1094
|
+
this.gl.deleteBuffer(this.buffer);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
this.program = null;
|
|
1099
|
+
this.buffer = null;
|
|
1100
|
+
this.gl = null;
|
|
1101
|
+
this._contextLost = true;
|
|
1102
|
+
}
|
|
1103
|
+
}
|