p5 2.2.2 → 2.2.3-rc.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.
Files changed (98) hide show
  1. package/dist/accessibility/color_namer.js +5 -5
  2. package/dist/accessibility/index.js +5 -5
  3. package/dist/app.js +5 -5
  4. package/dist/color/color_conversion.js +5 -5
  5. package/dist/color/index.js +1 -1
  6. package/dist/color/setting.js +1 -1
  7. package/dist/{constants-BxjhKpTv.js → constants-BUwWryrh.js} +1 -1
  8. package/dist/core/constants.js +1 -1
  9. package/dist/core/environment.js +7 -3
  10. package/dist/core/filterShaders.js +1 -1
  11. package/dist/core/friendly_errors/fes_core.js +1 -1
  12. package/dist/core/friendly_errors/file_errors.js +1 -1
  13. package/dist/core/friendly_errors/index.js +1 -1
  14. package/dist/core/friendly_errors/param_validator.js +2063 -2014
  15. package/dist/core/friendly_errors/sketch_verifier.js +1 -1
  16. package/dist/core/helpers.js +1 -1
  17. package/dist/core/init.js +5 -5
  18. package/dist/core/internationalization.js +1 -1
  19. package/dist/core/legacy.js +5 -5
  20. package/dist/core/main.js +5 -5
  21. package/dist/core/p5.Graphics.js +3 -3
  22. package/dist/core/p5.Renderer.js +2 -2
  23. package/dist/core/p5.Renderer2D.js +5 -5
  24. package/dist/core/p5.Renderer3D.js +3 -3
  25. package/dist/core/rendering.js +3 -3
  26. package/dist/dom/dom.js +1 -1
  27. package/dist/dom/index.js +1 -1
  28. package/dist/dom/p5.Element.js +1 -1
  29. package/dist/dom/p5.MediaElement.js +11 -4
  30. package/dist/events/pointer.js +4 -0
  31. package/dist/image/const.js +1 -1
  32. package/dist/image/filterRenderer2D.js +4 -4
  33. package/dist/image/image.js +3 -3
  34. package/dist/image/index.js +3 -3
  35. package/dist/image/loading_displaying.js +3 -3
  36. package/dist/image/p5.Image.js +2 -2
  37. package/dist/io/files.js +3 -3
  38. package/dist/io/index.js +3 -3
  39. package/dist/{ir_builders-w12-GSxu.js → ir_builders-Cd6rU9Vm.js} +48 -14
  40. package/dist/{main-DDs4QOnh.js → main-DFpoFdvM.js} +126 -36
  41. package/dist/math/Matrices/Matrix.js +1 -1
  42. package/dist/math/Matrices/MatrixNumjs.js +1 -1
  43. package/dist/math/index.js +1 -1
  44. package/dist/math/p5.Matrix.js +1 -1
  45. package/dist/math/p5.Vector.js +1 -1
  46. package/dist/math/trigonometry.js +1 -1
  47. package/dist/{p5.Renderer-BSGddFv7.js → p5.Renderer-D-EuAodU.js} +9 -2
  48. package/dist/{rendering-C9g7uSQ5.js → rendering-DE9-Hl7Y.js} +103 -78
  49. package/dist/shape/2d_primitives.js +1 -1
  50. package/dist/shape/attributes.js +1 -1
  51. package/dist/shape/custom_shapes.js +1 -1
  52. package/dist/shape/index.js +1 -1
  53. package/dist/strands/ir_builders.js +1 -1
  54. package/dist/strands/ir_dag.js +32 -2
  55. package/dist/strands/ir_types.js +18 -11
  56. package/dist/strands/p5.strands.js +24 -35
  57. package/dist/strands/strands_api.js +86 -41
  58. package/dist/strands/strands_codegen.js +0 -12
  59. package/dist/strands/strands_conditionals.js +1 -1
  60. package/dist/strands/strands_for.js +1 -1
  61. package/dist/strands/strands_node.js +1 -1
  62. package/dist/strands/strands_phi_utils.js +27 -9
  63. package/dist/strands/strands_transpiler.js +1237 -831
  64. package/dist/type/index.js +2 -2
  65. package/dist/type/p5.Font.js +7 -5
  66. package/dist/type/textCore.js +2 -2
  67. package/dist/webgl/3d_primitives.js +3 -3
  68. package/dist/webgl/GeometryBuilder.js +1 -1
  69. package/dist/webgl/ShapeBuilder.js +1 -1
  70. package/dist/webgl/enums.js +1 -1
  71. package/dist/webgl/index.js +4 -4
  72. package/dist/webgl/interaction.js +1 -1
  73. package/dist/webgl/light.js +3 -3
  74. package/dist/webgl/loading.js +41 -35
  75. package/dist/webgl/material.js +3 -3
  76. package/dist/webgl/p5.Camera.js +3 -3
  77. package/dist/webgl/p5.Framebuffer.js +3 -3
  78. package/dist/webgl/p5.Geometry.js +1 -1
  79. package/dist/webgl/p5.Quat.js +1 -1
  80. package/dist/webgl/p5.RendererGL.js +4 -4
  81. package/dist/webgl/p5.Shader.js +14 -6
  82. package/dist/webgl/p5.Texture.js +3 -3
  83. package/dist/webgl/strands_glslBackend.js +1 -1
  84. package/dist/webgl/text.js +3 -3
  85. package/dist/webgl/utils.js +3 -3
  86. package/dist/webgpu/index.js +2 -2
  87. package/dist/webgpu/p5.RendererWebGPU.js +2 -2
  88. package/dist/webgpu/strands_wgslBackend.js +13 -4
  89. package/lib/p5.esm.js +3670 -2951
  90. package/lib/p5.esm.min.js +1 -1
  91. package/lib/p5.js +3670 -2951
  92. package/lib/p5.min.js +1 -1
  93. package/lib/p5.webgpu.esm.js +43 -21
  94. package/lib/p5.webgpu.js +43 -21
  95. package/lib/p5.webgpu.min.js +1 -1
  96. package/package.json +1 -1
  97. package/types/global.d.ts +1283 -1301
  98. package/types/p5.d.ts +655 -657
@@ -8,7 +8,7 @@ import 'acorn';
8
8
  import 'acorn-walk';
9
9
  import 'escodegen';
10
10
  import './strands_FES.js';
11
- import '../ir_builders-w12-GSxu.js';
11
+ import '../ir_builders-Cd6rU9Vm.js';
12
12
  import './strands_builtins.js';
13
13
  import './strands_conditionals.js';
14
14
  import './strands_phi_utils.js';
@@ -42,7 +42,6 @@ function strands(p5, fn) {
42
42
  ctx.vertexDeclarations = new Set();
43
43
  ctx.fragmentDeclarations = new Set();
44
44
  ctx.hooks = [];
45
- ctx.globalAssignments = [];
46
45
  ctx.backend = backend;
47
46
  ctx.active = active;
48
47
  ctx.renderer = renderer;
@@ -50,6 +49,7 @@ function strands(p5, fn) {
50
49
  ctx.previousFES = p5.disableFriendlyErrors;
51
50
  ctx.windowOverrides = {};
52
51
  ctx.fnOverrides = {};
52
+ ctx.graphicsOverrides = {};
53
53
  if (active) {
54
54
  p5.disableFriendlyErrors = true;
55
55
  }
@@ -63,7 +63,6 @@ function strands(p5, fn) {
63
63
  ctx.vertexDeclarations = new Set();
64
64
  ctx.fragmentDeclarations = new Set();
65
65
  ctx.hooks = [];
66
- ctx.globalAssignments = [];
67
66
  ctx.active = false;
68
67
  p5.disableFriendlyErrors = ctx.previousFES;
69
68
  for (const key in ctx.windowOverrides) {
@@ -72,6 +71,17 @@ function strands(p5, fn) {
72
71
  for (const key in ctx.fnOverrides) {
73
72
  fn[key] = ctx.fnOverrides[key];
74
73
  }
74
+ // Clean up the hooks temporarily installed on p5.Graphics.prototype (#8549)
75
+ const GraphicsProto = p5.Graphics?.prototype;
76
+ if (GraphicsProto) {
77
+ for (const key in ctx.graphicsOverrides) {
78
+ if (ctx.graphicsOverrides[key] === undefined) {
79
+ delete GraphicsProto[key];
80
+ } else {
81
+ GraphicsProto[key] = ctx.graphicsOverrides[key];
82
+ }
83
+ }
84
+ }
75
85
  }
76
86
 
77
87
  const strandsContext = {};
@@ -197,7 +207,7 @@ if (typeof p5 !== "undefined") {
197
207
  * }
198
208
  *
199
209
  * function material() {
200
- * let t = uniformFloat();
210
+ * let t = millis();
201
211
  * worldInputs.begin();
202
212
  * // Move the vertex up and down in a wave in world space
203
213
  * // In world space, moving the object (e.g., with translate()) will affect these coordinates
@@ -209,7 +219,6 @@ if (typeof p5 !== "undefined") {
209
219
  * function draw() {
210
220
  * background(255);
211
221
  * shader(myShader);
212
- * myShader.setUniform('t', millis());
213
222
  * lights();
214
223
  * noStroke();
215
224
  * fill('red');
@@ -298,9 +307,7 @@ if (typeof p5 !== "undefined") {
298
307
  * A value between `0.0` and `1.0`
299
308
  *
300
309
  * @example
301
- * <div modernizr="webgl">
302
- * <code>
303
- * // Example 1: A soft vertical fade using smoothstep (no uniforms)
310
+ * // Example 1: A soft vertical fade using smoothstep
304
311
  *
305
312
  * let fadeShader;
306
313
  *
@@ -319,31 +326,25 @@ if (typeof p5 !== "undefined") {
319
326
  *
320
327
  * function setup() {
321
328
  * createCanvas(300, 200, WEBGL);
322
- * fadeShader = baseFilterShader().modify(fadeCallback);
329
+ * fadeShader = buildFilterShader(fadeCallback);
323
330
  * }
324
331
  *
325
332
  * function draw() {
326
333
  * background(0);
327
334
  * filter(fadeShader);
328
335
  * }
329
- * </code>
330
- * </div>
331
336
  *
332
337
  * @example
333
- * <div modernizr="webgl">
334
- * <code>
335
- * // Example 2: Animate the smooth transition using a uniform
338
+ * // Example 2: Animate the smooth transition over time
336
339
  *
337
340
  * let animatedShader;
338
341
  *
339
342
  * function animatedFadeCallback() {
340
- * const time = uniformFloat(() => millis() * 0.001);
341
- *
342
343
  * getColor((inputs) => {
343
344
  * let x = inputs.texCoord.x;
344
345
  *
345
346
  * // Move the smoothstep band back and forth over time
346
- * let center = 0.5 + 0.25 * sin(time);
347
+ * let center = 0.5 + 0.25 * sin(millis() * 0.001);
347
348
  * let t = smoothstep(center - 0.05, center + 0.05, x);
348
349
  *
349
350
  * return [t, t, t, 1];
@@ -352,15 +353,13 @@ if (typeof p5 !== "undefined") {
352
353
  *
353
354
  * function setup() {
354
355
  * createCanvas(300, 200, WEBGL);
355
- * animatedShader = baseFilterShader().modify(animatedFadeCallback);
356
+ * animatedShader = buildFilterShader(animatedFadeCallback);
356
357
  * }
357
358
  *
358
359
  * function draw() {
359
360
  * background(0);
360
361
  * filter(animatedShader);
361
362
  * }
362
- * </code>
363
- * </div>
364
363
  */
365
364
 
366
365
  /**
@@ -477,7 +476,7 @@ if (typeof p5 !== "undefined") {
477
476
  * }
478
477
  *
479
478
  * function material() {
480
- * let t = uniformFloat();
479
+ * let t = millis();
481
480
  * pixelInputs.begin();
482
481
  * // Animate alpha (transparency) based on x position
483
482
  * pixelInputs.color.a = 0.5 + 0.5 *
@@ -488,7 +487,6 @@ if (typeof p5 !== "undefined") {
488
487
  * function draw() {
489
488
  * background(240);
490
489
  * shader(myShader);
491
- * myShader.setUniform('t', millis());
492
490
  * lights();
493
491
  * noStroke();
494
492
  * fill('purple');
@@ -640,7 +638,8 @@ if (typeof p5 !== "undefined") {
640
638
  * filterColor.texCoord.x,
641
639
  * filterColor.texCoord.y + 0.1 * sin(filterColor.texCoord.x * 10)
642
640
  * ];
643
- * filterColor.set(getTexture(canvasContent, warped));
641
+ * let tex = filterColor.canvasContent;
642
+ * filterColor.set(getTexture(tex, warped));
644
643
  * filterColor.end();
645
644
  * }
646
645
  *
@@ -678,7 +677,7 @@ if (typeof p5 !== "undefined") {
678
677
  * }
679
678
  *
680
679
  * function material() {
681
- * let t = uniformFloat();
680
+ * let t = millis();
682
681
  * objectInputs.begin();
683
682
  * // Create a sine wave along the object
684
683
  * objectInputs.position.y += sin(t * 0.001 + objectInputs.position.x);
@@ -688,7 +687,6 @@ if (typeof p5 !== "undefined") {
688
687
  * function draw() {
689
688
  * background(220);
690
689
  * shader(myShader);
691
- * myShader.setUniform('t', millis());
692
690
  * noStroke();
693
691
  * fill('orange');
694
692
  * sphere(50);
@@ -720,7 +718,7 @@ if (typeof p5 !== "undefined") {
720
718
  * }
721
719
  *
722
720
  * function material() {
723
- * let t = uniformFloat();
721
+ * let t = millis();
724
722
  * cameraInputs.begin();
725
723
  * // Move vertices in camera space based on their x position
726
724
  * cameraInputs.position.y += 30 * sin(cameraInputs.position.x * 0.05 + t * 0.001);
@@ -732,7 +730,6 @@ if (typeof p5 !== "undefined") {
732
730
  * function draw() {
733
731
  * background(200);
734
732
  * shader(myShader);
735
- * myShader.setUniform('t', millis());
736
733
  * noStroke();
737
734
  * fill('red');
738
735
  * sphere(50);
@@ -779,8 +776,6 @@ if (typeof p5 !== "undefined") {
779
776
  * will behave as a vec4 holding components r, g, b, and a (alpha), with each component being in the range 0.0 to 1.0.
780
777
  *
781
778
  * @example
782
- * <div modernizr='webgl'>
783
- * <code>
784
779
  * // A filter shader (using p5.strands) which will
785
780
  * // sample and invert the color of each pixel
786
781
  * // from the canvas.
@@ -813,12 +808,8 @@ if (typeof p5 !== "undefined") {
813
808
  *
814
809
  * filterColor.end();
815
810
  * }
816
- * </code>
817
- *
818
811
  *
819
812
  * @example
820
- * <div modernizr='webgl'>
821
- * <code>
822
813
  * // This primitive edge-detection filter samples
823
814
  * // and compares the colors of the current pixel
824
815
  * // on the canvas, and a little to the right.
@@ -875,8 +866,6 @@ if (typeof p5 !== "undefined") {
875
866
  * rotate(frameCount / 300);
876
867
  * square(0, 0, 30);
877
868
  * }
878
- * </code>
879
- * </div>
880
869
  */
881
870
 
882
871
  /**
@@ -1,4 +1,4 @@
1
- import { u as unaryOpNode, c as createStrandsNode, s as statementNode, v as variableNode, S as StrandsNode, p as primitiveConstructorNode, f as functionCallNode, a as structInstanceNode, b as structConstructorNode, d as binaryOpNode } from '../ir_builders-w12-GSxu.js';
1
+ import { u as unaryOpNode, c as createStrandsNode, S as StrandsNode, p as primitiveConstructorNode, v as variableNode, b as binaryOpNode, s as statementNode, f as functionCallNode, a as structInstanceNode, d as structConstructorNode } from '../ir_builders-Cd6rU9Vm.js';
2
2
  import { OperatorTable, StatementType, NodeType, DataType, BaseType, BlockType, isStructType, structType } from './ir_types.js';
3
3
  import { strandsBuiltinFunctions } from './strands_builtins.js';
4
4
  import { StrandsConditional } from './strands_conditionals.js';
@@ -101,6 +101,42 @@ function installBuiltinGlobalAccessors(strandsContext) {
101
101
  strandsContext._builtinGlobalsAccessorsInstalled = true;
102
102
  }
103
103
 
104
+ //////////////////////////////////////////////
105
+ // Prototype mirroring helpers
106
+ //////////////////////////////////////////////
107
+
108
+ /*
109
+ * Permanently augment both p5.prototype (fn) and p5.Graphics.prototype
110
+ * with a strands function. Overwrites unconditionally - strands wrappers
111
+ * are the correct dual mode implementation.
112
+ */
113
+ function augmentFn(fn, p5, name, value) {
114
+ fn[name] = value;
115
+ const GraphicsProto = p5?.Graphics?.prototype;
116
+ if (GraphicsProto) {
117
+ GraphicsProto[name] = value;
118
+ }
119
+ }
120
+
121
+ /*
122
+ * Temporarily augment window, p5.prototype (fn), and p5.Graphics.prototype
123
+ * with a hook function. Saves previous values into strandsContext override
124
+ * stores so deinitStrandsContext can restore them.
125
+ */
126
+ function augmentFnTemporary(fn, strandsContext, name, value) {
127
+ strandsContext.windowOverrides[name] = window[name];
128
+ strandsContext.fnOverrides[name] = fn[name];
129
+ window[name] = value;
130
+ fn[name] = value;
131
+ const GraphicsProto = strandsContext.p5?.Graphics?.prototype;
132
+ if (GraphicsProto) {
133
+ strandsContext.graphicsOverrides[name] = Object.prototype.hasOwnProperty.call(GraphicsProto, name)
134
+ ? GraphicsProto[name]
135
+ : undefined;
136
+ GraphicsProto[name] = value;
137
+ }
138
+ }
139
+
104
140
  //////////////////////////////////////////////
105
141
  // User nodes
106
142
  //////////////////////////////////////////////
@@ -124,27 +160,27 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
124
160
  //////////////////////////////////////////////
125
161
  // Unique Functions
126
162
  //////////////////////////////////////////////
127
- fn.discard = function() {
163
+ augmentFn(fn, p5, 'discard', function() {
128
164
  statementNode(strandsContext, StatementType.DISCARD);
129
- };
130
- fn.break = function() {
165
+ });
166
+ augmentFn(fn, p5, 'break', function() {
131
167
  statementNode(strandsContext, StatementType.BREAK);
132
- };
168
+ });
133
169
  p5.break = fn.break;
134
- fn.instanceID = function() {
170
+ augmentFn(fn, p5, 'instanceID', function() {
135
171
  const node = variableNode(strandsContext, { baseType: BaseType.INT, dimension: 1 }, strandsContext.backend.instanceIdReference());
136
172
  return createStrandsNode(node.id, node.dimension, strandsContext);
137
- };
173
+ });
138
174
  // Internal methods use p5 static methods; user-facing methods use fn.
139
175
  // Some methods need to be used by both.
140
176
  p5.strandsIf = function(conditionNode, ifBody) {
141
177
  return new StrandsConditional(strandsContext, conditionNode, ifBody);
142
178
  };
143
- fn.strandsIf = p5.strandsIf;
179
+ augmentFn(fn, p5, 'strandsIf', p5.strandsIf);
144
180
  p5.strandsFor = function(initialCb, conditionCb, updateCb, bodyCb, initialVars) {
145
181
  return new StrandsFor(strandsContext, initialCb, conditionCb, updateCb, bodyCb, initialVars).build();
146
182
  };
147
- fn.strandsFor = p5.strandsFor;
183
+ augmentFn(fn, p5, 'strandsFor', p5.strandsFor);
148
184
  p5.strandsEarlyReturn = function(value) {
149
185
  const { dag, cfg } = strandsContext;
150
186
 
@@ -177,7 +213,7 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
177
213
 
178
214
  return valueNode;
179
215
  };
180
- fn.strandsEarlyReturn = p5.strandsEarlyReturn;
216
+ augmentFn(fn, p5, 'strandsEarlyReturn', p5.strandsEarlyReturn);
181
217
  p5.strandsNode = function(...args) {
182
218
  if (args.length === 1 && args[0] instanceof StrandsNode) {
183
219
  return args[0];
@@ -185,7 +221,20 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
185
221
  if (args.length > 4) {
186
222
  userError("type error", "It looks like you've tried to construct a p5.strands node implicitly, with more than 4 components. This is currently not supported.");
187
223
  }
188
- const { id, dimension } = primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, args.flat());
224
+ // Filter out undefined/null values
225
+ const flatArgs = args.flat();
226
+ const definedArgs = flatArgs.filter(a => a !== undefined && a !== null);
227
+
228
+ // If all args are undefined, this is likely a `let myVar` at the
229
+ // start of an if statement and it will be assigned within the branches.
230
+ // For that, we use an assign-on-use node, meaning we'll take the type of the
231
+ // values assigned to it.
232
+ if (definedArgs.length === 0) {
233
+ const { id, dimension } = primitiveConstructorNode(strandsContext, { baseType: BaseType.ASSIGN_ON_USE, dimension: null }, [0]);
234
+ return createStrandsNode(id, dimension, strandsContext);
235
+ }
236
+
237
+ const { id, dimension } = primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, definedArgs);
189
238
  return createStrandsNode(id, dimension, strandsContext);//new StrandsNode(id, dimension, strandsContext);
190
239
  };
191
240
  //////////////////////////////////////////////
@@ -195,16 +244,16 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
195
244
  const isp5Function = overrides[0].isp5Function;
196
245
  if (isp5Function) {
197
246
  const originalFn = fn[functionName];
198
- fn[functionName] = function(...args) {
247
+ augmentFn(fn, p5, functionName, function(...args) {
199
248
  if (strandsContext.active) {
200
249
  const { id, dimension } = functionCallNode(strandsContext, functionName, args);
201
250
  return createStrandsNode(id, dimension, strandsContext);
202
251
  } else {
203
252
  return originalFn.apply(this, args);
204
253
  }
205
- };
254
+ });
206
255
  } else {
207
- fn[functionName] = function (...args) {
256
+ augmentFn(fn, p5, functionName, function (...args) {
208
257
  if (strandsContext.active) {
209
258
  const { id, dimension } = functionCallNode(strandsContext, functionName, args);
210
259
  return createStrandsNode(id, dimension, strandsContext);
@@ -213,11 +262,11 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
213
262
  `It looks like you've called ${functionName} outside of a shader's modify() function.`
214
263
  );
215
264
  }
216
- };
265
+ });
217
266
  }
218
267
  }
219
268
 
220
- fn.getTexture = function (...rawArgs) {
269
+ augmentFn(fn, p5, 'getTexture', function (...rawArgs) {
221
270
  if (strandsContext.active) {
222
271
  const { id, dimension } = strandsContext.backend.createGetTextureCall(strandsContext, rawArgs);
223
272
  return createStrandsNode(id, dimension, strandsContext);
@@ -226,17 +275,17 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
226
275
  `It looks like you've called getTexture outside of a shader's modify() function.`
227
276
  );
228
277
  }
229
- };
278
+ });
230
279
 
231
280
  // Add texture function as alias for getTexture with p5 fallback
232
281
  const originalTexture = fn.texture;
233
- fn.texture = function (...args) {
282
+ augmentFn(fn, p5, 'texture', function (...args) {
234
283
  if (strandsContext.active) {
235
284
  return this.getTexture(...args);
236
285
  } else {
237
286
  return originalTexture.apply(this, args);
238
287
  }
239
- };
288
+ });
240
289
 
241
290
  // Add noise function with backend-agnostic implementation
242
291
  const originalNoise = fn.noise;
@@ -246,16 +295,16 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
246
295
  strandsContext._noiseOctaves = null;
247
296
  strandsContext._noiseAmpFalloff = null;
248
297
 
249
- fn.noiseDetail = function (lod, falloff = 0.5) {
298
+ augmentFn(fn, p5, 'noiseDetail', function (lod, falloff = 0.5) {
250
299
  if (!strandsContext.active) {
251
300
  return originalNoiseDetail.apply(this, arguments);
252
301
  }
253
302
 
254
303
  strandsContext._noiseOctaves = lod;
255
304
  strandsContext._noiseAmpFalloff = falloff;
256
- };
305
+ });
257
306
 
258
- fn.noise = function (...args) {
307
+ augmentFn(fn, p5, 'noise', function (...args) {
259
308
  if (!strandsContext.active) {
260
309
  return originalNoise.apply(this, args); // fallback to regular p5.js noise
261
310
  }
@@ -302,9 +351,9 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
302
351
  }]
303
352
  });
304
353
  return createStrandsNode(id, dimension, strandsContext);
305
- };
354
+ });
306
355
 
307
- fn.millis = function (...args) {
356
+ augmentFn(fn, p5, 'millis', function (...args) {
308
357
  if (!strandsContext.active) {
309
358
  return originalMillis.apply(this, args);
310
359
  }
@@ -317,14 +366,14 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
317
366
  return instance ? instance.millis() : undefined;
318
367
  }
319
368
  );
320
- };
369
+ });
321
370
 
322
371
  // Next is type constructors and uniform functions.
323
372
  // For some of them, we have aliases so that you can write either a more human-readable
324
373
  // variant or also one more directly translated from GLSL, or to be more compatible with
325
374
  // APIs we documented at the release of 2.x and have to continue supporting.
326
375
  for (const type in DataType) {
327
- if (type === BaseType.DEFER || type === 'sampler') {
376
+ if (type === BaseType.DEFER || type === BaseType.ASSIGN_ON_USE || type === 'sampler') {
328
377
  continue;
329
378
  }
330
379
  const typeInfo = DataType[type];
@@ -346,13 +395,13 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
346
395
  typeAliases.push(pascalTypeName.replace('Vec', 'Vector'));
347
396
  }
348
397
  }
349
- fn[`uniform${pascalTypeName}`] = function(name, defaultValue) {
398
+ augmentFn(fn, p5, `uniform${pascalTypeName}`, function(name, defaultValue) {
350
399
  const { id, dimension } = variableNode(strandsContext, typeInfo, name);
351
400
  strandsContext.uniforms.push({ name, typeInfo, defaultValue });
352
401
  return createStrandsNode(id, dimension, strandsContext);
353
- };
402
+ });
354
403
  // Shared variables with smart context detection
355
- fn[`shared${pascalTypeName}`] = function(name) {
404
+ augmentFn(fn, p5, `shared${pascalTypeName}`, function(name) {
356
405
  const { id, dimension } = variableNode(strandsContext, typeInfo, name);
357
406
 
358
407
  // Initialize shared variables tracking if not present
@@ -365,24 +414,23 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
365
414
  typeInfo,
366
415
  usedInVertex: false,
367
416
  usedInFragment: false,
368
- declared: false
369
417
  });
370
418
 
371
419
  return createStrandsNode(id, dimension, strandsContext);
372
- };
420
+ });
373
421
 
374
422
  // Alias varying* as shared* for backward compatibility
375
- fn[`varying${pascalTypeName}`] = fn[`shared${pascalTypeName}`];
423
+ augmentFn(fn, p5, `varying${pascalTypeName}`, fn[`shared${pascalTypeName}`]);
376
424
 
377
425
  for (const typeAlias of typeAliases) {
378
426
  // For compatibility, also alias uniformVec2 as uniformVector2, what we initially
379
427
  // documented these as
380
- fn[`uniform${typeAlias}`] = fn[`uniform${pascalTypeName}`];
381
- fn[`varying${typeAlias}`] = fn[`varying${pascalTypeName}`];
382
- fn[`shared${typeAlias}`] = fn[`shared${pascalTypeName}`];
428
+ augmentFn(fn, p5, `uniform${typeAlias}`, fn[`uniform${pascalTypeName}`]);
429
+ augmentFn(fn, p5, `varying${typeAlias}`, fn[`varying${pascalTypeName}`]);
430
+ augmentFn(fn, p5, `shared${typeAlias}`, fn[`shared${pascalTypeName}`]);
383
431
  }
384
432
  const originalp5Fn = fn[typeInfo.fnName];
385
- fn[typeInfo.fnName] = function(...args) {
433
+ augmentFn(fn, p5, typeInfo.fnName, function(...args) {
386
434
  if (strandsContext.active) {
387
435
  if (args.length === 1 && args[0].dimension && args[0].dimension === typeInfo.dimension) {
388
436
  const { id, dimension } = functionCallNode(
@@ -414,7 +462,7 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
414
462
  `It looks like you've called ${typeInfo.fnName} outside of a shader's modify() function.`
415
463
  );
416
464
  }
417
- };
465
+ });
418
466
  }
419
467
  }
420
468
  //////////////////////////////////////////////
@@ -695,10 +743,7 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
695
743
  }
696
744
 
697
745
  for (const name of aliases) {
698
- strandsContext.windowOverrides[name] = window[name];
699
- strandsContext.fnOverrides[name] = fn[name];
700
- window[name] = hook;
701
- fn[name] = hook;
746
+ augmentFnTemporary(fn, strandsContext, name, hook);
702
747
  }
703
748
  hook.earlyReturns = [];
704
749
  }
@@ -47,18 +47,6 @@ function generateShaderCode(strandsContext) {
47
47
  backend.generateBlock(blockID, strandsContext, generationContext);
48
48
  }
49
49
 
50
- // Process any unvisited global assignments to ensure side effects are generated
51
- for (const assignmentNodeID of strandsContext.globalAssignments) {
52
- if (!generationContext.visitedNodes.has(assignmentNodeID)) {
53
- // This assignment hasn't been visited yet, so we need to generate it
54
- backend.generateAssignment(generationContext, strandsContext.dag, assignmentNodeID);
55
- generationContext.visitedNodes.add(assignmentNodeID);
56
- }
57
- }
58
-
59
- // Reset global assignments for next hook
60
- strandsContext.globalAssignments = [];
61
-
62
50
  const firstLine = backend.hookEntry(hookType);
63
51
  let returnType;
64
52
  if (hookType.returnType.properties) {
@@ -1,7 +1,7 @@
1
1
  import { createBasicBlock, addEdge, pushBlock, popBlock, pushBlockForModification, recordInBasicBlock } from './ir_cfg.js';
2
2
  import { getOrCreateNode } from './ir_dag.js';
3
3
  import { BlockType, NodeType } from './ir_types.js';
4
- import { c as createStrandsNode } from '../ir_builders-w12-GSxu.js';
4
+ import { c as createStrandsNode } from '../ir_builders-Cd6rU9Vm.js';
5
5
  import { createPhiNode } from './strands_phi_utils.js';
6
6
  import './strands_FES.js';
7
7
  import './strands_builtins.js';
@@ -1,7 +1,7 @@
1
1
  import { createBasicBlock, addEdge, pushBlock, popBlock, pushBlockForModification, recordInBasicBlock } from './ir_cfg.js';
2
2
  import { getNodeDataFromID, createNodeData, getOrCreateNode } from './ir_dag.js';
3
3
  import { BlockType, NodeType, StatementType, OpCode, BaseType } from './ir_types.js';
4
- import { c as createStrandsNode, p as primitiveConstructorNode } from '../ir_builders-w12-GSxu.js';
4
+ import { c as createStrandsNode, p as primitiveConstructorNode } from '../ir_builders-Cd6rU9Vm.js';
5
5
  import { createPhiNode } from './strands_phi_utils.js';
6
6
  import './strands_FES.js';
7
7
  import './strands_builtins.js';
@@ -1,4 +1,4 @@
1
- export { S as StrandsNode, c as createStrandsNode } from '../ir_builders-w12-GSxu.js';
1
+ export { S as StrandsNode, c as createStrandsNode } from '../ir_builders-Cd6rU9Vm.js';
2
2
  import './ir_types.js';
3
3
  import './ir_dag.js';
4
4
  import './ir_cfg.js';
@@ -1,6 +1,6 @@
1
1
  import { recordInBasicBlock } from './ir_cfg.js';
2
- import { getNodeDataFromID, getOrCreateNode } from './ir_dag.js';
3
- import { NodeType } from './ir_types.js';
2
+ import { getNodeDataFromID, propagateTypeToAssignOnUse, getOrCreateNode } from './ir_dag.js';
3
+ import { BaseType, NodeType } from './ir_types.js';
4
4
  import './strands_FES.js';
5
5
 
6
6
  function createPhiNode(strandsContext, phiInputs, varName) {
@@ -9,13 +9,31 @@ function createPhiNode(strandsContext, phiInputs, varName) {
9
9
  if (validInputs.length === 0) {
10
10
  throw new Error(`No valid inputs for phi node for variable ${varName}`);
11
11
  }
12
- // Get dimension and baseType from first valid input
13
- let firstInput = validInputs
14
- .map((input) => getNodeDataFromID(strandsContext.dag, input.value.id))
15
- .find((input) => input.dimension) ??
16
- getNodeDataFromID(strandsContext.dag, validInputs[0].value.id);
17
- const dimension = firstInput.dimension;
18
- const baseType = firstInput.baseType;
12
+
13
+ // Get dimension and baseType from first valid input, skipping ASSIGN_ON_USE nodes
14
+ const inputNodes = validInputs.map((input) => getNodeDataFromID(strandsContext.dag, input.value.id));
15
+
16
+ // Find first non-ASSIGN_ON_USE input to determine type
17
+ let typeSource = inputNodes.find((input) => input.baseType !== BaseType.ASSIGN_ON_USE && input.dimension) ??
18
+ inputNodes.find((input) => input.baseType !== BaseType.ASSIGN_ON_USE);
19
+
20
+ // If all are ASSIGN_ON_USE, fall back to first input
21
+ if (!typeSource) {
22
+ typeSource = inputNodes[0];
23
+ }
24
+
25
+ const dimension = typeSource.dimension;
26
+ const baseType = typeSource.baseType;
27
+
28
+ // Propagate the type to all ASSIGN_ON_USE inputs
29
+ if (baseType !== BaseType.ASSIGN_ON_USE) {
30
+ for (const input of inputNodes) {
31
+ if (input.baseType === BaseType.ASSIGN_ON_USE) {
32
+ propagateTypeToAssignOnUse(strandsContext.dag, input.id, baseType, dimension);
33
+ }
34
+ }
35
+ }
36
+
19
37
  const nodeData = {
20
38
  nodeType: NodeType.PHI,
21
39
  dimension,