@viji-dev/core 0.3.21 → 0.3.23

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.
@@ -2099,6 +2099,7 @@ class ShaderParameterParser {
2099
2099
  }
2100
2100
  }
2101
2101
  }
2102
+ this.crossValidateAccumulators(parameters);
2102
2103
  return parameters;
2103
2104
  }
2104
2105
  /**
@@ -2154,7 +2155,7 @@ class ShaderParameterParser {
2154
2155
  if (!param.uniformName) {
2155
2156
  throw new Error("Parameter uniformName is required");
2156
2157
  }
2157
- if (!param.config.label) {
2158
+ if (param.type !== "accumulator" && !param.config.label) {
2158
2159
  throw new Error(`Parameter ${param.uniformName} missing required 'label' key`);
2159
2160
  }
2160
2161
  switch (param.type) {
@@ -2190,6 +2191,17 @@ class ShaderParameterParser {
2190
2191
  break;
2191
2192
  case "image":
2192
2193
  break;
2194
+ case "accumulator":
2195
+ if (param.config.rate === void 0) {
2196
+ throw new Error(`Accumulator '${param.uniformName}' requires a 'rate' config key (parameter name or numeric constant)`);
2197
+ }
2198
+ if (typeof param.config.rate !== "string" && typeof param.config.rate !== "number") {
2199
+ throw new Error(`Accumulator '${param.uniformName}' rate must be a parameter name or numeric constant`);
2200
+ }
2201
+ if (typeof param.config.rate === "string" && param.config.rate.startsWith("u_")) {
2202
+ throw new Error(`Accumulator '${param.uniformName}' cannot reference built-in uniform '${param.config.rate}' — use a parameter name`);
2203
+ }
2204
+ break;
2193
2205
  default:
2194
2206
  console.warn(`Unknown parameter type: ${param.type}`);
2195
2207
  }
@@ -2213,10 +2225,33 @@ class ShaderParameterParser {
2213
2225
  return `uniform int ${param.uniformName};`;
2214
2226
  case "image":
2215
2227
  return `uniform sampler2D ${param.uniformName};`;
2228
+ case "accumulator":
2229
+ return `uniform float ${param.uniformName}; // accumulator (rate: ${param.config.rate})`;
2216
2230
  default:
2217
2231
  return `// Unknown parameter type: ${param.type}`;
2218
2232
  }
2219
2233
  }
2234
+ /**
2235
+ * Cross-validate accumulator references after all parameters are parsed.
2236
+ * Accumulators that reference non-existent parameters get a warning
2237
+ * but remain in the list so their uniform is still generated.
2238
+ */
2239
+ static crossValidateAccumulators(parameters) {
2240
+ const paramNames = new Set(
2241
+ parameters.filter((p) => p.type !== "accumulator").map((p) => p.uniformName)
2242
+ );
2243
+ for (const param of parameters) {
2244
+ if (param.type !== "accumulator") continue;
2245
+ const rate = param.config.rate;
2246
+ if (typeof rate === "string" && !paramNames.has(rate)) {
2247
+ const available = [...paramNames].join(", ");
2248
+ console.warn(
2249
+ `Accumulator '${param.uniformName}' references parameter '${rate}' which does not exist.` + (available ? ` Available parameters: ${available}` : " No parameters declared.")
2250
+ );
2251
+ param.config._rateInvalid = true;
2252
+ }
2253
+ }
2254
+ }
2220
2255
  }
2221
2256
  class ShaderWorkerAdapter {
2222
2257
  constructor(offscreenCanvas, _vijiAPI, shaderCode) {
@@ -2264,6 +2299,9 @@ class ShaderWorkerAdapter {
2264
2299
  streamTextures = [];
2265
2300
  // Device video textures
2266
2301
  deviceTextures = new Array(ShaderWorkerAdapter.MAX_DEVICE_VIDEOS).fill(null);
2302
+ // Accumulator state (CPU-side phase accumulators for smooth parameter-driven animation)
2303
+ accumulatorValues = /* @__PURE__ */ new Map();
2304
+ accumulatorWarned = /* @__PURE__ */ new Set();
2267
2305
  // Backbuffer support (ping-pong framebuffers)
2268
2306
  backbufferFramebuffer = null;
2269
2307
  backbufferTexture = null;
@@ -2276,6 +2314,11 @@ class ShaderWorkerAdapter {
2276
2314
  async init() {
2277
2315
  try {
2278
2316
  this.parameters = ShaderParameterParser.parseParameters(this.shaderCode);
2317
+ for (const param of this.parameters) {
2318
+ if (param.type === "accumulator") {
2319
+ this.accumulatorValues.set(param.uniformName, param.config.default ?? 0);
2320
+ }
2321
+ }
2279
2322
  this.createFullscreenQuad();
2280
2323
  const processedCode = this.injectUniforms(this.shaderCode);
2281
2324
  this.compileAndLinkShader(processedCode);
@@ -2497,6 +2540,7 @@ uniform float u_audioAny; // Any beat energy (0-1)
2497
2540
  // Audio - Beat Energy (smoothed 500ms decay)
2498
2541
  uniform float u_audioKickSmoothed; // Smoothed kick energy (0-1)
2499
2542
  uniform float u_audioSnareSmoothed; // Smoothed snare energy (0-1)
2543
+ uniform float u_audioHatSmoothed; // Smoothed hi-hat energy (0-1)
2500
2544
  uniform float u_audioAnySmoothed; // Smoothed any-beat energy (0-1)
2501
2545
 
2502
2546
  // Audio - Beat Triggers (true for one frame on beat)
@@ -2848,6 +2892,7 @@ ${error}`);
2848
2892
  }
2849
2893
  gl.useProgram(this.program);
2850
2894
  this.updateBuiltInUniforms(viji);
2895
+ this.updateAccumulators(viji, parameterObjects);
2851
2896
  this.updateParameterUniforms(parameterObjects);
2852
2897
  if (this.backbufferEnabled && this.backbufferTexture) {
2853
2898
  const backbufferUnit = this.textureUnits.get("backbuffer");
@@ -3232,11 +3277,43 @@ ${error}`);
3232
3277
  }
3233
3278
  }
3234
3279
  }
3280
+ /**
3281
+ * Update accumulator uniforms — CPU-side phase accumulation for smooth animation.
3282
+ * Each accumulator adds (rate × deltaTime) per frame, where rate comes from
3283
+ * a referenced parameter value or a numeric constant.
3284
+ */
3285
+ updateAccumulators(viji, parameterObjects) {
3286
+ const dt = viji.deltaTime || 0;
3287
+ for (const param of this.parameters) {
3288
+ if (param.type !== "accumulator") continue;
3289
+ const rateConfig = param.config.rate;
3290
+ let rate;
3291
+ if (typeof rateConfig === "number") {
3292
+ rate = rateConfig;
3293
+ } else {
3294
+ const sourceParam = parameterObjects.get(rateConfig);
3295
+ if (sourceParam !== void 0) {
3296
+ rate = sourceParam.value ?? 0;
3297
+ } else {
3298
+ if (!this.accumulatorWarned.has(param.uniformName)) {
3299
+ console.warn(`Accumulator '${param.uniformName}': rate source '${rateConfig}' not found, using 0`);
3300
+ this.accumulatorWarned.add(param.uniformName);
3301
+ }
3302
+ rate = 0;
3303
+ }
3304
+ }
3305
+ const current = this.accumulatorValues.get(param.uniformName) ?? 0;
3306
+ const next2 = current + rate * dt;
3307
+ this.accumulatorValues.set(param.uniformName, next2);
3308
+ this.setUniform(param.uniformName, "float", next2);
3309
+ }
3310
+ }
3235
3311
  /**
3236
3312
  * Update parameter uniforms from parameter objects
3237
3313
  */
3238
3314
  updateParameterUniforms(parameterObjects) {
3239
3315
  for (const param of this.parameters) {
3316
+ if (param.type === "accumulator") continue;
3240
3317
  const paramObj = parameterObjects.get(param.uniformName);
3241
3318
  if (!paramObj) {
3242
3319
  if (Math.random() < 0.01) {
@@ -3826,9 +3903,9 @@ class VijiWorkerRuntime {
3826
3903
  this.viji.ctx = this.ctx;
3827
3904
  }
3828
3905
  return this.ctx;
3829
- } else if (type === "webgl") {
3906
+ } else if (type === "webgl" || type === "webgl2") {
3830
3907
  if (!this.gl && this.canvas) {
3831
- this.gl = this.canvas.getContext("webgl2") || this.canvas.getContext("webgl");
3908
+ this.gl = type === "webgl2" ? this.canvas.getContext("webgl2") : this.canvas.getContext("webgl");
3832
3909
  this.viji.gl = this.gl;
3833
3910
  if (this.gl) {
3834
3911
  this.gl.viewport(0, 0, this.viji.width, this.viji.height);
@@ -3914,11 +3991,11 @@ class VijiWorkerRuntime {
3914
3991
  * In the parameter system, the 'label' serves as the parameter name/key
3915
3992
  */
3916
3993
  registerShaderParameter(param) {
3994
+ if (param.type === "accumulator") return;
3917
3995
  const config = param.config;
3918
3996
  const paramConfig = {
3919
3997
  ...config,
3920
3998
  label: param.uniformName,
3921
- // uniformName becomes the parameter key
3922
3999
  description: config.label ? `${config.label}${config.description ? ": " + config.description : ""}` : config.description
3923
4000
  };
3924
4001
  switch (param.type) {
@@ -25972,4 +26049,4 @@ async function setSceneCode(sceneCode) {
25972
26049
  }
25973
26050
  }
25974
26051
  self.setSceneCode = setSceneCode;
25975
- //# sourceMappingURL=viji.worker-bm-hvzXt.js.map
26052
+ //# sourceMappingURL=viji.worker-DTQvTudb.js.map