@vib3code/sdk 2.0.1 → 2.0.3-canary.91a95f3
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 +114 -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
|
@@ -9,7 +9,8 @@ uniform vec2 u_resolution;
|
|
|
9
9
|
uniform float u_time;
|
|
10
10
|
uniform vec2 u_mouse;
|
|
11
11
|
uniform float u_geometry;
|
|
12
|
-
uniform float u_density;
|
|
12
|
+
uniform float u_density; // Used by inline visualizer (scaled 0.3-2.5)
|
|
13
|
+
uniform float u_gridDensity; // Used by bridge/external (raw 5-100)
|
|
13
14
|
uniform float u_speed;
|
|
14
15
|
uniform vec3 u_color;
|
|
15
16
|
uniform float u_intensity;
|
|
@@ -40,6 +41,9 @@ uniform float u_rot4dXW;
|
|
|
40
41
|
uniform float u_rot4dYW;
|
|
41
42
|
uniform float u_rot4dZW;
|
|
42
43
|
|
|
44
|
+
// EXHALE FEATURE: Breathing uniform
|
|
45
|
+
uniform float u_breath;
|
|
46
|
+
|
|
43
47
|
// 6D rotation matrices - 3D space rotations (XY, XZ, YZ)
|
|
44
48
|
mat4 rotateXY(float theta) {
|
|
45
49
|
float c = cos(theta);
|
|
@@ -78,9 +82,12 @@ mat4 rotateZW(float theta) {
|
|
|
78
82
|
return mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, c, -s, 0, 0, s, c);
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
// 4D to 3D projection
|
|
85
|
+
// 4D to 3D projection - BREATHING EFFECT
|
|
82
86
|
vec3 project4Dto3D(vec4 p) {
|
|
83
|
-
|
|
87
|
+
// Modulate projection distance with breath for "exhale" effect (expansion/contraction)
|
|
88
|
+
float baseDim = 2.5;
|
|
89
|
+
float dim = baseDim + u_breath * 0.5; // Expands on exhale
|
|
90
|
+
float w = dim / (dim + p.w);
|
|
84
91
|
return vec3(p.x * w, p.y * w, p.z * w);
|
|
85
92
|
}
|
|
86
93
|
|
|
@@ -227,10 +234,10 @@ float torusLattice(vec3 p, float gridSize) {
|
|
|
227
234
|
|
|
228
235
|
float kleinLattice(vec3 p, float gridSize) {
|
|
229
236
|
vec3 q = fract(p * gridSize);
|
|
230
|
-
float
|
|
231
|
-
float
|
|
232
|
-
float
|
|
233
|
-
float klein = length(vec2(
|
|
237
|
+
float u = q.x * 2.0 * 3.14159;
|
|
238
|
+
float v = q.y * 2.0 * 3.14159;
|
|
239
|
+
float x = cos(u) * (3.0 + cos(u/2.0) * sin(v) - sin(u/2.0) * sin(2.0*v));
|
|
240
|
+
float klein = length(vec2(x, q.z)) - 0.1;
|
|
234
241
|
return 1.0 - smoothstep(0.0, 0.05, abs(klein));
|
|
235
242
|
}
|
|
236
243
|
|
|
@@ -345,8 +352,17 @@ void main() {
|
|
|
345
352
|
|
|
346
353
|
float scrollDensityMod = 1.0 + u_gridDensityShift * 0.3;
|
|
347
354
|
float audioDensityMod = 1.0 + u_audioDensityBoost * 0.5;
|
|
348
|
-
|
|
349
|
-
|
|
355
|
+
|
|
356
|
+
// SCALE FIX: Support raw gridDensity (5-100) or pre-scaled density (0.3-2.5)
|
|
357
|
+
float effectiveDensity = u_density;
|
|
358
|
+
if (u_gridDensity > 0.1) {
|
|
359
|
+
// Convert 5-100 to 0.3-2.5
|
|
360
|
+
effectiveDensity = 0.3 + (u_gridDensity - 5.0) / 95.0 * 2.2;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
float breathDensityMod = 1.0 + u_breath * 0.1;
|
|
364
|
+
float baseDensity = effectiveDensity * u_roleDensity * breathDensityMod;
|
|
365
|
+
|
|
350
366
|
float densityVariations = (u_densityVariation * 0.3 + (scrollDensityMod - 1.0) * 0.4 + (audioDensityMod - 1.0) * 0.2);
|
|
351
367
|
float roleDensity = baseDensity + densityVariations;
|
|
352
368
|
|
|
@@ -357,6 +373,9 @@ void main() {
|
|
|
357
373
|
vec3 baseColor = u_color;
|
|
358
374
|
float latticeIntensity = lattice * u_intensity;
|
|
359
375
|
|
|
376
|
+
// Breathing glow effect
|
|
377
|
+
latticeIntensity *= (1.0 + u_breath * 0.2);
|
|
378
|
+
|
|
360
379
|
// Multi-layer color composition for higher fidelity
|
|
361
380
|
vec3 color = baseColor * (0.2 + latticeIntensity * 0.8);
|
|
362
381
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// VIB3+ Holographic System Fragment Shader (WGSL)
|
|
2
2
|
// 5-layer glassmorphic audio-reactive effects
|
|
3
|
-
// Port of the GLSL HolographicVisualizer shader
|
|
3
|
+
// Port of the GLSL HolographicVisualizer shader with Exhale feature
|
|
4
4
|
|
|
5
5
|
struct VIB3Uniforms {
|
|
6
6
|
time: f32,
|
|
@@ -28,7 +28,7 @@ struct VIB3Uniforms {
|
|
|
28
28
|
high: f32,
|
|
29
29
|
layerScale: f32,
|
|
30
30
|
layerOpacity: f32,
|
|
31
|
-
|
|
31
|
+
breath: f32,
|
|
32
32
|
layerColor: vec3<f32>,
|
|
33
33
|
densityMult: f32,
|
|
34
34
|
speedMult: f32,
|
|
@@ -91,42 +91,91 @@ fn apply6DRot(pos: vec4<f32>) -> vec4<f32> {
|
|
|
91
91
|
return p;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
// ==========
|
|
95
|
-
fn
|
|
96
|
-
|
|
94
|
+
// ========== 4D to 3D Projection (Breathing) ==========
|
|
95
|
+
fn project4Dto3D_w(p: vec4<f32>) -> vec3<f32> {
|
|
96
|
+
// Modulate projection with breath
|
|
97
|
+
let baseDim = 2.5;
|
|
98
|
+
let dim = baseDim + u.breath * 0.5;
|
|
99
|
+
let w = dim / (dim + p.w);
|
|
100
|
+
return vec3<f32>(p.x * w, p.y * w, p.z * w);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ========== Polytope Core Warp Functions ==========
|
|
104
|
+
fn warpHypersphereCore_w(p: vec3<f32>, geomIdx: i32) -> vec3<f32> {
|
|
105
|
+
let radius = length(p);
|
|
106
|
+
let morphBlend = clamp(u.morphFactor * 0.6 + 0.3, 0.0, 2.0);
|
|
107
|
+
let w = sin(radius * (1.3 + f32(geomIdx) * 0.12) + u.time * 0.0008 * u.speed)
|
|
108
|
+
* (0.4 + morphBlend * 0.45);
|
|
109
|
+
|
|
110
|
+
var p4d = vec4<f32>(p * (1.0 + morphBlend * 0.2), w);
|
|
111
|
+
p4d = apply6DRot(p4d); // Reuse rotation helper
|
|
112
|
+
|
|
113
|
+
let proj = project4Dto3D_w(p4d);
|
|
114
|
+
return mix(p, proj, clamp(0.45 + morphBlend * 0.35, 0.0, 1.0));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fn warpHypertetraCore_w(p: vec3<f32>, geomIdx: i32) -> vec3<f32> {
|
|
118
|
+
let c1 = normalize(vec3<f32>(1.0, 1.0, 1.0));
|
|
119
|
+
let c2 = normalize(vec3<f32>(-1.0, -1.0, 1.0));
|
|
120
|
+
let c3 = normalize(vec3<f32>(-1.0, 1.0, -1.0));
|
|
121
|
+
let c4 = normalize(vec3<f32>(1.0, -1.0, -1.0));
|
|
122
|
+
|
|
123
|
+
let morphBlend = clamp(u.morphFactor * 0.8 + 0.2, 0.0, 2.0);
|
|
124
|
+
let basisMix = dot(p, c1) * 0.14 + dot(p, c2) * 0.1 + dot(p, c3) * 0.08;
|
|
125
|
+
let w = sin(basisMix * 5.5 + u.time * 0.0009 * u.speed)
|
|
126
|
+
* cos(dot(p, c4) * 4.2 - u.time * 0.0007 * u.speed)
|
|
127
|
+
* (0.5 + morphBlend * 0.4);
|
|
128
|
+
|
|
129
|
+
let offset = vec3<f32>(dot(p, c1), dot(p, c2), dot(p, c3)) * 0.1 * morphBlend;
|
|
130
|
+
var p4d = vec4<f32>(p + offset, w);
|
|
131
|
+
p4d = apply6DRot(p4d);
|
|
132
|
+
|
|
133
|
+
let proj = project4Dto3D_w(p4d);
|
|
134
|
+
|
|
135
|
+
let planeInf = min(min(abs(dot(p, c1)), abs(dot(p, c2))),
|
|
136
|
+
min(abs(dot(p, c3)), abs(dot(p, c4))));
|
|
137
|
+
let blended = mix(p, proj, clamp(0.45 + morphBlend * 0.35, 0.0, 1.0));
|
|
138
|
+
return mix(blended, blended * (1.0 - planeInf * 0.55), 0.2 + morphBlend * 0.2);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fn applyCoreWarp_w(p: vec3<f32>, geomType: f32) -> vec3<f32> {
|
|
142
|
+
let totalBase = 8.0;
|
|
143
|
+
let coreFloat = floor(geomType / totalBase);
|
|
144
|
+
let coreIndex = i32(clamp(coreFloat, 0.0, 2.0));
|
|
145
|
+
let baseFloat = geomType - floor(geomType / totalBase) * totalBase;
|
|
146
|
+
let geomIdx = i32(clamp(floor(baseFloat + 0.5), 0.0, totalBase - 1.0));
|
|
147
|
+
|
|
148
|
+
if (coreIndex == 1) { return warpHypersphereCore_w(p, geomIdx); }
|
|
149
|
+
if (coreIndex == 2) { return warpHypertetraCore_w(p, geomIdx); }
|
|
150
|
+
return p;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ========== 24 Geometry SDFs (Base 8) ==========
|
|
154
|
+
fn baseGeometry(p: vec3<f32>, t: f32) -> f32 {
|
|
155
|
+
let totalBase = 8.0;
|
|
156
|
+
let baseFloat = t - floor(t / totalBase) * totalBase;
|
|
157
|
+
// We use integer comparison here since WGSL doesn't like float switches
|
|
158
|
+
if (baseFloat < 0.5) { // Tetrahedron
|
|
97
159
|
return max(max(max(abs(p.x + p.y) - p.z, abs(p.x - p.y) - p.z),
|
|
98
160
|
abs(p.x + p.y) + p.z), abs(p.x - p.y) + p.z) / sqrt(3.0);
|
|
99
|
-
} else if (
|
|
100
|
-
let q = abs(p) -
|
|
101
|
-
return length(max(q,
|
|
102
|
-
} else if (
|
|
161
|
+
} else if (baseFloat < 1.5) { // Hypercube (projected)
|
|
162
|
+
let q = abs(p) - vec3<f32>(0.8);
|
|
163
|
+
return length(max(q, vec3<f32>(0.0))) + min(max(max(q.x, q.y), q.z), 0.0);
|
|
164
|
+
} else if (baseFloat < 2.5) { // Sphere
|
|
103
165
|
return length(p) - 1.0;
|
|
104
|
-
} else if (
|
|
166
|
+
} else if (baseFloat < 3.5) { // Torus
|
|
105
167
|
let t2 = vec2<f32>(length(p.xy) - 0.8, p.z);
|
|
106
168
|
return length(t2) - 0.3;
|
|
107
|
-
} else if (
|
|
169
|
+
} else if (baseFloat < 4.5) { // Klein
|
|
108
170
|
let r = length(p.xy);
|
|
109
171
|
return abs(r - 0.7) - 0.2 + sin(atan2(p.y, p.x) * 3.0 + p.z * 5.0) * 0.1;
|
|
110
|
-
} else if (
|
|
172
|
+
} else if (baseFloat < 5.5) { // Fractal
|
|
111
173
|
return length(p) - 0.8 + sin(p.x * 5.0) * sin(p.y * 5.0) * sin(p.z * 5.0) * 0.2;
|
|
112
|
-
} else if (
|
|
174
|
+
} else if (baseFloat < 6.5) { // Wave
|
|
113
175
|
return abs(p.z - sin(p.x * 5.0 + u.time) * cos(p.y * 5.0 + u.time) * 0.3) - 0.1;
|
|
114
|
-
} else {
|
|
176
|
+
} else { // Crystal
|
|
115
177
|
let q = abs(p);
|
|
116
|
-
return max(max(
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
fn geom(p: vec4<f32>, t: f32) -> f32 {
|
|
121
|
-
if (t < 8.0) { return baseGeometry(p, t); }
|
|
122
|
-
else if (t < 16.0) { return max(baseGeometry(p, t - 8.0), length(p) - 1.2); }
|
|
123
|
-
else {
|
|
124
|
-
let tf = max(max(max(
|
|
125
|
-
abs(p.x + p.y) - p.z - p.w,
|
|
126
|
-
abs(p.x - p.y) - p.z + p.w),
|
|
127
|
-
abs(p.x + p.y) + p.z - p.w),
|
|
128
|
-
abs(p.x - p.y) + p.z + p.w) / sqrt(4.0);
|
|
129
|
-
return max(baseGeometry(p, t - 16.0), tf);
|
|
178
|
+
return max(max(q.x, q.y), q.z) - 0.8;
|
|
130
179
|
}
|
|
131
180
|
}
|
|
132
181
|
|
|
@@ -161,25 +210,45 @@ fn main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
161
210
|
let density = u.densityMult;
|
|
162
211
|
let spd = u.speedMult;
|
|
163
212
|
|
|
164
|
-
// Create 4D point
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
213
|
+
// Create 4D point (simplified to 3D base + W)
|
|
214
|
+
// SCALE FIX: Apply gridDensity scaling if densityMult is weak?
|
|
215
|
+
// WGSL density logic usually relies on densityMult passed by bridge.
|
|
216
|
+
// But let's apply the same scaling logic just in case:
|
|
217
|
+
var effectiveDensity = density;
|
|
218
|
+
if (u.gridDensity > 0.1 && density < 0.5) {
|
|
219
|
+
effectiveDensity = 0.3 + (u.gridDensity - 5.0) / 95.0 * 2.2;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
var pos4d = vec4<f32>(uv * 2.0 * effectiveDensity, sin(u.time * 0.3 * spd) * 0.5, cos(u.time * 0.2 * spd) * 0.5);
|
|
223
|
+
|
|
224
|
+
// Rotate
|
|
225
|
+
pos4d = apply6DRot(pos4d);
|
|
226
|
+
|
|
227
|
+
// Project to 3D (with breath)
|
|
228
|
+
let pos3d = project4Dto3D_w(pos4d);
|
|
229
|
+
|
|
230
|
+
// Warp (Polytope logic)
|
|
231
|
+
var warpedPos = applyCoreWarp_w(pos3d, u.geometry);
|
|
232
|
+
|
|
233
|
+
// Apply morph/chaos to warped point
|
|
234
|
+
warpedPos *= u.morphFactor;
|
|
235
|
+
warpedPos += vec3<f32>(sin(u.time * 0.1), cos(u.time * 0.15), sin(u.time * 0.12)) * u.chaos;
|
|
236
|
+
|
|
237
|
+
// Geometry evaluation on warped 3D point
|
|
238
|
+
let dist = baseGeometry(warpedPos, u.geometry);
|
|
169
239
|
|
|
170
|
-
// Geometry evaluation
|
|
171
|
-
let dist = geom(pos, u.geometry);
|
|
172
240
|
let edge = smoothstep(0.02, 0.0, abs(dist));
|
|
173
241
|
let fill = smoothstep(0.1, 0.0, dist) * 0.3;
|
|
174
242
|
|
|
175
243
|
// Color from HSL
|
|
176
|
-
// colorShift is baked into layerColor; use hue directly
|
|
177
244
|
let hueVal = u.hue / 360.0;
|
|
178
245
|
let sat = clamp(u.saturation, 0.0, 1.0);
|
|
179
246
|
let lightness = clamp(u.intensity, 0.2, 0.8);
|
|
180
247
|
let color = hslToRgb(hueVal, sat, lightness);
|
|
181
248
|
|
|
182
|
-
// Final alpha
|
|
183
|
-
let
|
|
249
|
+
// Final alpha - modulate with breath
|
|
250
|
+
let breathAlpha = 1.0 + u.breath * 0.2;
|
|
251
|
+
let alpha = (edge + fill) * u.intensity * u.layerOpacity * breathAlpha;
|
|
252
|
+
|
|
184
253
|
return vec4<f32>(color * alpha, alpha);
|
|
185
254
|
}
|
|
@@ -30,6 +30,7 @@ uniform float u_rot4dZW;
|
|
|
30
30
|
uniform float u_mouseIntensity;
|
|
31
31
|
uniform float u_clickIntensity;
|
|
32
32
|
uniform float u_roleIntensity;
|
|
33
|
+
uniform float u_breath; // Vitality System exhale (0.0 - 1.0)
|
|
33
34
|
|
|
34
35
|
// 6D rotation matrices - 3D space rotations (XY, XZ, YZ)
|
|
35
36
|
mat4 rotateXY(float theta) {
|
package/src/viewer/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export { ViewerPortal, ViewerMode, ProjectionMode } from './ViewerPortal.js';
|
|
8
|
-
export { ReactivityManager } from './
|
|
8
|
+
export { ReactivityManager } from './ViewerInputHandler.js';
|
|
9
9
|
export { CardBending, BendPreset } from './CardBending.js';
|
|
10
10
|
export { TradingCardExporter, CardSize, FrameStyle, Rarity } from './TradingCardExporter.js';
|
|
11
11
|
export { AudioReactivity, AudioSource, FrequencyBand } from './AudioReactivity.js';
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* headless-renderer.js - VIB3+ Headless Frame Capture Utility
|
|
5
|
+
*
|
|
6
|
+
* Uses Puppeteer to render VIB3+ visualizations in a headless browser and
|
|
7
|
+
* capture screenshots. Designed for:
|
|
8
|
+
* - Agent visual feedback loops (capture → analyze → refine)
|
|
9
|
+
* - CI visual regression testing
|
|
10
|
+
* - Thumbnail generation for gallery entries
|
|
11
|
+
* - Offline batch rendering
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node tools/headless-renderer.js [options]
|
|
15
|
+
*
|
|
16
|
+
* Options:
|
|
17
|
+
* --url <url> Dev server URL (default: http://localhost:5173)
|
|
18
|
+
* --output <path> Output directory (default: ./renders)
|
|
19
|
+
* --width <px> Viewport width (default: 512)
|
|
20
|
+
* --height <px> Viewport height (default: 512)
|
|
21
|
+
* --params <json> JSON parameter object to apply
|
|
22
|
+
* --system <name> System: quantum|faceted|holographic
|
|
23
|
+
* --geometry <index> Geometry index 0-23
|
|
24
|
+
* --delay <ms> Wait time after parameter set (default: 500)
|
|
25
|
+
* --frames <count> Number of frames to capture (default: 1)
|
|
26
|
+
* --interval <ms> Interval between frames (default: 100)
|
|
27
|
+
* --format <type> png|jpeg|webp (default: png)
|
|
28
|
+
* --base64 Output base64 to stdout instead of file
|
|
29
|
+
*
|
|
30
|
+
* Examples:
|
|
31
|
+
* # Single frame with custom params
|
|
32
|
+
* node tools/headless-renderer.js --system quantum --geometry 11 --params '{"hue":200,"chaos":0.3}'
|
|
33
|
+
*
|
|
34
|
+
* # 10 frames of animation
|
|
35
|
+
* node tools/headless-renderer.js --frames 10 --interval 200 --output ./animation
|
|
36
|
+
*
|
|
37
|
+
* # Base64 output for piping to agents
|
|
38
|
+
* node tools/headless-renderer.js --base64 --params '{"hue":120}'
|
|
39
|
+
*
|
|
40
|
+
* @module tools/headless-renderer
|
|
41
|
+
* @version 1.0.0
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
45
|
+
import { join, resolve } from 'path';
|
|
46
|
+
|
|
47
|
+
// Parse CLI arguments
|
|
48
|
+
function parseArgs(argv) {
|
|
49
|
+
const args = {
|
|
50
|
+
url: 'http://localhost:5173',
|
|
51
|
+
output: './renders',
|
|
52
|
+
width: 512,
|
|
53
|
+
height: 512,
|
|
54
|
+
params: null,
|
|
55
|
+
system: null,
|
|
56
|
+
geometry: null,
|
|
57
|
+
delay: 500,
|
|
58
|
+
frames: 1,
|
|
59
|
+
interval: 100,
|
|
60
|
+
format: 'png',
|
|
61
|
+
base64: false
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
for (let i = 2; i < argv.length; i++) {
|
|
65
|
+
const flag = argv[i];
|
|
66
|
+
const next = argv[i + 1];
|
|
67
|
+
|
|
68
|
+
switch (flag) {
|
|
69
|
+
case '--url': args.url = next; i++; break;
|
|
70
|
+
case '--output': args.output = next; i++; break;
|
|
71
|
+
case '--width': args.width = parseInt(next, 10); i++; break;
|
|
72
|
+
case '--height': args.height = parseInt(next, 10); i++; break;
|
|
73
|
+
case '--params': args.params = JSON.parse(next); i++; break;
|
|
74
|
+
case '--system': args.system = next; i++; break;
|
|
75
|
+
case '--geometry': args.geometry = parseInt(next, 10); i++; break;
|
|
76
|
+
case '--delay': args.delay = parseInt(next, 10); i++; break;
|
|
77
|
+
case '--frames': args.frames = parseInt(next, 10); i++; break;
|
|
78
|
+
case '--interval': args.interval = parseInt(next, 10); i++; break;
|
|
79
|
+
case '--format': args.format = next; i++; break;
|
|
80
|
+
case '--base64': args.base64 = true; break;
|
|
81
|
+
case '--help':
|
|
82
|
+
console.log('Usage: node tools/headless-renderer.js [options]');
|
|
83
|
+
console.log('See file header for full option list.');
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return args;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function main() {
|
|
92
|
+
const args = parseArgs(process.argv);
|
|
93
|
+
|
|
94
|
+
// Dynamic import puppeteer (devDependency)
|
|
95
|
+
let puppeteer;
|
|
96
|
+
try {
|
|
97
|
+
puppeteer = await import('puppeteer-core');
|
|
98
|
+
if (puppeteer.default) puppeteer = puppeteer.default;
|
|
99
|
+
} catch {
|
|
100
|
+
try {
|
|
101
|
+
puppeteer = await import('puppeteer');
|
|
102
|
+
if (puppeteer.default) puppeteer = puppeteer.default;
|
|
103
|
+
} catch {
|
|
104
|
+
console.error('Error: puppeteer or puppeteer-core is required.');
|
|
105
|
+
console.error('Install with: npm install puppeteer-core');
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Find Chrome/Chromium
|
|
111
|
+
const executablePath = findChromium();
|
|
112
|
+
|
|
113
|
+
console.log(`[headless-renderer] Launching browser...`);
|
|
114
|
+
const browser = await puppeteer.launch({
|
|
115
|
+
headless: 'new',
|
|
116
|
+
executablePath,
|
|
117
|
+
args: [
|
|
118
|
+
'--no-sandbox',
|
|
119
|
+
'--disable-setuid-sandbox',
|
|
120
|
+
'--disable-dev-shm-usage',
|
|
121
|
+
'--use-gl=swiftshader', // Software GPU for headless
|
|
122
|
+
`--window-size=${args.width},${args.height}`
|
|
123
|
+
]
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const page = await browser.newPage();
|
|
127
|
+
await page.setViewport({ width: args.width, height: args.height });
|
|
128
|
+
|
|
129
|
+
console.log(`[headless-renderer] Loading ${args.url}...`);
|
|
130
|
+
try {
|
|
131
|
+
await page.goto(args.url, { waitUntil: 'networkidle2', timeout: 30000 });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error(`Error: Could not load ${args.url}`);
|
|
134
|
+
console.error('Is the dev server running? Start it with: npm run dev');
|
|
135
|
+
await browser.close();
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Wait for VIB3+ engine to initialize
|
|
140
|
+
await page.waitForFunction(() => {
|
|
141
|
+
return typeof window.engine !== 'undefined' ||
|
|
142
|
+
document.querySelector('canvas') !== null;
|
|
143
|
+
}, { timeout: 10000 }).catch(() => {
|
|
144
|
+
console.warn('[headless-renderer] Warning: Engine not detected, capturing anyway');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Apply system switch
|
|
148
|
+
if (args.system) {
|
|
149
|
+
console.log(`[headless-renderer] Switching to system: ${args.system}`);
|
|
150
|
+
await page.evaluate((system) => {
|
|
151
|
+
if (window.switchSystem) window.switchSystem(system);
|
|
152
|
+
else if (window.engine?.switchSystem) window.engine.switchSystem(system);
|
|
153
|
+
}, args.system);
|
|
154
|
+
await sleep(200);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Apply geometry
|
|
158
|
+
if (args.geometry !== null) {
|
|
159
|
+
console.log(`[headless-renderer] Setting geometry: ${args.geometry}`);
|
|
160
|
+
await page.evaluate((geo) => {
|
|
161
|
+
if (window.selectGeometry) window.selectGeometry(geo);
|
|
162
|
+
else if (window.engine?.setParameter) window.engine.setParameter('geometry', geo);
|
|
163
|
+
}, args.geometry);
|
|
164
|
+
await sleep(100);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Apply custom parameters
|
|
168
|
+
if (args.params) {
|
|
169
|
+
console.log(`[headless-renderer] Applying parameters:`, JSON.stringify(args.params));
|
|
170
|
+
await page.evaluate((params) => {
|
|
171
|
+
for (const [key, value] of Object.entries(params)) {
|
|
172
|
+
if (window.updateParameter) window.updateParameter(key, value);
|
|
173
|
+
else if (window.engine?.setParameter) window.engine.setParameter(key, value);
|
|
174
|
+
}
|
|
175
|
+
}, args.params);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Wait for render to settle
|
|
179
|
+
console.log(`[headless-renderer] Waiting ${args.delay}ms for render...`);
|
|
180
|
+
await sleep(args.delay);
|
|
181
|
+
|
|
182
|
+
// Wait one animation frame
|
|
183
|
+
await page.evaluate(() => new Promise(r => requestAnimationFrame(r)));
|
|
184
|
+
|
|
185
|
+
// Capture frames
|
|
186
|
+
if (!args.base64 && !existsSync(args.output)) {
|
|
187
|
+
mkdirSync(args.output, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (let i = 0; i < args.frames; i++) {
|
|
191
|
+
const screenshot = await page.screenshot({
|
|
192
|
+
type: args.format === 'jpeg' ? 'jpeg' : 'png',
|
|
193
|
+
encoding: args.base64 ? 'base64' : 'binary',
|
|
194
|
+
fullPage: false
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
if (args.base64) {
|
|
198
|
+
// Output base64 to stdout (for agent consumption)
|
|
199
|
+
if (args.frames === 1) {
|
|
200
|
+
process.stdout.write(screenshot);
|
|
201
|
+
} else {
|
|
202
|
+
console.log(JSON.stringify({
|
|
203
|
+
frame: i,
|
|
204
|
+
format: args.format,
|
|
205
|
+
data: screenshot
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
const ext = args.format === 'jpeg' ? 'jpg' : args.format;
|
|
210
|
+
const filename = args.frames === 1
|
|
211
|
+
? `capture.${ext}`
|
|
212
|
+
: `frame_${String(i).padStart(4, '0')}.${ext}`;
|
|
213
|
+
const filepath = join(resolve(args.output), filename);
|
|
214
|
+
|
|
215
|
+
const fs = await import('fs');
|
|
216
|
+
fs.writeFileSync(filepath, screenshot);
|
|
217
|
+
console.log(`[headless-renderer] Saved: ${filepath}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Wait between frames
|
|
221
|
+
if (i < args.frames - 1 && args.interval > 0) {
|
|
222
|
+
await sleep(args.interval);
|
|
223
|
+
await page.evaluate(() => new Promise(r => requestAnimationFrame(r)));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
await browser.close();
|
|
228
|
+
console.log(`[headless-renderer] Done.`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function sleep(ms) {
|
|
232
|
+
return new Promise(r => setTimeout(r, ms));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function findChromium() {
|
|
236
|
+
const candidates = [
|
|
237
|
+
'/usr/bin/chromium-browser',
|
|
238
|
+
'/usr/bin/chromium',
|
|
239
|
+
'/usr/bin/google-chrome',
|
|
240
|
+
'/usr/bin/google-chrome-stable',
|
|
241
|
+
'/snap/bin/chromium',
|
|
242
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
243
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
244
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
for (const path of candidates) {
|
|
248
|
+
if (existsSync(path)) return path;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Let puppeteer figure it out
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
main().catch(err => {
|
|
256
|
+
console.error('[headless-renderer] Fatal error:', err.message);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
});
|
|
@@ -34,7 +34,8 @@ export class ShaderSyncVerifier {
|
|
|
34
34
|
'u_rot4dXY', 'u_rot4dXZ', 'u_rot4dYZ',
|
|
35
35
|
'u_rot4dXW', 'u_rot4dYW', 'u_rot4dZW',
|
|
36
36
|
'u_gridDensity', 'u_morphFactor', 'u_chaos',
|
|
37
|
-
'u_speed', 'u_hue', 'u_intensity', 'u_dimension'
|
|
37
|
+
'u_speed', 'u_hue', 'u_intensity', 'u_dimension',
|
|
38
|
+
'u_breath' // Exhale feature
|
|
38
39
|
],
|
|
39
40
|
recommended: [
|
|
40
41
|
'u_saturation', 'u_mouseIntensity', 'u_clickIntensity',
|
|
@@ -590,6 +591,7 @@ uniform float u_rot4dZW;
|
|
|
590
591
|
uniform float u_mouseIntensity;
|
|
591
592
|
uniform float u_clickIntensity;
|
|
592
593
|
uniform float u_roleIntensity;
|
|
594
|
+
uniform float u_breath;
|
|
593
595
|
void main() { gl_FragColor = vec4(0.0); }
|
|
594
596
|
`;
|
|
595
597
|
|
|
@@ -620,6 +622,7 @@ uniform float u_clickIntensity;
|
|
|
620
622
|
uniform float u_bass;
|
|
621
623
|
uniform float u_mid;
|
|
622
624
|
uniform float u_high;
|
|
625
|
+
uniform float u_breath;
|
|
623
626
|
void main() { gl_FragColor = vec4(0.0); }
|
|
624
627
|
`;
|
|
625
628
|
|
|
@@ -657,7 +660,7 @@ struct VIB3Uniforms {
|
|
|
657
660
|
layerColor: vec3<f32>,
|
|
658
661
|
densityMult: f32,
|
|
659
662
|
speedMult: f32,
|
|
660
|
-
|
|
663
|
+
breath: f32,
|
|
661
664
|
};
|
|
662
665
|
@group(0) @binding(0) var<uniform> u: VIB3Uniforms;
|
|
663
666
|
`;
|
|
@@ -702,6 +705,7 @@ uniform float u_rot4dYZ;
|
|
|
702
705
|
uniform float u_rot4dXW;
|
|
703
706
|
uniform float u_rot4dYW;
|
|
704
707
|
uniform float u_rot4dZW;
|
|
708
|
+
uniform float u_breath;
|
|
705
709
|
void main() { gl_FragColor = vec4(0.0); }
|
|
706
710
|
`;
|
|
707
711
|
|
|
@@ -739,7 +743,7 @@ struct VIB3Uniforms {
|
|
|
739
743
|
layerColor: vec3<f32>,
|
|
740
744
|
densityMult: f32,
|
|
741
745
|
speedMult: f32,
|
|
742
|
-
|
|
746
|
+
breath: f32,
|
|
743
747
|
};
|
|
744
748
|
@group(0) @binding(0) var<uniform> u: VIB3Uniforms;
|
|
745
749
|
`;
|
|
@@ -778,7 +782,7 @@ struct VIB3Uniforms {
|
|
|
778
782
|
layerColor: vec3<f32>,
|
|
779
783
|
densityMult: f32,
|
|
780
784
|
speedMult: f32,
|
|
781
|
-
|
|
785
|
+
breath: f32,
|
|
782
786
|
};
|
|
783
787
|
@group(0) @binding(0) var<uniform> u: VIB3Uniforms;
|
|
784
788
|
`;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"site": "clickerss",
|
|
4
|
+
"url": "https://www.clickerss.com/",
|
|
5
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://www.clickerss.com/\nCall log:\n - navigating to \"https://www.clickerss.com/\", waiting until \"networkidle\"\n"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"site": "facetad",
|
|
9
|
+
"url": "https://www.facetad.com/",
|
|
10
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://www.facetad.com/\nCall log:\n - navigating to \"https://www.facetad.com/\", waiting until \"networkidle\"\n"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"site": "wix-template-3630",
|
|
14
|
+
"url": "https://www.wix.com/website-template/view/html/3630",
|
|
15
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://www.wix.com/website-template/view/html/3630\nCall log:\n - navigating to \"https://www.wix.com/website-template/view/html/3630\", waiting until \"networkidle\"\n"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"site": "tableside",
|
|
19
|
+
"url": "https://www.tableside.com.au/",
|
|
20
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://www.tableside.com.au/\nCall log:\n - navigating to \"https://www.tableside.com.au/\", waiting until \"networkidle\"\n"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"site": "wix-studio-space",
|
|
24
|
+
"url": "https://www.wix.com/studio/design/inspiration/space",
|
|
25
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://www.wix.com/studio/design/inspiration/space\nCall log:\n - navigating to \"https://www.wix.com/studio/design/inspiration/space\", waiting until \"networkidle\"\n"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"site": "simone-webflow",
|
|
29
|
+
"url": "https://weare-simone.webflow.io/",
|
|
30
|
+
"error": "page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://weare-simone.webflow.io/\nCall log:\n - navigating to \"https://weare-simone.webflow.io/\", waiting until \"networkidle\"\n"
|
|
31
|
+
}
|
|
32
|
+
]
|