p5 2.2.1 → 2.2.2-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 (91) 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-DQyACdzq.js → constants-D3npMLOW.js} +1 -1
  8. package/dist/core/constants.js +1 -1
  9. package/dist/core/environment.js +1 -1
  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 +1 -1
  15. package/dist/core/friendly_errors/sketch_verifier.js +2 -2
  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 +1 -1
  30. package/dist/image/const.js +1 -1
  31. package/dist/image/filterRenderer2D.js +4 -4
  32. package/dist/image/image.js +3 -3
  33. package/dist/image/index.js +3 -3
  34. package/dist/image/loading_displaying.js +3 -3
  35. package/dist/image/p5.Image.js +2 -2
  36. package/dist/io/files.js +3 -3
  37. package/dist/io/index.js +3 -3
  38. package/dist/{ir_builders-DXNgaB9N.js → ir_builders-w12-GSxu.js} +37 -5
  39. package/dist/{main-DvN69W3f.js → main-C5AeICIY.js} +3 -3
  40. package/dist/math/Matrices/Matrix.js +1 -1
  41. package/dist/math/Matrices/MatrixNumjs.js +1 -1
  42. package/dist/math/index.js +1 -1
  43. package/dist/math/p5.Matrix.js +1 -1
  44. package/dist/math/p5.Vector.js +1 -1
  45. package/dist/math/trigonometry.js +1 -1
  46. package/dist/{p5.Renderer-D-5LdCRz.js → p5.Renderer-xpFkUQC6.js} +1 -1
  47. package/dist/{rendering-h9unX5K0.js → rendering-B8po3Onj.js} +57 -13
  48. package/dist/shape/2d_primitives.js +1 -1
  49. package/dist/shape/attributes.js +1 -1
  50. package/dist/shape/custom_shapes.js +1 -1
  51. package/dist/shape/index.js +1 -1
  52. package/dist/strands/ir_builders.js +1 -1
  53. package/dist/strands/p5.strands.js +1 -1
  54. package/dist/strands/strands_api.js +49 -18
  55. package/dist/strands/strands_conditionals.js +1 -1
  56. package/dist/strands/strands_for.js +2 -2
  57. package/dist/strands/strands_node.js +1 -1
  58. package/dist/type/index.js +2 -2
  59. package/dist/type/p5.Font.js +2 -2
  60. package/dist/type/textCore.js +2 -2
  61. package/dist/webgl/3d_primitives.js +3 -3
  62. package/dist/webgl/GeometryBuilder.js +1 -1
  63. package/dist/webgl/ShapeBuilder.js +1 -1
  64. package/dist/webgl/enums.js +1 -1
  65. package/dist/webgl/index.js +4 -4
  66. package/dist/webgl/interaction.js +1 -1
  67. package/dist/webgl/light.js +3 -3
  68. package/dist/webgl/loading.js +11 -13
  69. package/dist/webgl/material.js +3 -3
  70. package/dist/webgl/p5.Camera.js +3 -3
  71. package/dist/webgl/p5.Framebuffer.js +3 -3
  72. package/dist/webgl/p5.Geometry.js +1 -1
  73. package/dist/webgl/p5.Quat.js +1 -1
  74. package/dist/webgl/p5.RendererGL.js +4 -4
  75. package/dist/webgl/p5.Texture.js +3 -3
  76. package/dist/webgl/strands_glslBackend.js +1 -1
  77. package/dist/webgl/text.js +4 -4
  78. package/dist/webgl/utils.js +3 -3
  79. package/dist/webgpu/index.js +2 -2
  80. package/dist/webgpu/p5.RendererWebGPU.js +13 -4
  81. package/dist/webgpu/strands_wgslBackend.js +5 -4
  82. package/lib/p5.esm.js +152 -47
  83. package/lib/p5.esm.min.js +1 -1
  84. package/lib/p5.js +152 -47
  85. package/lib/p5.min.js +1 -1
  86. package/lib/p5.webgpu.esm.js +51 -9
  87. package/lib/p5.webgpu.js +51 -9
  88. package/lib/p5.webgpu.min.js +1 -1
  89. package/package.json +1 -1
  90. package/types/global.d.ts +1449 -1379
  91. package/types/p5.d.ts +727 -692
package/lib/p5.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! p5.js v2.2.1 February 11, 2026 */
1
+ /*! p5.js v2.2.2-rc.0 February 18, 2026 */
2
2
  /**
3
3
  * @module Constants
4
4
  * @submodule Constants
@@ -12,7 +12,7 @@ const _PI = Math.PI;
12
12
  * @property {String} VERSION
13
13
  * @final
14
14
  */
15
- const VERSION = '2.2.1';
15
+ const VERSION = '2.2.2-rc.0';
16
16
 
17
17
  // GRAPHICS RENDERER
18
18
  /**
@@ -61237,6 +61237,40 @@ function material(p5, fn) {
61237
61237
  * }
61238
61238
  * ```
61239
61239
  *
61240
+ * We can use the `noise()` function built into strands to generate a color for each pixel. (Again no need here for underlying content for the filter to operate on.) Again we'll animate by passing in an announced uniform variable `time` with `setUniform()`, each frame.
61241
+ *
61242
+ * ```js example
61243
+ * let myFilter;
61244
+ *
61245
+ * function setup() {
61246
+ * createCanvas(100, 100, WEBGL);
61247
+ * myFilter = buildFilterShader(noiseShaderCallback);
61248
+ * describe('Evolving animated cloud-like noise in cyan and magenta');
61249
+ * }
61250
+ *
61251
+ * function noiseShaderCallback() {
61252
+ * let time = uniformFloat();
61253
+ * filterColor.begin();
61254
+ * let coord = filterColor.texCoord;
61255
+ *
61256
+ * //generate a value roughly between 0 and 1
61257
+ * let noiseVal = noise(coord.x, coord.y, time / 2000);
61258
+ *
61259
+ * let result = mix(
61260
+ * [1, 0, 1, 1], // Magenta
61261
+ * [0, 1, 1, 1], // Cyan
61262
+ * noiseVal
61263
+ * );
61264
+ * filterColor.set(result);
61265
+ * filterColor.end();
61266
+ * }
61267
+ *
61268
+ * function draw() {
61269
+ * myFilter.setUniform("time", millis());
61270
+ * filter(myFilter);
61271
+ * }
61272
+ * ```
61273
+ *
61240
61274
  * Like the `modify()` method on shaders,
61241
61275
  * advanced users can also fill in `filterColor` using <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders" target="_blank">GLSL</a>
61242
61276
  * instead of JavaScript.
@@ -61251,15 +61285,17 @@ function material(p5, fn) {
61251
61285
  * @beta
61252
61286
  * @submodule p5.strands
61253
61287
  * @param {Function} callback A function building a p5.strands shader.
61288
+ * @param {Object} [scope] An optional scope object passed to .modify().
61254
61289
  * @returns {p5.Shader} The material shader
61255
61290
  */
61256
61291
  /**
61257
61292
  * @method buildFilterShader
61258
61293
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
61294
+ * @param {Object} [scope] An optional scope object passed to .modify().
61259
61295
  * @returns {p5.Shader} The material shader
61260
61296
  */
61261
- fn.buildFilterShader = function (callback) {
61262
- return this.baseFilterShader().modify(callback);
61297
+ fn.buildFilterShader = function (callback, scope) {
61298
+ return this.baseFilterShader().modify(callback, scope);
61263
61299
  };
61264
61300
 
61265
61301
  /**
@@ -62079,15 +62115,17 @@ function material(p5, fn) {
62079
62115
  * @submodule p5.strands
62080
62116
  * @beta
62081
62117
  * @param {Function} callback A function building a p5.strands shader.
62118
+ * @param {Object} [scope] An optional scope object passed to .modify().
62082
62119
  * @returns {p5.Shader} The material shader.
62083
62120
  */
62084
62121
  /**
62085
62122
  * @method buildMaterialShader
62086
62123
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62124
+ * @param {Object} [scope] An optional scope object passed to .modify().
62087
62125
  * @returns {p5.Shader} The material shader.
62088
62126
  */
62089
- fn.buildMaterialShader = function (cb) {
62090
- return this.baseMaterialShader().modify(cb);
62127
+ fn.buildMaterialShader = function (cb, scope) {
62128
+ return this.baseMaterialShader().modify(cb, scope);
62091
62129
  };
62092
62130
 
62093
62131
  /**
@@ -62186,7 +62224,7 @@ function material(p5, fn) {
62186
62224
  /**
62187
62225
  * Returns the base shader used for filters.
62188
62226
  *
62189
- * Calling <a href="#/p5/buildMaterialShader">`buildFilterShader(shaderFunction)`</a>
62227
+ * Calling <a href="#/p5/buildFilterShader">`buildFilterShader(shaderFunction)`</a>
62190
62228
  * is equivalent to calling `baseFilterShader().modify(shaderFunction)`.
62191
62229
  *
62192
62230
  * Read <a href="#/p5/buildFilterShader">the `buildFilterShader` reference</a> or
@@ -62295,15 +62333,17 @@ function material(p5, fn) {
62295
62333
  * @submodule p5.strands
62296
62334
  * @beta
62297
62335
  * @param {Function} callback A function building a p5.strands shader.
62336
+ * @param {Object} [scope] An optional scope object passed to .modify().
62298
62337
  * @returns {p5.Shader} The normal shader.
62299
62338
  */
62300
62339
  /**
62301
62340
  * @method buildNormalShader
62302
62341
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62342
+ * @param {Object} [scope] An optional scope object passed to .modify().
62303
62343
  * @returns {p5.Shader} The normal shader.
62304
62344
  */
62305
- fn.buildNormalShader = function (cb) {
62306
- return this.baseNormalShader().modify(cb);
62345
+ fn.buildNormalShader = function (cb, scope) {
62346
+ return this.baseNormalShader().modify(cb, scope);
62307
62347
  };
62308
62348
 
62309
62349
  /**
@@ -62459,15 +62499,17 @@ function material(p5, fn) {
62459
62499
  * @submodule p5.strands
62460
62500
  * @beta
62461
62501
  * @param {Function} callback A function building a p5.strands shader.
62502
+ * @param {Object} [scope] An optional scope object passed to .modify().
62462
62503
  * @returns {p5.Shader} The color shader.
62463
62504
  */
62464
62505
  /**
62465
62506
  * @method buildColorShader
62466
62507
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62508
+ * @param {Object} [scope] An optional scope object passed to .modify().
62467
62509
  * @returns {p5.Shader} The color shader.
62468
62510
  */
62469
- fn.buildColorShader = function (cb) {
62470
- return this.baseColorShader().modify(cb);
62511
+ fn.buildColorShader = function (cb, scope) {
62512
+ return this.baseColorShader().modify(cb, scope);
62471
62513
  };
62472
62514
 
62473
62515
  /**
@@ -62714,15 +62756,17 @@ function material(p5, fn) {
62714
62756
  * @submodule p5.strands
62715
62757
  * @beta
62716
62758
  * @param {Function} callback A function building a p5.strands shader.
62759
+ * @param {Object} [scope] An optional scope object passed to .modify().
62717
62760
  * @returns {p5.Shader} The stroke shader.
62718
62761
  */
62719
62762
  /**
62720
62763
  * @method buildStrokeShader
62721
62764
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62765
+ * @param {Object} [scope] An optional scope object passed to .modify().
62722
62766
  * @returns {p5.Shader} The stroke shader.
62723
62767
  */
62724
- fn.buildStrokeShader = function (cb) {
62725
- return this.baseStrokeShader().modify(cb);
62768
+ fn.buildStrokeShader = function (cb, scope) {
62769
+ return this.baseStrokeShader().modify(cb, scope);
62726
62770
  };
62727
62771
 
62728
62772
  /**
@@ -69201,7 +69245,7 @@ class StrandsNode {
69201
69245
  const baseType = orig?.baseType ?? BaseType.FLOAT;
69202
69246
 
69203
69247
  let newValueID;
69204
- if (value instanceof StrandsNode) {
69248
+ if (value?.isStrandsNode) {
69205
69249
  newValueID = value.id;
69206
69250
  } else {
69207
69251
  const newVal = primitiveConstructorNode(
@@ -69256,7 +69300,7 @@ class StrandsNode {
69256
69300
  const baseType = orig?.baseType ?? BaseType.FLOAT;
69257
69301
 
69258
69302
  let newValueID;
69259
- if (value instanceof StrandsNode) {
69303
+ if (value?.isStrandsNode) {
69260
69304
  newValueID = value.id;
69261
69305
  } else {
69262
69306
  const newVal = primitiveConstructorNode(
@@ -69486,7 +69530,7 @@ function unaryOpNode(strandsContext, nodeOrValue, opCode) {
69486
69530
  const { dag, cfg } = strandsContext;
69487
69531
  let dependsOn;
69488
69532
  let node;
69489
- if (nodeOrValue instanceof StrandsNode) {
69533
+ if (nodeOrValue?.isStrandsNode) {
69490
69534
  node = nodeOrValue;
69491
69535
  } else {
69492
69536
  const { id, dimension } = primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, nodeOrValue);
@@ -69686,6 +69730,20 @@ function constructTypeFromIDs(strandsContext, typeInfo, strandsNodesArray) {
69686
69730
 
69687
69731
  function primitiveConstructorNode(strandsContext, typeInfo, dependsOn) {
69688
69732
  const cfg = strandsContext.cfg;
69733
+ dependsOn = (Array.isArray(dependsOn) ? dependsOn : [dependsOn])
69734
+ .flat(Infinity)
69735
+ .map(a => {
69736
+ if (
69737
+ a.isStrandsNode &&
69738
+ a.typeInfo().baseType === BaseType.INT &&
69739
+ // TODO: handle ivec inputs instead of just int scalars
69740
+ a.typeInfo().dimension === 1
69741
+ ) {
69742
+ return castToFloat(strandsContext, a);
69743
+ } else {
69744
+ return a;
69745
+ }
69746
+ });
69689
69747
  const { mappedDependencies, inferredTypeInfo } = mapPrimitiveDepsToIDs(strandsContext, typeInfo, dependsOn);
69690
69748
 
69691
69749
  const finalType = {
@@ -69701,6 +69759,24 @@ function primitiveConstructorNode(strandsContext, typeInfo, dependsOn) {
69701
69759
  return { id, dimension: finalType.dimension, components: mappedDependencies };
69702
69760
  }
69703
69761
 
69762
+ function castToFloat(strandsContext, dep) {
69763
+ const { id, dimension } = functionCallNode(
69764
+ strandsContext,
69765
+ strandsContext.backend.getTypeName('float', dep.typeInfo().dimension),
69766
+ [dep],
69767
+ {
69768
+ overloads: [{
69769
+ params: [dep.typeInfo()],
69770
+ returnType: {
69771
+ ...dep.typeInfo(),
69772
+ baseType: BaseType.FLOAT,
69773
+ },
69774
+ }],
69775
+ }
69776
+ );
69777
+ return createStrandsNode(id, dimension, strandsContext);
69778
+ }
69779
+
69704
69780
  function structConstructorNode(strandsContext, structTypeInfo, rawUserArgs) {
69705
69781
  const { cfg, dag } = strandsContext;
69706
69782
  const { properties } = structTypeInfo;
@@ -69920,7 +69996,7 @@ function swizzleTrap(id, dimension, strandsContext, onRebind) {
69920
69996
  // This may not be the most efficient way, as we swizzle each component individually,
69921
69997
  // so that .xyz becomes .x, .y, .z
69922
69998
  let scalars = [];
69923
- if (value instanceof StrandsNode) {
69999
+ if (value?.isStrandsNode) {
69924
70000
  if (value.dimension === 1) {
69925
70001
  scalars = Array(chars.length).fill(value);
69926
70002
  } else if (value.dimension === chars.length) {
@@ -96586,7 +96662,7 @@ const verifierUtils = {
96586
96662
 
96587
96663
  try {
96588
96664
  const ast = parse(code, {
96589
- ecmaVersion: 2021,
96665
+ ecmaVersion: 'latest',
96590
96666
  sourceType: 'module',
96591
96667
  locations: true // This helps us get the line number.
96592
96668
  });
@@ -110019,12 +110095,10 @@ function loading$1(p5, fn){
110019
110095
  const vertString = tokens[vertexTokens[tokenInd]];
110020
110096
  let vertParts = vertString.split('/');
110021
110097
 
110022
- // TODO: Faces can technically use negative numbers to refer to the
110023
- // previous nth vertex. I haven't seen this used in practice, but
110024
- // it might be good to implement this in the future.
110025
-
110026
110098
  for (let i = 0; i < vertParts.length; i++) {
110027
- vertParts[i] = parseInt(vertParts[i]) - 1;
110099
+ let index = parseInt(vertParts[i]);
110100
+ if (index > 0) index -= 1; // OBJ uses 1-based indexing
110101
+ vertParts[i] = index;
110028
110102
  }
110029
110103
 
110030
110104
  if (!usedVerts[vertString]) {
@@ -110033,11 +110107,11 @@ function loading$1(p5, fn){
110033
110107
 
110034
110108
  if (usedVerts[vertString][currentMaterial] === undefined) {
110035
110109
  const vertIndex = model.vertices.length;
110036
- model.vertices.push(loadedVerts.v[vertParts[0]].copy());
110037
- model.uvs.push(loadedVerts.vt[vertParts[1]] ?
110038
- loadedVerts.vt[vertParts[1]].slice() : [0, 0]);
110039
- model.vertexNormals.push(loadedVerts.vn[vertParts[2]] ?
110040
- loadedVerts.vn[vertParts[2]].copy() : new Vector());
110110
+ model.vertices.push(loadedVerts.v.at(vertParts[0]).copy());
110111
+ model.uvs.push(loadedVerts.vt.at(vertParts[1]) ?
110112
+ loadedVerts.vt.at(vertParts[1]).slice() : [0, 0]);
110113
+ model.vertexNormals.push(loadedVerts.vn.at(vertParts[2]) ?
110114
+ loadedVerts.vn.at(vertParts[2]).copy() : new Vector());
110041
110115
 
110042
110116
  usedVerts[vertString][currentMaterial] = vertIndex;
110043
110117
  face.push(vertIndex);
@@ -120917,7 +120991,7 @@ function text(p5, fn) {
120917
120991
 
120918
120992
  if (!p5.Font.hasGlyphData(this.states.textFont)) {
120919
120993
  console.log(
120920
- 'WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported'
120994
+ 'WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported. Make sure to set the font using textFont() before drawing text.'
120921
120995
  );
120922
120996
  return;
120923
120997
  }
@@ -132149,7 +132223,7 @@ class StrandsFor {
132149
132223
  let initialVar = this.initialCb();
132150
132224
 
132151
132225
  // Convert to StrandsNode if it's not already one
132152
- if (!(initialVar instanceof StrandsNode)) {
132226
+ if (!(initialVar?.isStrandsNode)) {
132153
132227
  const { id, dimension } = primitiveConstructorNode(this.strandsContext, { baseType: BaseType.FLOAT, dimension: 1 }, initialVar);
132154
132228
  initialVar = createStrandsNode(id, dimension, this.strandsContext);
132155
132229
  }
@@ -132311,7 +132385,7 @@ function _getBuiltinGlobalsCache(strandsContext) {
132311
132385
  function getBuiltinGlobalNode(strandsContext, name) {
132312
132386
  const spec = BUILTIN_GLOBAL_SPECS[name];
132313
132387
  if (!spec) return null
132314
-
132388
+
132315
132389
  const cache = _getBuiltinGlobalsCache(strandsContext);
132316
132390
  const uniformName = `_p5_global_${name}`;
132317
132391
  const cached = cache.nodes.get(uniformName);
@@ -132409,7 +132483,7 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
132409
132483
  }
132410
132484
 
132411
132485
  // Convert value to a StrandsNode if it isn't already
132412
- const valueNode = value instanceof StrandsNode ? value : p5.strandsNode(value);
132486
+ const valueNode = value?.isStrandsNode ? value : p5.strandsNode(value);
132413
132487
 
132414
132488
  // Create a new CFG block for the early return
132415
132489
  const earlyReturnBlockID = createBasicBlock(cfg, BlockType.DEFAULT);
@@ -132624,12 +132698,17 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
132624
132698
  fn[typeInfo.fnName] = function(...args) {
132625
132699
  if (strandsContext.active) {
132626
132700
  if (args.length === 1 && args[0].dimension && args[0].dimension === typeInfo.dimension) {
132627
- const { id, dimension } = functionCallNode(strandsContext, typeInfo.fnName, args, {
132628
- overloads: [{
132629
- params: [args[0].typeInfo()],
132630
- returnType: typeInfo,
132631
- }]
132632
- });
132701
+ const { id, dimension } = functionCallNode(
132702
+ strandsContext,
132703
+ strandsContext.backend.getTypeName(typeInfo.baseType, typeInfo.dimension),
132704
+ args,
132705
+ {
132706
+ overloads: [{
132707
+ params: [args[0].typeInfo()],
132708
+ returnType: typeInfo,
132709
+ }]
132710
+ }
132711
+ );
132633
132712
  return createStrandsNode(id, dimension, strandsContext);
132634
132713
  } else {
132635
132714
  // For vector types with a single argument, repeat it for each component
@@ -132686,7 +132765,7 @@ function createHookArguments(strandsContext, parameters){
132686
132765
  const oldDependsOn = dag.dependsOn[structNode.id];
132687
132766
  const newDependsOn = [...oldDependsOn];
132688
132767
  let newValueID;
132689
- if (val instanceof StrandsNode) {
132768
+ if (val?.isStrandsNode) {
132690
132769
  newValueID = val.id;
132691
132770
  }
132692
132771
  else {
@@ -132718,7 +132797,7 @@ function createHookArguments(strandsContext, parameters){
132718
132797
  return args;
132719
132798
  }
132720
132799
  function enforceReturnTypeMatch(strandsContext, expectedType, returned, hookName) {
132721
- if (!(returned instanceof StrandsNode)) {
132800
+ if (!(returned?.isStrandsNode)) {
132722
132801
  // try {
132723
132802
  const result = primitiveConstructorNode(strandsContext, expectedType, returned);
132724
132803
  return result.id;
@@ -132740,7 +132819,12 @@ function enforceReturnTypeMatch(strandsContext, expectedType, returned, hookName
132740
132819
  };
132741
132820
  if (receivedType.dimension !== expectedType.dimension) {
132742
132821
  if (receivedType.dimension !== 1) {
132743
- userError('type error', `You have returned a vector with ${receivedType.dimension} components in ${hookName} when a ${expectedType.baseType + expectedType.dimension} was expected!`);
132822
+ const receivedTypeDisplay = receivedType.baseType + (receivedType.dimension > 1 ? receivedType.dimension : '');
132823
+ const expectedTypeDisplay = expectedType.baseType + expectedType.dimension;
132824
+ userError('type error',
132825
+ `You have returned a ${receivedTypeDisplay} in ${hookName} when a ${expectedTypeDisplay} was expected!\n\n` +
132826
+ `Make sure your hook returns the correct type.`
132827
+ );
132744
132828
  }
132745
132829
  else {
132746
132830
  const result = primitiveConstructorNode(strandsContext, expectedType, returned);
@@ -132827,10 +132911,27 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
132827
132911
  const handleRetVal = (retNode) => {
132828
132912
  if(isStructType(expectedReturnType)) {
132829
132913
  const expectedStructType = structType(expectedReturnType);
132830
- if (retNode instanceof StrandsNode) {
132914
+ if (retNode?.isStrandsNode) {
132831
132915
  const returnedNode = getNodeDataFromID(strandsContext.dag, retNode.id);
132832
132916
  if (returnedNode.baseType !== expectedStructType.typeName) {
132833
- userError("type error", `You have returned a ${retNode.baseType} from ${hookType.name} when a ${expectedStructType.typeName} was expected.`);
132917
+ const receivedTypeName = returnedNode.baseType || 'undefined';
132918
+ const receivedDim = dag.dimensions[retNode.id];
132919
+ const receivedTypeDisplay = receivedDim > 1 ?
132920
+ `${receivedTypeName}${receivedDim}` : receivedTypeName;
132921
+
132922
+ const expectedProps = expectedStructType.properties
132923
+ .map(p => p.name).join(', ');
132924
+ userError('type error',
132925
+ `You have returned a ${receivedTypeDisplay} from ${hookType.name} when a ${expectedStructType.typeName} was expected.\n\n` +
132926
+ `The ${expectedStructType.typeName} struct has these properties: { ${expectedProps} }\n\n` +
132927
+ `Instead of returning a different type, you should modify and return the ${expectedStructType.typeName} struct that was passed to your hook.\n\n` +
132928
+ `For example:\n` +
132929
+ `${hookType.name}((inputs) => {\n` +
132930
+ ` // Modify properties of inputs\n` +
132931
+ ` inputs.someProperty = ...;\n` +
132932
+ ` return inputs; // Return the modified struct\n` +
132933
+ `})`
132934
+ );
132834
132935
  }
132835
132936
  const newDeps = returnedNode.dependsOn.slice();
132836
132937
  for (let i = 0; i < expectedStructType.properties.length; i++) {
@@ -132849,10 +132950,14 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
132849
132950
  const propName = expectedProp.name;
132850
132951
  const receivedValue = retNode[propName];
132851
132952
  if (receivedValue === undefined) {
132852
- userError('type error', `You've returned an incomplete struct from ${hookType.name}.\n` +
132853
- `Expected: { ${expectedReturnType.properties.map(p => p.name).join(', ')} }\n` +
132854
- `Received: { ${Object.keys(retNode).join(', ')} }\n` +
132855
- `All of the properties are required!`);
132953
+ const expectedProps = expectedReturnType.properties.map(p => p.name).join(', ');
132954
+ const receivedProps = Object.keys(retNode).join(', ');
132955
+ userError('type error',
132956
+ `You've returned an incomplete ${expectedStructType.typeName} struct from ${hookType.name}.\n\n` +
132957
+ `Expected properties: { ${expectedProps} }\n` +
132958
+ `Received properties: { ${receivedProps} }\n\n` +
132959
+ `All properties are required! Make sure to include all properties in the returned struct.`
132960
+ );
132856
132961
  }
132857
132962
  const expectedTypeInfo = expectedProp.dataType;
132858
132963
  const returnedPropID = enforceReturnTypeMatch(strandsContext, expectedTypeInfo, receivedValue, hookType.name);