@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,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnifiedRenderBridge - Connects VIB3+ visualization systems to WebGL/WebGPU backends.
|
|
3
|
+
*
|
|
4
|
+
* All three VIB3+ visualization systems (Quantum, Faceted, Holographic) use the same
|
|
5
|
+
* rendering pattern: procedural fragment shaders on a fullscreen quad. This bridge
|
|
6
|
+
* abstracts that pattern so systems can render identically on either backend.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const bridge = await UnifiedRenderBridge.create(canvas, { preferWebGPU: true });
|
|
10
|
+
* bridge.compileShader('faceted', vertexSrc, fragmentSrc);
|
|
11
|
+
* bridge.setUniforms({ u_time: 1.5, u_resolution: [800, 600], ... });
|
|
12
|
+
* bridge.render('faceted');
|
|
13
|
+
* bridge.dispose();
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createWebGPUBackend, isWebGPUSupported, WGSLShaderLib } from './backends/WebGPUBackend.js';
|
|
17
|
+
|
|
18
|
+
/** @typedef {'webgl'|'webgpu'} BackendType */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Packs VIB3+ parameters into a Float32Array for WebGPU uniform buffer.
|
|
22
|
+
* Layout must match VIB3Uniforms struct in WGSL.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} uniforms - Uniform name→value map
|
|
25
|
+
* @returns {Float32Array}
|
|
26
|
+
*/
|
|
27
|
+
function packVIB3Uniforms(uniforms) {
|
|
28
|
+
// Total: 32 floats = 128 bytes → aligned to 256 bytes in buffer
|
|
29
|
+
const data = new Float32Array(64); // 256 bytes
|
|
30
|
+
|
|
31
|
+
data[0] = uniforms.u_time || 0;
|
|
32
|
+
data[1] = 0; // _pad0
|
|
33
|
+
data[2] = uniforms.u_resolution?.[0] || 800;
|
|
34
|
+
data[3] = uniforms.u_resolution?.[1] || 600;
|
|
35
|
+
|
|
36
|
+
data[4] = uniforms.u_geometry || 0;
|
|
37
|
+
data[5] = uniforms.u_rot4dXY || 0;
|
|
38
|
+
data[6] = uniforms.u_rot4dXZ || 0;
|
|
39
|
+
data[7] = uniforms.u_rot4dYZ || 0;
|
|
40
|
+
data[8] = uniforms.u_rot4dXW || 0;
|
|
41
|
+
data[9] = uniforms.u_rot4dYW || 0;
|
|
42
|
+
data[10] = uniforms.u_rot4dZW || 0;
|
|
43
|
+
|
|
44
|
+
data[11] = uniforms.u_dimension || 3.5;
|
|
45
|
+
data[12] = uniforms.u_gridDensity || 1.5;
|
|
46
|
+
data[13] = uniforms.u_morphFactor || 1.0;
|
|
47
|
+
data[14] = uniforms.u_chaos || 0.2;
|
|
48
|
+
data[15] = uniforms.u_speed || 1.0;
|
|
49
|
+
data[16] = uniforms.u_hue || 200;
|
|
50
|
+
data[17] = uniforms.u_intensity || 0.7;
|
|
51
|
+
data[18] = uniforms.u_saturation || 0.8;
|
|
52
|
+
|
|
53
|
+
data[19] = uniforms.u_mouseIntensity || 0;
|
|
54
|
+
data[20] = uniforms.u_clickIntensity || 0;
|
|
55
|
+
data[21] = uniforms.u_bass || 0;
|
|
56
|
+
data[22] = uniforms.u_mid || 0;
|
|
57
|
+
data[23] = uniforms.u_high || 0;
|
|
58
|
+
|
|
59
|
+
data[24] = uniforms.u_layerScale || 1.0;
|
|
60
|
+
data[25] = uniforms.u_layerOpacity || 1.0;
|
|
61
|
+
data[26] = 0; // _pad1
|
|
62
|
+
data[27] = uniforms.u_layerColor?.[0] || 1.0;
|
|
63
|
+
data[28] = uniforms.u_layerColor?.[1] || 1.0;
|
|
64
|
+
data[29] = uniforms.u_layerColor?.[2] || 1.0;
|
|
65
|
+
data[30] = uniforms.u_densityMult || 1.0;
|
|
66
|
+
data[31] = uniforms.u_speedMult || 1.0;
|
|
67
|
+
// [32..63] padding to 256
|
|
68
|
+
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class UnifiedRenderBridge {
|
|
73
|
+
/**
|
|
74
|
+
* @param {HTMLCanvasElement} canvas
|
|
75
|
+
* @param {BackendType} backendType
|
|
76
|
+
* @param {object} backend - WebGLBackend-like or WebGPUBackend instance
|
|
77
|
+
*/
|
|
78
|
+
constructor(canvas, backendType, backend) {
|
|
79
|
+
/** @type {HTMLCanvasElement} */
|
|
80
|
+
this.canvas = canvas;
|
|
81
|
+
|
|
82
|
+
/** @type {BackendType} */
|
|
83
|
+
this.backendType = backendType;
|
|
84
|
+
|
|
85
|
+
/** @type {object} */
|
|
86
|
+
this.backend = backend;
|
|
87
|
+
|
|
88
|
+
// ---- WebGL state ----
|
|
89
|
+
/** @type {Map<string, {program: WebGLProgram, uniformLocations: Map<string, WebGLUniformLocation>}>} */
|
|
90
|
+
this._glPrograms = new Map();
|
|
91
|
+
|
|
92
|
+
/** @type {WebGLBuffer|null} */
|
|
93
|
+
this._glQuadBuffer = null;
|
|
94
|
+
|
|
95
|
+
// ---- WebGPU state ----
|
|
96
|
+
/** @type {Map<string, string>} pipeline name → buffer name */
|
|
97
|
+
this._gpuPipelineBuffers = new Map();
|
|
98
|
+
|
|
99
|
+
// ---- Shared state ----
|
|
100
|
+
/** @type {Map<string, object>} */
|
|
101
|
+
this._currentUniforms = new Map();
|
|
102
|
+
|
|
103
|
+
this._initialized = false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create a UnifiedRenderBridge with automatic backend selection.
|
|
108
|
+
*
|
|
109
|
+
* @param {HTMLCanvasElement} canvas - Target canvas element
|
|
110
|
+
* @param {object} [options]
|
|
111
|
+
* @param {boolean} [options.preferWebGPU=true] - Try WebGPU first
|
|
112
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
113
|
+
* @returns {Promise<UnifiedRenderBridge>}
|
|
114
|
+
*/
|
|
115
|
+
static async create(canvas, options = {}) {
|
|
116
|
+
const preferWebGPU = options.preferWebGPU !== false;
|
|
117
|
+
const debug = options.debug || false;
|
|
118
|
+
|
|
119
|
+
// Try WebGPU first if preferred
|
|
120
|
+
if (preferWebGPU && isWebGPUSupported()) {
|
|
121
|
+
try {
|
|
122
|
+
const gpuBackend = await createWebGPUBackend(canvas, {
|
|
123
|
+
debug,
|
|
124
|
+
depth: false // Procedural shaders don't need depth
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (gpuBackend) {
|
|
128
|
+
const bridge = new UnifiedRenderBridge(canvas, 'webgpu', gpuBackend);
|
|
129
|
+
bridge._initialized = true;
|
|
130
|
+
if (debug) console.log('UnifiedRenderBridge: using WebGPU backend');
|
|
131
|
+
return bridge;
|
|
132
|
+
}
|
|
133
|
+
} catch (e) {
|
|
134
|
+
if (debug) console.warn('WebGPU init failed, falling back to WebGL:', e);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Fall back to WebGL
|
|
139
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
140
|
+
if (!gl) {
|
|
141
|
+
throw new Error('Neither WebGPU nor WebGL is available');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const bridge = new UnifiedRenderBridge(canvas, 'webgl', gl);
|
|
145
|
+
bridge._initWebGLQuadBuffer();
|
|
146
|
+
bridge._initialized = true;
|
|
147
|
+
if (debug) console.log('UnifiedRenderBridge: using WebGL backend');
|
|
148
|
+
return bridge;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get the active backend type
|
|
153
|
+
* @returns {BackendType}
|
|
154
|
+
*/
|
|
155
|
+
getBackendType() {
|
|
156
|
+
return this.backendType;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Check if the bridge is initialized
|
|
161
|
+
* @returns {boolean}
|
|
162
|
+
*/
|
|
163
|
+
get initialized() {
|
|
164
|
+
return this._initialized;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ========================================================================
|
|
168
|
+
// Shader Compilation
|
|
169
|
+
// ========================================================================
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Compile a shader program for a named visualization.
|
|
173
|
+
*
|
|
174
|
+
* For WebGL: compiles GLSL vertex + fragment shaders.
|
|
175
|
+
* For WebGPU: compiles WGSL fragment shader with fullscreen pipeline.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} name - Shader name (e.g., 'faceted', 'quantum')
|
|
178
|
+
* @param {object} sources
|
|
179
|
+
* @param {string} sources.glslVertex - GLSL vertex shader source
|
|
180
|
+
* @param {string} sources.glslFragment - GLSL fragment shader source
|
|
181
|
+
* @param {string} [sources.wgslFragment] - WGSL fragment shader source (optional, for WebGPU)
|
|
182
|
+
* @returns {boolean} Success
|
|
183
|
+
*/
|
|
184
|
+
compileShader(name, sources) {
|
|
185
|
+
if (this.backendType === 'webgl') {
|
|
186
|
+
return this._compileWebGLShader(name, sources.glslVertex, sources.glslFragment);
|
|
187
|
+
} else {
|
|
188
|
+
if (!sources.wgslFragment) {
|
|
189
|
+
// If no WGSL provided, we can't render on WebGPU with this shader.
|
|
190
|
+
// Systems that want WebGPU support must provide WGSL sources.
|
|
191
|
+
console.warn(`No WGSL fragment shader for "${name}", WebGPU rendering unavailable`);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
return this._compileWebGPUShader(name, sources.wgslFragment);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @private
|
|
200
|
+
*/
|
|
201
|
+
_compileWebGLShader(name, vertexSrc, fragmentSrc) {
|
|
202
|
+
const gl = this.backend;
|
|
203
|
+
|
|
204
|
+
const vertexShader = this._compileGLShader(gl, gl.VERTEX_SHADER, vertexSrc);
|
|
205
|
+
const fragmentShader = this._compileGLShader(gl, gl.FRAGMENT_SHADER, fragmentSrc);
|
|
206
|
+
|
|
207
|
+
if (!vertexShader || !fragmentShader) return false;
|
|
208
|
+
|
|
209
|
+
const program = gl.createProgram();
|
|
210
|
+
gl.attachShader(program, vertexShader);
|
|
211
|
+
gl.attachShader(program, fragmentShader);
|
|
212
|
+
gl.linkProgram(program);
|
|
213
|
+
|
|
214
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
215
|
+
console.error(`Shader link error [${name}]:`, gl.getProgramInfoLog(program));
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Cache uniform locations
|
|
220
|
+
const uniformLocations = new Map();
|
|
221
|
+
const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
|
222
|
+
for (let i = 0; i < numUniforms; i++) {
|
|
223
|
+
const info = gl.getActiveUniform(program, i);
|
|
224
|
+
if (info) {
|
|
225
|
+
uniformLocations.set(info.name, gl.getUniformLocation(program, info.name));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Clean up old program if replacing
|
|
230
|
+
const old = this._glPrograms.get(name);
|
|
231
|
+
if (old) {
|
|
232
|
+
gl.deleteProgram(old.program);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
this._glPrograms.set(name, { program, uniformLocations });
|
|
236
|
+
|
|
237
|
+
// Clean up shader objects (they're linked into the program now)
|
|
238
|
+
gl.deleteShader(vertexShader);
|
|
239
|
+
gl.deleteShader(fragmentShader);
|
|
240
|
+
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @private
|
|
246
|
+
*/
|
|
247
|
+
_compileGLShader(gl, type, source) {
|
|
248
|
+
const shader = gl.createShader(type);
|
|
249
|
+
gl.shaderSource(shader, source);
|
|
250
|
+
gl.compileShader(shader);
|
|
251
|
+
|
|
252
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
253
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
254
|
+
gl.deleteShader(shader);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return shader;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
_compileWebGPUShader(name, wgslFragmentSrc) {
|
|
265
|
+
const gpu = this.backend;
|
|
266
|
+
|
|
267
|
+
// Create custom uniform buffer for VIB3+ uniforms
|
|
268
|
+
const bufferName = `${name}-uniforms`;
|
|
269
|
+
const existing = gpu.getCustomUniformBuffer(bufferName);
|
|
270
|
+
if (!existing) {
|
|
271
|
+
gpu.createCustomUniformBuffer(bufferName, 256);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const uniformEntry = gpu.getCustomUniformBuffer(bufferName);
|
|
275
|
+
|
|
276
|
+
// Create fullscreen pipeline with the custom bind group layout
|
|
277
|
+
try {
|
|
278
|
+
gpu.createFullscreenPipeline(name, wgslFragmentSrc, {
|
|
279
|
+
bindGroupLayouts: [uniformEntry.layout]
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
this._gpuPipelineBuffers.set(name, bufferName);
|
|
283
|
+
return true;
|
|
284
|
+
} catch (e) {
|
|
285
|
+
console.error(`WebGPU pipeline creation failed [${name}]:`, e);
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ========================================================================
|
|
291
|
+
// Uniform Updates
|
|
292
|
+
// ========================================================================
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Set uniforms for the next render call.
|
|
296
|
+
* Accepts a flat object with uniform names as keys.
|
|
297
|
+
*
|
|
298
|
+
* @param {object} uniforms - e.g., { u_time: 1.5, u_resolution: [800, 600] }
|
|
299
|
+
*/
|
|
300
|
+
setUniforms(uniforms) {
|
|
301
|
+
// Store for render-time application
|
|
302
|
+
this._pendingUniforms = uniforms;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ========================================================================
|
|
306
|
+
// Rendering
|
|
307
|
+
// ========================================================================
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Render a fullscreen quad using the named shader program.
|
|
311
|
+
*
|
|
312
|
+
* @param {string} name - Shader name to use
|
|
313
|
+
* @param {object} [options]
|
|
314
|
+
* @param {number[]} [options.clearColor] - RGBA 0-1
|
|
315
|
+
* @param {boolean} [options.clear] - Whether to clear before drawing
|
|
316
|
+
*/
|
|
317
|
+
render(name, options = {}) {
|
|
318
|
+
if (this.backendType === 'webgl') {
|
|
319
|
+
this._renderWebGL(name, options);
|
|
320
|
+
} else {
|
|
321
|
+
this._renderWebGPU(name, options);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @private
|
|
327
|
+
*/
|
|
328
|
+
_renderWebGL(name, options) {
|
|
329
|
+
const gl = this.backend;
|
|
330
|
+
const entry = this._glPrograms.get(name);
|
|
331
|
+
if (!entry) return;
|
|
332
|
+
|
|
333
|
+
const { program, uniformLocations } = entry;
|
|
334
|
+
|
|
335
|
+
gl.useProgram(program);
|
|
336
|
+
gl.enable(gl.BLEND);
|
|
337
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
338
|
+
|
|
339
|
+
if (options.clear !== false) {
|
|
340
|
+
const cc = options.clearColor || [0, 0, 0, 1];
|
|
341
|
+
gl.clearColor(cc[0], cc[1], cc[2], cc[3]);
|
|
342
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Apply uniforms
|
|
346
|
+
const uniforms = this._pendingUniforms || {};
|
|
347
|
+
for (const [uName, value] of Object.entries(uniforms)) {
|
|
348
|
+
const loc = uniformLocations.get(uName);
|
|
349
|
+
if (loc === null || loc === undefined) continue;
|
|
350
|
+
|
|
351
|
+
if (Array.isArray(value)) {
|
|
352
|
+
switch (value.length) {
|
|
353
|
+
case 2: gl.uniform2fv(loc, value); break;
|
|
354
|
+
case 3: gl.uniform3fv(loc, value); break;
|
|
355
|
+
case 4: gl.uniform4fv(loc, value); break;
|
|
356
|
+
default: gl.uniform1fv(loc, value); break;
|
|
357
|
+
}
|
|
358
|
+
} else if (typeof value === 'number') {
|
|
359
|
+
gl.uniform1f(loc, value);
|
|
360
|
+
} else if (typeof value === 'boolean') {
|
|
361
|
+
gl.uniform1i(loc, value ? 1 : 0);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Draw fullscreen quad
|
|
366
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._glQuadBuffer);
|
|
367
|
+
const posLoc = gl.getAttribLocation(program, 'a_position');
|
|
368
|
+
if (posLoc >= 0) {
|
|
369
|
+
gl.enableVertexAttribArray(posLoc);
|
|
370
|
+
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
|
371
|
+
}
|
|
372
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @private
|
|
377
|
+
*/
|
|
378
|
+
_renderWebGPU(name, options) {
|
|
379
|
+
const gpu = this.backend;
|
|
380
|
+
const bufferName = this._gpuPipelineBuffers.get(name);
|
|
381
|
+
if (!bufferName) return;
|
|
382
|
+
|
|
383
|
+
const uniformEntry = gpu.getCustomUniformBuffer(bufferName);
|
|
384
|
+
if (!uniformEntry) return;
|
|
385
|
+
|
|
386
|
+
// Pack and upload uniforms
|
|
387
|
+
const packed = packVIB3Uniforms(this._pendingUniforms || {});
|
|
388
|
+
gpu.updateCustomUniforms(bufferName, packed);
|
|
389
|
+
|
|
390
|
+
// Render fullscreen quad
|
|
391
|
+
gpu.renderFullscreenQuad({
|
|
392
|
+
pipeline: name,
|
|
393
|
+
bindGroups: [uniformEntry.bindGroup],
|
|
394
|
+
clearColor: options.clearColor || [0, 0, 0, 1],
|
|
395
|
+
clear: options.clear !== false
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ========================================================================
|
|
400
|
+
// Canvas Management
|
|
401
|
+
// ========================================================================
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Resize the rendering surface
|
|
405
|
+
* @param {number} width
|
|
406
|
+
* @param {number} height
|
|
407
|
+
* @param {number} [pixelRatio=1]
|
|
408
|
+
*/
|
|
409
|
+
resize(width, height, pixelRatio = 1) {
|
|
410
|
+
const w = Math.floor(width * pixelRatio);
|
|
411
|
+
const h = Math.floor(height * pixelRatio);
|
|
412
|
+
|
|
413
|
+
this.canvas.width = w;
|
|
414
|
+
this.canvas.height = h;
|
|
415
|
+
|
|
416
|
+
if (this.backendType === 'webgl') {
|
|
417
|
+
this.backend.viewport(0, 0, w, h);
|
|
418
|
+
} else {
|
|
419
|
+
this.backend.resize(w, h);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Get the raw WebGL context or WebGPU backend for advanced usage
|
|
425
|
+
* @returns {WebGLRenderingContext|WebGL2RenderingContext|import('./backends/WebGPUBackend.js').WebGPUBackend}
|
|
426
|
+
*/
|
|
427
|
+
getRawBackend() {
|
|
428
|
+
return this.backend;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ========================================================================
|
|
432
|
+
// Cleanup
|
|
433
|
+
// ========================================================================
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Dispose of all resources
|
|
437
|
+
*/
|
|
438
|
+
dispose() {
|
|
439
|
+
if (this.backendType === 'webgl') {
|
|
440
|
+
const gl = this.backend;
|
|
441
|
+
for (const [, entry] of this._glPrograms) {
|
|
442
|
+
gl.deleteProgram(entry.program);
|
|
443
|
+
}
|
|
444
|
+
this._glPrograms.clear();
|
|
445
|
+
|
|
446
|
+
if (this._glQuadBuffer) {
|
|
447
|
+
gl.deleteBuffer(this._glQuadBuffer);
|
|
448
|
+
this._glQuadBuffer = null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Lose context to free GPU memory
|
|
452
|
+
const loseContext = gl.getExtension('WEBGL_lose_context');
|
|
453
|
+
if (loseContext) {
|
|
454
|
+
loseContext.loseContext();
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
this.backend.dispose();
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
this._gpuPipelineBuffers.clear();
|
|
461
|
+
this._currentUniforms.clear();
|
|
462
|
+
this._pendingUniforms = null;
|
|
463
|
+
this._initialized = false;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ========================================================================
|
|
467
|
+
// Internal Helpers
|
|
468
|
+
// ========================================================================
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Create the fullscreen quad vertex buffer for WebGL
|
|
472
|
+
* @private
|
|
473
|
+
*/
|
|
474
|
+
_initWebGLQuadBuffer() {
|
|
475
|
+
const gl = this.backend;
|
|
476
|
+
const vertices = new Float32Array([
|
|
477
|
+
-1, -1, 1, -1, -1, 1,
|
|
478
|
+
-1, 1, 1, -1, 1, 1
|
|
479
|
+
]);
|
|
480
|
+
this._glQuadBuffer = gl.createBuffer();
|
|
481
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._glQuadBuffer);
|
|
482
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Check if WebGPU is available in the current environment
|
|
488
|
+
* @returns {boolean}
|
|
489
|
+
*/
|
|
490
|
+
export function canUseWebGPU() {
|
|
491
|
+
return isWebGPUSupported();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export { WGSLShaderLib };
|
|
495
|
+
|
|
496
|
+
export default UnifiedRenderBridge;
|