p5 2.2.2 → 2.2.3-rc.0

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 (96) 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-D3ryGa0m.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-DMfaOLIL.js} +48 -8
  40. package/dist/{main-DDs4QOnh.js → main-CGwYa9-f.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-C0e0XesC.js} +9 -2
  48. package/dist/{rendering-C9g7uSQ5.js → rendering-4Z2qdE_W.js} +90 -55
  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 +15 -2
  57. package/dist/strands/strands_api.js +86 -40
  58. package/dist/strands/strands_conditionals.js +1 -1
  59. package/dist/strands/strands_for.js +1 -1
  60. package/dist/strands/strands_node.js +1 -1
  61. package/dist/strands/strands_phi_utils.js +27 -9
  62. package/dist/strands/strands_transpiler.js +1237 -831
  63. package/dist/type/index.js +2 -2
  64. package/dist/type/p5.Font.js +7 -5
  65. package/dist/type/textCore.js +2 -2
  66. package/dist/webgl/3d_primitives.js +3 -3
  67. package/dist/webgl/GeometryBuilder.js +1 -1
  68. package/dist/webgl/ShapeBuilder.js +1 -1
  69. package/dist/webgl/enums.js +1 -1
  70. package/dist/webgl/index.js +4 -4
  71. package/dist/webgl/interaction.js +1 -1
  72. package/dist/webgl/light.js +3 -3
  73. package/dist/webgl/loading.js +41 -35
  74. package/dist/webgl/material.js +3 -3
  75. package/dist/webgl/p5.Camera.js +3 -3
  76. package/dist/webgl/p5.Framebuffer.js +3 -3
  77. package/dist/webgl/p5.Geometry.js +1 -1
  78. package/dist/webgl/p5.Quat.js +1 -1
  79. package/dist/webgl/p5.RendererGL.js +4 -4
  80. package/dist/webgl/p5.Texture.js +3 -3
  81. package/dist/webgl/strands_glslBackend.js +1 -1
  82. package/dist/webgl/text.js +3 -3
  83. package/dist/webgl/utils.js +3 -3
  84. package/dist/webgpu/index.js +2 -2
  85. package/dist/webgpu/p5.RendererWebGPU.js +2 -2
  86. package/dist/webgpu/strands_wgslBackend.js +13 -4
  87. package/lib/p5.esm.js +3634 -2870
  88. package/lib/p5.esm.min.js +1 -1
  89. package/lib/p5.js +3634 -2870
  90. package/lib/p5.min.js +1 -1
  91. package/lib/p5.webgpu.esm.js +43 -15
  92. package/lib/p5.webgpu.js +43 -15
  93. package/lib/p5.webgpu.min.js +1 -1
  94. package/package.json +1 -1
  95. package/types/global.d.ts +805 -805
  96. package/types/p5.d.ts +415 -415
@@ -37,6 +37,7 @@ const BaseType = {
37
37
  BOOL: "bool",
38
38
  MAT: "mat",
39
39
  DEFER: "defer",
40
+ ASSIGN_ON_USE: "assign_on_use",
40
41
  SAMPLER2D: "sampler2D",
41
42
  SAMPLER: "sampler",
42
43
  };
@@ -46,6 +47,7 @@ const BasePriority = {
46
47
  [BaseType.BOOL]: 1,
47
48
  [BaseType.MAT]: 0,
48
49
  [BaseType.DEFER]: -1,
50
+ [BaseType.ASSIGN_ON_USE]: -2,
49
51
  [BaseType.SAMPLER2D]: -10,
50
52
  [BaseType.SAMPLER]: -11,
51
53
  };
@@ -66,6 +68,7 @@ const DataType = {
66
68
  mat3: { fnName: "mat3x3", baseType: BaseType.MAT, dimension:3, priority: 0, },
67
69
  mat4: { fnName: "mat4x4", baseType: BaseType.MAT, dimension:4, priority: 0, },
68
70
  defer: { fnName: null, baseType: BaseType.DEFER, dimension: null, priority: -1 },
71
+ assign_on_use: { fnName: null, baseType: BaseType.ASSIGN_ON_USE, dimension: null, priority: -2 },
69
72
  sampler2D: { fnName: "sampler2D", baseType: BaseType.SAMPLER2D, dimension: 1, priority: -10 },
70
73
  sampler: { fnName: "sampler", baseType: BaseType.SAMPLER, dimension: 1, priority: -11 },
71
74
  };
@@ -137,7 +140,7 @@ const OpCode = {
137
140
  }
138
141
  };
139
142
  const OperatorTable = [
140
- { arity: "unary", name: "not", symbol: "!", opCode: OpCode.Unary.LOGICAL_NOT },
143
+ { arity: "unary", boolean: true, name: "not", symbol: "!", opCode: OpCode.Unary.LOGICAL_NOT },
141
144
  { arity: "unary", name: "neg", symbol: "-", opCode: OpCode.Unary.NEGATE },
142
145
  { arity: "unary", name: "plus", symbol: "+", opCode: OpCode.Unary.PLUS },
143
146
  { arity: "binary", name: "add", symbol: "+", opCode: OpCode.Binary.ADD },
@@ -145,14 +148,14 @@ const OperatorTable = [
145
148
  { arity: "binary", name: "mult", symbol: "*", opCode: OpCode.Binary.MULTIPLY },
146
149
  { arity: "binary", name: "div", symbol: "/", opCode: OpCode.Binary.DIVIDE },
147
150
  { arity: "binary", name: "mod", symbol: "%", opCode: OpCode.Binary.MODULO },
148
- { arity: "binary", name: "equalTo", symbol: "==", opCode: OpCode.Binary.EQUAL },
149
- { arity: "binary", name: "notEqual", symbol: "!=", opCode: OpCode.Binary.NOT_EQUAL },
150
- { arity: "binary", name: "greaterThan", symbol: ">", opCode: OpCode.Binary.GREATER_THAN },
151
- { arity: "binary", name: "greaterEqual", symbol: ">=", opCode: OpCode.Binary.GREATER_EQUAL },
152
- { arity: "binary", name: "lessThan", symbol: "<", opCode: OpCode.Binary.LESS_THAN },
153
- { arity: "binary", name: "lessEqual", symbol: "<=", opCode: OpCode.Binary.LESS_EQUAL },
154
- { arity: "binary", name: "and", symbol: "&&", opCode: OpCode.Binary.LOGICAL_AND },
155
- { arity: "binary", name: "or", symbol: "||", opCode: OpCode.Binary.LOGICAL_OR },
151
+ { arity: "binary", boolean: true, name: "equalTo", symbol: "==", opCode: OpCode.Binary.EQUAL },
152
+ { arity: "binary", boolean: true, name: "notEqual", symbol: "!=", opCode: OpCode.Binary.NOT_EQUAL },
153
+ { arity: "binary", boolean: true, name: "greaterThan", symbol: ">", opCode: OpCode.Binary.GREATER_THAN },
154
+ { arity: "binary", boolean: true, name: "greaterEqual", symbol: ">=", opCode: OpCode.Binary.GREATER_EQUAL },
155
+ { arity: "binary", boolean: true, name: "lessThan", symbol: "<", opCode: OpCode.Binary.LESS_THAN },
156
+ { arity: "binary", boolean: true, name: "lessEqual", symbol: "<=", opCode: OpCode.Binary.LESS_EQUAL },
157
+ { arity: "binary", boolean: true, name: "and", symbol: "&&", opCode: OpCode.Binary.LOGICAL_AND },
158
+ { arity: "binary", boolean: true, name: "or", symbol: "||", opCode: OpCode.Binary.LOGICAL_OR },
156
159
  ];
157
160
  const ConstantFolding = {
158
161
  [OpCode.Binary.ADD]: (a, b) => a + b,
@@ -173,7 +176,8 @@ const ConstantFolding = {
173
176
  const OpCodeToSymbol = {};
174
177
  const UnarySymbolToName = {};
175
178
  const BinarySymbolToName = {};
176
- for (const { symbol, opCode, name, arity } of OperatorTable) {
179
+ const booleanOpCode = {};
180
+ for (const { symbol, opCode, name, arity, boolean } of OperatorTable) {
177
181
  // SymbolToOpCode[symbol] = opCode;
178
182
  OpCodeToSymbol[opCode] = symbol;
179
183
  if (arity === 'unary') {
@@ -182,6 +186,9 @@ for (const { symbol, opCode, name, arity } of OperatorTable) {
182
186
  if (arity === 'binary') {
183
187
  BinarySymbolToName[symbol] = name;
184
188
  }
189
+ if (boolean) {
190
+ booleanOpCode[opCode] = true;
191
+ }
185
192
  }
186
193
  const BlockType = {
187
194
  GLOBAL: 'global',
@@ -200,4 +207,4 @@ const BlockTypeToName = Object.fromEntries(
200
207
  Object.entries(BlockType).map(([key, val]) => [val, key])
201
208
  );
202
209
 
203
- export { BasePriority, BaseType, BinarySymbolToName, BlockType, BlockTypeToName, ConstantFolding, DataType, GenType, NodeType, NodeTypeRequiredFields, NodeTypeToName, OpCode, OpCodeToSymbol, OperatorTable, StatementType, TypeInfoFromGLSLName, UnarySymbolToName, isStructType, structType, typeEquals };
210
+ export { BasePriority, BaseType, BinarySymbolToName, BlockType, BlockTypeToName, ConstantFolding, DataType, GenType, NodeType, NodeTypeRequiredFields, NodeTypeToName, OpCode, OpCodeToSymbol, OperatorTable, StatementType, TypeInfoFromGLSLName, UnarySymbolToName, booleanOpCode, isStructType, structType, typeEquals };
@@ -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-DMfaOLIL.js';
12
12
  import './strands_builtins.js';
13
13
  import './strands_conditionals.js';
14
14
  import './strands_phi_utils.js';
@@ -50,6 +50,7 @@ function strands(p5, fn) {
50
50
  ctx.previousFES = p5.disableFriendlyErrors;
51
51
  ctx.windowOverrides = {};
52
52
  ctx.fnOverrides = {};
53
+ ctx.graphicsOverrides = {};
53
54
  if (active) {
54
55
  p5.disableFriendlyErrors = true;
55
56
  }
@@ -72,6 +73,17 @@ function strands(p5, fn) {
72
73
  for (const key in ctx.fnOverrides) {
73
74
  fn[key] = ctx.fnOverrides[key];
74
75
  }
76
+ // Clean up the hooks temporarily installed on p5.Graphics.prototype (#8549)
77
+ const GraphicsProto = p5.Graphics?.prototype;
78
+ if (GraphicsProto) {
79
+ for (const key in ctx.graphicsOverrides) {
80
+ if (ctx.graphicsOverrides[key] === undefined) {
81
+ delete GraphicsProto[key];
82
+ } else {
83
+ GraphicsProto[key] = ctx.graphicsOverrides[key];
84
+ }
85
+ }
86
+ }
75
87
  }
76
88
 
77
89
  const strandsContext = {};
@@ -640,7 +652,8 @@ if (typeof p5 !== "undefined") {
640
652
  * filterColor.texCoord.x,
641
653
  * filterColor.texCoord.y + 0.1 * sin(filterColor.texCoord.x * 10)
642
654
  * ];
643
- * filterColor.set(getTexture(canvasContent, warped));
655
+ * let tex = filterColor.canvasContent;
656
+ * filterColor.set(getTexture(tex, warped));
644
657
  * filterColor.end();
645
658
  * }
646
659
  *
@@ -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-DMfaOLIL.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
@@ -369,20 +418,20 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
369
418
  });
370
419
 
371
420
  return createStrandsNode(id, dimension, strandsContext);
372
- };
421
+ });
373
422
 
374
423
  // Alias varying* as shared* for backward compatibility
375
- fn[`varying${pascalTypeName}`] = fn[`shared${pascalTypeName}`];
424
+ augmentFn(fn, p5, `varying${pascalTypeName}`, fn[`shared${pascalTypeName}`]);
376
425
 
377
426
  for (const typeAlias of typeAliases) {
378
427
  // For compatibility, also alias uniformVec2 as uniformVector2, what we initially
379
428
  // documented these as
380
- fn[`uniform${typeAlias}`] = fn[`uniform${pascalTypeName}`];
381
- fn[`varying${typeAlias}`] = fn[`varying${pascalTypeName}`];
382
- fn[`shared${typeAlias}`] = fn[`shared${pascalTypeName}`];
429
+ augmentFn(fn, p5, `uniform${typeAlias}`, fn[`uniform${pascalTypeName}`]);
430
+ augmentFn(fn, p5, `varying${typeAlias}`, fn[`varying${pascalTypeName}`]);
431
+ augmentFn(fn, p5, `shared${typeAlias}`, fn[`shared${pascalTypeName}`]);
383
432
  }
384
433
  const originalp5Fn = fn[typeInfo.fnName];
385
- fn[typeInfo.fnName] = function(...args) {
434
+ augmentFn(fn, p5, typeInfo.fnName, function(...args) {
386
435
  if (strandsContext.active) {
387
436
  if (args.length === 1 && args[0].dimension && args[0].dimension === typeInfo.dimension) {
388
437
  const { id, dimension } = functionCallNode(
@@ -414,7 +463,7 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
414
463
  `It looks like you've called ${typeInfo.fnName} outside of a shader's modify() function.`
415
464
  );
416
465
  }
417
- };
466
+ });
418
467
  }
419
468
  }
420
469
  //////////////////////////////////////////////
@@ -695,10 +744,7 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
695
744
  }
696
745
 
697
746
  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;
747
+ augmentFnTemporary(fn, strandsContext, name, hook);
702
748
  }
703
749
  hook.earlyReturns = [];
704
750
  }
@@ -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-DMfaOLIL.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-DMfaOLIL.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-DMfaOLIL.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,