@vib3code/sdk 2.0.1 → 2.0.3-canary.6f35b4c
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 +36 -0
- package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +243 -0
- package/DOCS/CLI_ONBOARDING.md +1 -1
- package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +117 -0
- package/DOCS/EPIC_SCROLL_EVENTS.md +773 -0
- package/DOCS/HANDOFF_LANDING_PAGE.md +154 -0
- package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +493 -0
- package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +937 -0
- package/DOCS/PRODUCT_STRATEGY.md +63 -0
- package/DOCS/README.md +103 -0
- package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +97 -0
- package/DOCS/ROADMAP.md +111 -0
- package/DOCS/SCROLL_TIMELINE_v3.md +269 -0
- package/DOCS/SITE_REFACTOR_PLAN.md +100 -0
- package/DOCS/STATUS.md +24 -0
- package/DOCS/SYSTEM_INVENTORY.md +33 -30
- package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +85 -0
- package/DOCS/VISUAL_ANALYSIS_FACETAD.md +133 -0
- package/DOCS/VISUAL_ANALYSIS_SIMONE.md +95 -0
- package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +86 -0
- package/DOCS/{BLUEPRINT_EXECUTION_PLAN_2026-01-07.md → archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md} +1 -1
- package/DOCS/{DEV_TRACK_ANALYSIS.md → archive/DEV_TRACK_ANALYSIS.md} +3 -0
- package/DOCS/{SYSTEM_AUDIT_2026-01-30.md → archive/SYSTEM_AUDIT_2026-01-30.md} +3 -0
- package/DOCS/{DEV_TRACK_SESSION_2026-01-31.md → dev-tracks/DEV_TRACK_SESSION_2026-01-31.md} +1 -1
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +231 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +127 -0
- package/DOCS/dev-tracks/README.md +10 -0
- package/README.md +26 -13
- package/cpp/CMakeLists.txt +236 -0
- package/cpp/bindings/embind.cpp +269 -0
- package/cpp/build.sh +129 -0
- package/cpp/geometry/Crystal.cpp +103 -0
- package/cpp/geometry/Fractal.cpp +136 -0
- package/cpp/geometry/GeometryGenerator.cpp +262 -0
- package/cpp/geometry/KleinBottle.cpp +71 -0
- package/cpp/geometry/Sphere.cpp +134 -0
- package/cpp/geometry/Tesseract.cpp +94 -0
- package/cpp/geometry/Tetrahedron.cpp +83 -0
- package/cpp/geometry/Torus.cpp +65 -0
- package/cpp/geometry/WarpFunctions.cpp +238 -0
- package/cpp/geometry/Wave.cpp +85 -0
- package/cpp/include/vib3_ffi.h +238 -0
- package/cpp/math/Mat4x4.cpp +409 -0
- package/cpp/math/Mat4x4.hpp +209 -0
- package/cpp/math/Projection.cpp +142 -0
- package/cpp/math/Projection.hpp +148 -0
- package/cpp/math/Rotor4D.cpp +322 -0
- package/cpp/math/Rotor4D.hpp +204 -0
- package/cpp/math/Vec4.cpp +303 -0
- package/cpp/math/Vec4.hpp +225 -0
- package/cpp/src/vib3_ffi.cpp +607 -0
- package/cpp/tests/Geometry_test.cpp +213 -0
- package/cpp/tests/Mat4x4_test.cpp +494 -0
- package/cpp/tests/Projection_test.cpp +298 -0
- package/cpp/tests/Rotor4D_test.cpp +423 -0
- package/cpp/tests/Vec4_test.cpp +489 -0
- package/package.json +31 -27
- package/src/agent/mcp/MCPServer.js +722 -0
- package/src/agent/mcp/stdio-server.js +264 -0
- package/src/agent/mcp/tools.js +367 -0
- package/src/cli/index.js +0 -0
- package/src/core/CanvasManager.js +97 -204
- package/src/core/ErrorReporter.js +1 -1
- package/src/core/Parameters.js +1 -1
- package/src/core/VIB3Engine.js +38 -1
- package/src/core/VitalitySystem.js +53 -0
- package/src/core/renderers/HolographicRendererAdapter.js +2 -2
- package/src/creative/AestheticMapper.js +628 -0
- package/src/creative/ChoreographyPlayer.js +481 -0
- package/src/export/TradingCardManager.js +3 -4
- package/src/faceted/FacetedSystem.js +237 -388
- package/src/holograms/HolographicVisualizer.js +29 -12
- package/src/holograms/RealHolographicSystem.js +68 -12
- package/src/polychora/PolychoraSystem.js +77 -0
- package/src/quantum/QuantumEngine.js +103 -66
- package/src/quantum/QuantumVisualizer.js +7 -2
- package/src/render/UnifiedRenderBridge.js +3 -0
- package/src/shaders/faceted/faceted.frag.glsl +220 -80
- package/src/shaders/faceted/faceted.frag.wgsl +138 -97
- package/src/shaders/holographic/holographic.frag.glsl +28 -9
- package/src/shaders/holographic/holographic.frag.wgsl +107 -38
- package/src/shaders/quantum/quantum.frag.glsl +1 -0
- package/src/shaders/quantum/quantum.frag.wgsl +1 -1
- package/src/viewer/index.js +1 -1
- package/tools/headless-renderer.js +258 -0
- package/tools/shader-sync-verify.js +8 -4
- package/tools/site-analysis/all-reports.json +32 -0
- package/tools/site-analysis/combined-analysis.md +50 -0
- package/tools/site-analyzer.mjs +779 -0
- package/tools/visual-catalog/capture.js +276 -0
- package/tools/visual-catalog/composite.js +138 -0
- /package/DOCS/{DEV_TRACK_PLAN_2026-01-07.md → archive/DEV_TRACK_PLAN_2026-01-07.md} +0 -0
- /package/DOCS/{SESSION_014_PLAN.md → archive/SESSION_014_PLAN.md} +0 -0
- /package/DOCS/{SESSION_LOG_2026-01-07.md → archive/SESSION_LOG_2026-01-07.md} +0 -0
- /package/DOCS/{STRATEGIC_BLUEPRINT_2026-01-07.md → archive/STRATEGIC_BLUEPRINT_2026-01-07.md} +0 -0
- /package/src/viewer/{ReactivityManager.js → ViewerInputHandler.js} +0 -0
|
@@ -50,6 +50,7 @@ const FRAGMENT_SHADER_GLSL = `
|
|
|
50
50
|
uniform float u_bass;
|
|
51
51
|
uniform float u_mid;
|
|
52
52
|
uniform float u_high;
|
|
53
|
+
uniform float u_breath; // Vitality System Breath (0.0 - 1.0)
|
|
53
54
|
|
|
54
55
|
// ── 6D Rotation Matrices ──
|
|
55
56
|
|
|
@@ -267,7 +268,11 @@ const FRAGMENT_SHADER_GLSL = `
|
|
|
267
268
|
// Intensity from lattice
|
|
268
269
|
float geometryIntensity = 1.0 - clamp(abs(value), 0.0, 1.0);
|
|
269
270
|
geometryIntensity += u_clickIntensity * 0.3;
|
|
270
|
-
|
|
271
|
+
|
|
272
|
+
// Exhale: Vitality Breath Modulation
|
|
273
|
+
float breathMod = 1.0 + (u_breath * 0.3); // +30% intensity at full breath
|
|
274
|
+
|
|
275
|
+
float finalIntensity = geometryIntensity * u_intensity * breathMod;
|
|
271
276
|
|
|
272
277
|
// Audio-reactive hue shift
|
|
273
278
|
float hue = u_hue / 360.0 + value * 0.1 + u_high * 0.08;
|
|
@@ -283,7 +288,7 @@ const FRAGMENT_SHADER_GLSL = `
|
|
|
283
288
|
float gray = (baseColor.r + baseColor.g + baseColor.b) / 3.0;
|
|
284
289
|
vec3 color = mix(vec3(gray), baseColor, u_saturation) * finalIntensity;
|
|
285
290
|
|
|
286
|
-
gl_FragColor = vec4(color, finalIntensity
|
|
291
|
+
gl_FragColor = vec4(color, finalIntensity);
|
|
287
292
|
}
|
|
288
293
|
`;
|
|
289
294
|
|
|
@@ -291,7 +296,7 @@ const FRAGMENT_SHADER_GLSL = `
|
|
|
291
296
|
const FRAGMENT_SHADER_WGSL = `
|
|
292
297
|
struct VIB3Uniforms {
|
|
293
298
|
time: f32,
|
|
294
|
-
|
|
299
|
+
_pad0: f32,
|
|
295
300
|
resolution: vec2<f32>,
|
|
296
301
|
geometry: f32,
|
|
297
302
|
rot4dXY: f32,
|
|
@@ -304,18 +309,24 @@ struct VIB3Uniforms {
|
|
|
304
309
|
gridDensity: f32,
|
|
305
310
|
morphFactor: f32,
|
|
306
311
|
chaos: f32,
|
|
312
|
+
speed: f32,
|
|
307
313
|
hue: f32,
|
|
308
314
|
intensity: f32,
|
|
309
315
|
saturation: f32,
|
|
310
316
|
mouseIntensity: f32,
|
|
311
317
|
clickIntensity: f32,
|
|
312
|
-
roleIntensity: f32,
|
|
313
318
|
bass: f32,
|
|
314
319
|
mid: f32,
|
|
315
320
|
high: f32,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
_pad1:
|
|
321
|
+
layerScale: f32,
|
|
322
|
+
layerOpacity: f32,
|
|
323
|
+
_pad1: f32,
|
|
324
|
+
layerColorR: f32,
|
|
325
|
+
layerColorG: f32,
|
|
326
|
+
layerColorB: f32,
|
|
327
|
+
densityMult: f32,
|
|
328
|
+
speedMult: f32,
|
|
329
|
+
breath: f32, // Index 32
|
|
319
330
|
};
|
|
320
331
|
|
|
321
332
|
@group(0) @binding(0) var<uniform> u: VIB3Uniforms;
|
|
@@ -406,7 +417,7 @@ fn warpHypertetraCore_w(p: vec3<f32>, geomIdx: i32) -> vec3<f32> {
|
|
|
406
417
|
fn applyCoreWarp_w(p: vec3<f32>, geomType: f32, mouseDelta: vec2<f32>) -> vec3<f32> {
|
|
407
418
|
let coreFloat = floor(geomType / 8.0);
|
|
408
419
|
let coreIndex = i32(clamp(coreFloat, 0.0, 2.0));
|
|
409
|
-
let baseFloat = geomType -
|
|
420
|
+
let baseFloat = geomType - floor(geomType / 8.0) * 8.0;
|
|
410
421
|
let geomIdx = i32(clamp(floor(baseFloat + 0.5), 0.0, 7.0));
|
|
411
422
|
if (coreIndex == 1) { return warpHypersphereCore_w(p, geomIdx); }
|
|
412
423
|
if (coreIndex == 2) { return warpHypertetraCore_w(p, geomIdx); }
|
|
@@ -459,7 +470,7 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
459
470
|
let timeSpeed = u.time * 0.0001 * u.speed;
|
|
460
471
|
|
|
461
472
|
var pos = vec4<f32>(uv2 * 3.0, sin(timeSpeed * 3.0), cos(timeSpeed * 2.0));
|
|
462
|
-
pos = vec4<f32>(pos.xy + (
|
|
473
|
+
pos = vec4<f32>(pos.xy + (vec2<f32>(0.5, 0.5) - 0.5) * u.mouseIntensity * 2.0, pos.z, pos.w);
|
|
463
474
|
|
|
464
475
|
pos = rotateXY_w(u.rot4dXY) * pos;
|
|
465
476
|
pos = rotateXZ_w(u.rot4dXZ) * pos;
|
|
@@ -469,7 +480,7 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
469
480
|
pos = rotateZW_w(u.rot4dZW) * pos;
|
|
470
481
|
|
|
471
482
|
let basePoint = project4Dto3D_w(pos);
|
|
472
|
-
let warpedPoint = applyCoreWarp_w(basePoint, u.geometry,
|
|
483
|
+
let warpedPoint = applyCoreWarp_w(basePoint, u.geometry, vec2<f32>(0.0, 0.0));
|
|
473
484
|
let warpedPos = vec4<f32>(warpedPoint, pos.w);
|
|
474
485
|
var value = geometryFunction_w(warpedPos);
|
|
475
486
|
|
|
@@ -478,7 +489,10 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
478
489
|
|
|
479
490
|
var geomIntensity = 1.0 - clamp(abs(value), 0.0, 1.0);
|
|
480
491
|
geomIntensity += u.clickIntensity * 0.3;
|
|
481
|
-
|
|
492
|
+
|
|
493
|
+
// Vitality (Breath) modulation
|
|
494
|
+
let breathMod = 1.0 + (u.breath * 0.3);
|
|
495
|
+
let finalIntensity = geomIntensity * u.intensity * breathMod;
|
|
482
496
|
|
|
483
497
|
let hueVal = u.hue / 360.0 + value * 0.1 + u.high * 0.08;
|
|
484
498
|
let baseColor = vec3<f32>(
|
|
@@ -488,7 +502,7 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
488
502
|
let gray = (baseColor.r + baseColor.g + baseColor.b) / 3.0;
|
|
489
503
|
let color = mix(vec3<f32>(gray), baseColor, u.saturation) * finalIntensity;
|
|
490
504
|
|
|
491
|
-
return vec4<f32>(color, finalIntensity
|
|
505
|
+
return vec4<f32>(color, finalIntensity);
|
|
492
506
|
}
|
|
493
507
|
`;
|
|
494
508
|
|
|
@@ -498,466 +512,301 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
498
512
|
|
|
499
513
|
export class FacetedSystem {
|
|
500
514
|
constructor() {
|
|
515
|
+
this.bridge = null;
|
|
501
516
|
this.canvas = null;
|
|
502
517
|
this.gl = null;
|
|
503
518
|
this.program = null;
|
|
504
|
-
this.
|
|
505
|
-
this.
|
|
506
|
-
this.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
speed: 1.0,
|
|
514
|
-
hue: 200,
|
|
515
|
-
intensity: 0.7,
|
|
516
|
-
saturation: 0.8,
|
|
517
|
-
dimension: 3.5,
|
|
518
|
-
mouseX: 0.5,
|
|
519
|
-
mouseY: 0.5,
|
|
520
|
-
mouseIntensity: 0.0,
|
|
521
|
-
clickIntensity: 0.0,
|
|
522
|
-
roleIntensity: 1.0,
|
|
523
|
-
bass: 0.0,
|
|
524
|
-
mid: 0.0,
|
|
525
|
-
high: 0.0
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
/** @type {UnifiedRenderBridge|null} */
|
|
529
|
-
this._bridge = null;
|
|
530
|
-
|
|
531
|
-
/** @type {'direct'|'bridge'} Rendering mode */
|
|
532
|
-
this._renderMode = 'direct';
|
|
519
|
+
this.params = {};
|
|
520
|
+
this.initialized = false;
|
|
521
|
+
this.contextLost = false;
|
|
522
|
+
this._animFrame = null;
|
|
523
|
+
this._time = 0;
|
|
524
|
+
this._running = false;
|
|
525
|
+
this._quadBuffer = null;
|
|
526
|
+
this._uniformLocations = {};
|
|
527
|
+
this._useDirectGL = false;
|
|
533
528
|
}
|
|
534
529
|
|
|
530
|
+
// ─── Synchronous Direct WebGL Init (matches Quantum/Holographic pattern) ───
|
|
531
|
+
|
|
535
532
|
/**
|
|
536
|
-
* Initialize with
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
* @param {boolean} [options.preferWebGPU=true]
|
|
540
|
-
* @param {boolean} [options.debug=false]
|
|
541
|
-
* @returns {Promise<boolean>}
|
|
533
|
+
* Initialize directly with WebGL on a given canvas.
|
|
534
|
+
* Synchronous — no async bridge, no WebGPU.
|
|
535
|
+
* This is the preferred path for the landing page and adapters.
|
|
542
536
|
*/
|
|
543
|
-
|
|
537
|
+
initDirect(canvas) {
|
|
544
538
|
this.canvas = canvas;
|
|
545
539
|
try {
|
|
546
|
-
this.
|
|
547
|
-
|
|
548
|
-
// Try loading external shader files first, fall back to inline
|
|
549
|
-
let sources = {
|
|
550
|
-
glslVertex: VERTEX_SHADER_GLSL,
|
|
551
|
-
glslFragment: FRAGMENT_SHADER_GLSL,
|
|
552
|
-
wgslFragment: FRAGMENT_SHADER_WGSL
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
try {
|
|
556
|
-
const external = await shaderLoader.loadShaderPair('faceted', 'faceted/faceted.frag');
|
|
557
|
-
if (external.glslFragment) {
|
|
558
|
-
sources.glslFragment = external.glslFragment;
|
|
559
|
-
}
|
|
560
|
-
if (external.wgslFragment) {
|
|
561
|
-
sources.wgslFragment = external.wgslFragment;
|
|
562
|
-
}
|
|
563
|
-
if (external.glslVertex) {
|
|
564
|
-
sources.glslVertex = external.glslVertex;
|
|
565
|
-
}
|
|
566
|
-
} catch (loadErr) {
|
|
567
|
-
// External load failed — use inline shaders (already set above)
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const compiled = this._bridge.compileShader('faceted', sources);
|
|
571
|
-
|
|
572
|
-
if (!compiled) {
|
|
573
|
-
console.error('Failed to compile faceted shaders via bridge');
|
|
574
|
-
return false;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
this._renderMode = 'bridge';
|
|
578
|
-
console.log(`Faceted System initialized via ${this._bridge.getBackendType()} bridge`);
|
|
579
|
-
return true;
|
|
540
|
+
this.gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
580
541
|
} catch (e) {
|
|
581
|
-
console.
|
|
582
|
-
return this.initialize(canvas);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Initialize faceted system (direct WebGL mode)
|
|
588
|
-
* Finds canvas by ID in DOM (matches reference architecture)
|
|
589
|
-
*/
|
|
590
|
-
initialize(canvasOverride = null) {
|
|
591
|
-
this.canvas = canvasOverride ?? document.getElementById('content-canvas');
|
|
592
|
-
if (!this.canvas) {
|
|
593
|
-
console.error('Faceted canvas (content-canvas) not found in DOM');
|
|
594
|
-
console.log('Looking for canvas IDs:', ['background-canvas', 'shadow-canvas', 'content-canvas', 'highlight-canvas', 'accent-canvas']);
|
|
542
|
+
console.warn('FacetedSystem: WebGL context creation failed', e);
|
|
595
543
|
return false;
|
|
596
544
|
}
|
|
597
|
-
|
|
598
|
-
this.gl = this.canvas.getContext('webgl');
|
|
599
545
|
if (!this.gl) {
|
|
600
|
-
console.
|
|
546
|
+
console.warn('FacetedSystem: WebGL not available');
|
|
601
547
|
return false;
|
|
602
548
|
}
|
|
603
549
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
e.preventDefault();
|
|
609
|
-
this._contextLost = true;
|
|
610
|
-
console.warn('Faceted: WebGL context lost');
|
|
611
|
-
};
|
|
612
|
-
this._onContextRestored = () => {
|
|
613
|
-
console.log('Faceted: WebGL context restored');
|
|
614
|
-
this._contextLost = false;
|
|
615
|
-
this.createShaderProgram();
|
|
616
|
-
};
|
|
617
|
-
this.canvas.addEventListener('webglcontextlost', this._onContextLost);
|
|
618
|
-
this.canvas.addEventListener('webglcontextrestored', this._onContextRestored);
|
|
619
|
-
|
|
620
|
-
if (!this.createShaderProgram()) {
|
|
621
|
-
console.error('Failed to create faceted shader program');
|
|
550
|
+
// Compile shader program
|
|
551
|
+
this.program = this._compileProgram(this.gl, VERTEX_SHADER_GLSL, FRAGMENT_SHADER_GLSL);
|
|
552
|
+
if (!this.program) {
|
|
553
|
+
console.error('FacetedSystem: Shader compilation failed');
|
|
622
554
|
return false;
|
|
623
555
|
}
|
|
624
556
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/**
|
|
632
|
-
* Create shader program with 6D rotation and 24 geometry support
|
|
633
|
-
*/
|
|
634
|
-
createShaderProgram() {
|
|
635
|
-
this.program = this.compileProgram(VERTEX_SHADER_GLSL, FRAGMENT_SHADER_GLSL);
|
|
636
|
-
if (!this.program) return false;
|
|
637
|
-
|
|
638
|
-
// Create fullscreen quad
|
|
639
|
-
const vertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);
|
|
640
|
-
const buffer = this.gl.createBuffer();
|
|
641
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
|
557
|
+
// Create fullscreen quad buffer
|
|
558
|
+
const vertices = new Float32Array([-1,-1, 1,-1, -1,1, -1,1, 1,-1, 1,1]);
|
|
559
|
+
this._quadBuffer = this.gl.createBuffer();
|
|
560
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this._quadBuffer);
|
|
642
561
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
643
562
|
|
|
563
|
+
// Cache uniform locations
|
|
564
|
+
const gl = this.gl;
|
|
565
|
+
const numUniforms = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
|
|
566
|
+
for (let i = 0; i < numUniforms; i++) {
|
|
567
|
+
const info = gl.getActiveUniform(this.program, i);
|
|
568
|
+
if (info) {
|
|
569
|
+
this._uniformLocations[info.name] = gl.getUniformLocation(this.program, info.name);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
this._useDirectGL = true;
|
|
574
|
+
this.initialized = true;
|
|
575
|
+
this.start();
|
|
644
576
|
return true;
|
|
645
577
|
}
|
|
646
578
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const vertexShader = this.compileShader(this.gl.VERTEX_SHADER, vertexSource);
|
|
652
|
-
const fragmentShader = this.compileShader(this.gl.FRAGMENT_SHADER, fragmentSource);
|
|
653
|
-
|
|
654
|
-
if (!vertexShader || !fragmentShader) return null;
|
|
579
|
+
_compileProgram(gl, vertexSrc, fragmentSrc) {
|
|
580
|
+
const vs = this._compileShader(gl, gl.VERTEX_SHADER, vertexSrc);
|
|
581
|
+
const fs = this._compileShader(gl, gl.FRAGMENT_SHADER, fragmentSrc);
|
|
582
|
+
if (!vs || !fs) return null;
|
|
655
583
|
|
|
656
|
-
const program =
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
584
|
+
const program = gl.createProgram();
|
|
585
|
+
gl.attachShader(program, vs);
|
|
586
|
+
gl.attachShader(program, fs);
|
|
587
|
+
gl.linkProgram(program);
|
|
660
588
|
|
|
661
|
-
if (!
|
|
662
|
-
console.error('
|
|
589
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
590
|
+
console.error('FacetedSystem link error:', gl.getProgramInfoLog(program));
|
|
663
591
|
return null;
|
|
664
592
|
}
|
|
665
593
|
|
|
594
|
+
gl.deleteShader(vs);
|
|
595
|
+
gl.deleteShader(fs);
|
|
666
596
|
return program;
|
|
667
597
|
}
|
|
668
598
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
|
678
|
-
console.error('Shader compile error:', this.gl.getShaderInfoLog(shader));
|
|
599
|
+
_compileShader(gl, type, source) {
|
|
600
|
+
const shader = gl.createShader(type);
|
|
601
|
+
gl.shaderSource(shader, source);
|
|
602
|
+
gl.compileShader(shader);
|
|
603
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
604
|
+
console.error('FacetedSystem shader error:', gl.getShaderInfoLog(shader));
|
|
605
|
+
gl.deleteShader(shader);
|
|
679
606
|
return null;
|
|
680
607
|
}
|
|
681
|
-
|
|
682
608
|
return shader;
|
|
683
609
|
}
|
|
684
610
|
|
|
685
|
-
|
|
686
|
-
* Setup canvas size
|
|
687
|
-
*/
|
|
688
|
-
setupCanvasSize() {
|
|
689
|
-
const rect = this.canvas.parentElement.getBoundingClientRect();
|
|
690
|
-
this.canvas.width = rect.width || 800;
|
|
691
|
-
this.canvas.height = rect.height || 600;
|
|
692
|
-
if (this.gl) {
|
|
693
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
611
|
+
// ─── Async Bridge Init (for SDK/WebGPU usage) ───
|
|
696
612
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
613
|
+
async initWithBridge(canvas, options) {
|
|
614
|
+
this.canvas = canvas;
|
|
615
|
+
try {
|
|
616
|
+
this.bridge = await UnifiedRenderBridge.create(canvas, options);
|
|
617
|
+
if (this.bridge) {
|
|
618
|
+
const success = this.bridge.compileShader('faceted', {
|
|
619
|
+
glslVertex: VERTEX_SHADER_GLSL,
|
|
620
|
+
glslFragment: FRAGMENT_SHADER_GLSL,
|
|
621
|
+
wgslFragment: FRAGMENT_SHADER_WGSL
|
|
622
|
+
});
|
|
623
|
+
if (!success) {
|
|
624
|
+
console.error("Faceted shader compilation failed");
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
this.initialized = true;
|
|
628
|
+
this.start();
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
} catch (e) {
|
|
632
|
+
console.error("Faceted initWithBridge failed:", e);
|
|
633
|
+
}
|
|
634
|
+
return false;
|
|
712
635
|
}
|
|
713
636
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if (
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
this.stop();
|
|
637
|
+
async initialize() {
|
|
638
|
+
if (this.initialized) return true;
|
|
639
|
+
const canvas = document.getElementById('faceted-content-canvas') ||
|
|
640
|
+
document.getElementById('content-canvas');
|
|
641
|
+
if (!canvas) {
|
|
642
|
+
console.warn("FacetedSystem: No canvas found for initialize()");
|
|
643
|
+
return false;
|
|
722
644
|
}
|
|
645
|
+
return this.initWithBridge(canvas, { preferWebGPU: false });
|
|
723
646
|
}
|
|
724
647
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
if (this._renderMode === 'bridge' && this._bridge) {
|
|
731
|
-
return this._bridge.getBackendType();
|
|
732
|
-
}
|
|
733
|
-
return 'direct-webgl';
|
|
648
|
+
// ─── Parameters ───
|
|
649
|
+
|
|
650
|
+
updateParameters(params) {
|
|
651
|
+
if (!params) return;
|
|
652
|
+
this.params = { ...this.params, ...params };
|
|
734
653
|
}
|
|
735
654
|
|
|
736
655
|
/**
|
|
737
|
-
* Build uniform object for
|
|
738
|
-
* @private
|
|
656
|
+
* Build the uniform object with proper u_ prefixed names for the shader.
|
|
739
657
|
*/
|
|
740
658
|
_buildUniforms() {
|
|
659
|
+
const p = this.params;
|
|
741
660
|
return {
|
|
742
|
-
u_time: this.
|
|
743
|
-
u_resolution: [this.canvas
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
661
|
+
u_time: this._time,
|
|
662
|
+
u_resolution: [this.canvas?.width || 800, this.canvas?.height || 600],
|
|
663
|
+
u_geometry: p.geometry ?? 0,
|
|
664
|
+
u_rot4dXY: p.rot4dXY ?? 0,
|
|
665
|
+
u_rot4dXZ: p.rot4dXZ ?? 0,
|
|
666
|
+
u_rot4dYZ: p.rot4dYZ ?? 0,
|
|
667
|
+
u_rot4dXW: p.rot4dXW ?? 0,
|
|
668
|
+
u_rot4dYW: p.rot4dYW ?? 0,
|
|
669
|
+
u_rot4dZW: p.rot4dZW ?? 0,
|
|
670
|
+
u_dimension: p.dimension ?? 3.5,
|
|
671
|
+
u_gridDensity: p.gridDensity ?? 15,
|
|
672
|
+
u_morphFactor: p.morphFactor ?? 1.0,
|
|
673
|
+
u_chaos: p.chaos ?? 0.2,
|
|
674
|
+
u_speed: p.speed ?? 1.0,
|
|
675
|
+
u_hue: p.hue ?? 200,
|
|
676
|
+
u_intensity: p.intensity ?? 0.7,
|
|
677
|
+
u_saturation: p.saturation ?? 0.8,
|
|
678
|
+
u_mouseIntensity: p.mouseIntensity ?? 0,
|
|
679
|
+
u_clickIntensity: p.clickIntensity ?? 0,
|
|
680
|
+
u_bass: p.bass ?? 0,
|
|
681
|
+
u_mid: p.mid ?? 0,
|
|
682
|
+
u_high: p.high ?? 0,
|
|
683
|
+
u_breath: p.breath ?? 0,
|
|
684
|
+
u_mouse: p.mouse ?? [0.5, 0.5],
|
|
766
685
|
};
|
|
767
686
|
}
|
|
768
687
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
this._bridge.setUniforms(this._buildUniforms());
|
|
776
|
-
this._bridge.render('faceted');
|
|
688
|
+
// ─── Render Loop ───
|
|
689
|
+
|
|
690
|
+
start() {
|
|
691
|
+
if (this._running) return;
|
|
692
|
+
this._running = true;
|
|
693
|
+
this._renderLoop();
|
|
777
694
|
}
|
|
778
695
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
if (!this.gl || !this.program || this._contextLost) return;
|
|
785
|
-
if (this.gl.isContextLost()) {
|
|
786
|
-
this._contextLost = true;
|
|
787
|
-
return;
|
|
696
|
+
stop() {
|
|
697
|
+
this._running = false;
|
|
698
|
+
if (this._animFrame) {
|
|
699
|
+
cancelAnimationFrame(this._animFrame);
|
|
700
|
+
this._animFrame = null;
|
|
788
701
|
}
|
|
789
|
-
|
|
790
|
-
this.gl.useProgram(this.program);
|
|
791
|
-
this.gl.enable(this.gl.BLEND);
|
|
792
|
-
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
793
|
-
|
|
794
|
-
this.gl.clearColor(0, 0, 0, 1);
|
|
795
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
796
|
-
|
|
797
|
-
const uniforms = this._buildUniforms();
|
|
798
|
-
|
|
799
|
-
Object.entries(uniforms).forEach(([name, value]) => {
|
|
800
|
-
const location = this.gl.getUniformLocation(this.program, name);
|
|
801
|
-
if (location !== null) {
|
|
802
|
-
if (Array.isArray(value)) {
|
|
803
|
-
this.gl.uniform2fv(location, value);
|
|
804
|
-
} else {
|
|
805
|
-
this.gl.uniform1f(location, value);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
// Draw fullscreen quad
|
|
811
|
-
const posLocation = this.gl.getAttribLocation(this.program, 'a_position');
|
|
812
|
-
this.gl.enableVertexAttribArray(posLocation);
|
|
813
|
-
this.gl.vertexAttribPointer(posLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
814
|
-
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
|
815
702
|
}
|
|
816
703
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
*/
|
|
820
|
-
renderFrame() {
|
|
821
|
-
if (!this.isActive) return;
|
|
822
|
-
|
|
823
|
-
// Apply audio reactivity
|
|
824
|
-
if (window.audioEnabled && window.audioReactive) {
|
|
825
|
-
this.parameters.bass = window.audioReactive.bass || 0;
|
|
826
|
-
this.parameters.mid = window.audioReactive.mid || 0;
|
|
827
|
-
this.parameters.high = window.audioReactive.high || 0;
|
|
828
|
-
}
|
|
704
|
+
_renderLoop() {
|
|
705
|
+
if (!this._running) return;
|
|
829
706
|
|
|
830
|
-
this.
|
|
707
|
+
this._time += 16.0 * (this.params.speed ?? 1.0);
|
|
831
708
|
|
|
832
|
-
if (this.
|
|
833
|
-
this.
|
|
834
|
-
} else {
|
|
835
|
-
this.
|
|
709
|
+
if (this._useDirectGL) {
|
|
710
|
+
this._renderDirectGL();
|
|
711
|
+
} else if (this.bridge) {
|
|
712
|
+
this.bridge.setUniforms(this._buildUniforms());
|
|
713
|
+
this.bridge.render('faceted', { clear: true, clearColor: [0, 0, 0, 1] });
|
|
836
714
|
}
|
|
715
|
+
|
|
716
|
+
this._animFrame = requestAnimationFrame(() => this._renderLoop());
|
|
837
717
|
}
|
|
838
718
|
|
|
839
719
|
/**
|
|
840
|
-
*
|
|
720
|
+
* Direct WebGL rendering — no bridge, just raw GL calls.
|
|
721
|
+
* Matches the original working FacetedSystem pattern.
|
|
841
722
|
*/
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (
|
|
845
|
-
Object.assign(this.parameters, frameState.params);
|
|
846
|
-
}
|
|
847
|
-
if (typeof frameState.time === 'number') {
|
|
848
|
-
this.time = frameState.time;
|
|
849
|
-
}
|
|
723
|
+
_renderDirectGL() {
|
|
724
|
+
const gl = this.gl;
|
|
725
|
+
if (!gl || !this.program) return;
|
|
850
726
|
|
|
851
|
-
this.
|
|
727
|
+
gl.useProgram(this.program);
|
|
728
|
+
gl.enable(gl.BLEND);
|
|
729
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
730
|
+
gl.clearColor(0, 0, 0, 1);
|
|
731
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
852
732
|
|
|
853
|
-
|
|
854
|
-
|
|
733
|
+
// Set uniforms
|
|
734
|
+
const uniforms = this._buildUniforms();
|
|
735
|
+
for (const [name, value] of Object.entries(uniforms)) {
|
|
736
|
+
const loc = this._uniformLocations[name];
|
|
737
|
+
if (loc === null || loc === undefined) continue;
|
|
738
|
+
if (Array.isArray(value)) {
|
|
739
|
+
if (value.length === 2) gl.uniform2fv(loc, value);
|
|
740
|
+
else if (value.length === 3) gl.uniform3fv(loc, value);
|
|
741
|
+
else if (value.length === 4) gl.uniform4fv(loc, value);
|
|
742
|
+
} else {
|
|
743
|
+
gl.uniform1f(loc, value);
|
|
744
|
+
}
|
|
855
745
|
}
|
|
856
|
-
}
|
|
857
746
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
// Only accept finite numbers to prevent NaN/Infinity reaching shaders
|
|
865
|
-
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
866
|
-
this.parameters[key] = value;
|
|
867
|
-
}
|
|
747
|
+
// Draw fullscreen quad
|
|
748
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._quadBuffer);
|
|
749
|
+
const posLoc = gl.getAttribLocation(this.program, 'a_position');
|
|
750
|
+
if (posLoc >= 0) {
|
|
751
|
+
gl.enableVertexAttribArray(posLoc);
|
|
752
|
+
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
|
868
753
|
}
|
|
754
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
869
755
|
}
|
|
870
756
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
* @param {Object} [context] - Optional context with canvas or canvasId
|
|
878
|
-
* @returns {boolean|Promise<boolean>} Success status
|
|
879
|
-
*/
|
|
880
|
-
init(context = {}) {
|
|
881
|
-
const canvasOverride = context.canvas ||
|
|
882
|
-
(context.canvasId ? document.getElementById(context.canvasId) : null);
|
|
883
|
-
|
|
884
|
-
// If preferWebGPU is set and canvas is provided, use bridge mode
|
|
885
|
-
if (context.preferWebGPU && canvasOverride) {
|
|
886
|
-
return this.initWithBridge(canvasOverride, {
|
|
887
|
-
preferWebGPU: true,
|
|
888
|
-
debug: context.debug
|
|
889
|
-
});
|
|
757
|
+
render() {
|
|
758
|
+
if (this._useDirectGL) {
|
|
759
|
+
this._renderDirectGL();
|
|
760
|
+
} else if (this.bridge) {
|
|
761
|
+
this.bridge.setUniforms(this._buildUniforms());
|
|
762
|
+
this.bridge.render('faceted', { clear: true, clearColor: [0, 0, 0, 1] });
|
|
890
763
|
}
|
|
764
|
+
}
|
|
891
765
|
|
|
892
|
-
|
|
766
|
+
getBackendType() {
|
|
767
|
+
if (this._useDirectGL) return 'webgl';
|
|
768
|
+
return this.bridge ? this.bridge.getBackendType() : 'none';
|
|
893
769
|
}
|
|
894
770
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
*/
|
|
901
|
-
resize(width, height, pixelRatio = 1) {
|
|
902
|
-
if (!this.canvas) return;
|
|
903
|
-
|
|
904
|
-
if (this._renderMode === 'bridge' && this._bridge) {
|
|
905
|
-
this._bridge.resize(width, height, pixelRatio);
|
|
906
|
-
} else if (this.gl) {
|
|
907
|
-
this.canvas.width = width * pixelRatio;
|
|
908
|
-
this.canvas.height = height * pixelRatio;
|
|
909
|
-
this.canvas.style.width = `${width}px`;
|
|
910
|
-
this.canvas.style.height = `${height}px`;
|
|
911
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
912
|
-
}
|
|
771
|
+
setActive(active) {
|
|
772
|
+
if (active) this.start();
|
|
773
|
+
else this.stop();
|
|
774
|
+
const layer = document.getElementById('faceted-layer');
|
|
775
|
+
if (layer) layer.style.display = active ? 'block' : 'none';
|
|
913
776
|
}
|
|
914
777
|
|
|
915
|
-
|
|
916
|
-
* Clean up all resources (RendererContract.dispose)
|
|
917
|
-
*/
|
|
918
|
-
dispose() {
|
|
919
|
-
this.isActive = false;
|
|
778
|
+
init(context) { return this.initialize(); }
|
|
920
779
|
|
|
921
|
-
|
|
780
|
+
resize(width, height, pixelRatio = 1) {
|
|
781
|
+
const w = Math.floor(width * pixelRatio);
|
|
782
|
+
const h = Math.floor(height * pixelRatio);
|
|
922
783
|
if (this.canvas) {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
926
|
-
if (this._onContextRestored) {
|
|
927
|
-
this.canvas.removeEventListener('webglcontextrestored', this._onContextRestored);
|
|
928
|
-
}
|
|
784
|
+
this.canvas.width = w;
|
|
785
|
+
this.canvas.height = h;
|
|
929
786
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
this.
|
|
787
|
+
if (this._useDirectGL && this.gl) {
|
|
788
|
+
this.gl.viewport(0, 0, w, h);
|
|
789
|
+
} else if (this.bridge && this.bridge.resize) {
|
|
790
|
+
this.bridge.resize(width, height, pixelRatio);
|
|
934
791
|
}
|
|
792
|
+
}
|
|
935
793
|
|
|
936
|
-
|
|
937
|
-
if (this.program) {
|
|
938
|
-
this.gl.deleteProgram(this.program);
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
this.program = null;
|
|
794
|
+
dispose() { this.destroy(); }
|
|
942
795
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
796
|
+
destroy() {
|
|
797
|
+
this.stop();
|
|
798
|
+
if (this._useDirectGL && this.gl) {
|
|
799
|
+
if (this.program) this.gl.deleteProgram(this.program);
|
|
800
|
+
if (this._quadBuffer) this.gl.deleteBuffer(this._quadBuffer);
|
|
948
801
|
this.gl = null;
|
|
802
|
+
this.program = null;
|
|
803
|
+
this._quadBuffer = null;
|
|
949
804
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
* Alias for dispose (for backward compatibility)
|
|
959
|
-
*/
|
|
960
|
-
destroy() {
|
|
961
|
-
this.dispose();
|
|
805
|
+
if (this.bridge) {
|
|
806
|
+
this.bridge.dispose();
|
|
807
|
+
this.bridge = null;
|
|
808
|
+
}
|
|
809
|
+
this.initialized = false;
|
|
810
|
+
this._useDirectGL = false;
|
|
962
811
|
}
|
|
963
812
|
}
|