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.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
  var p5 = (function () {
3
3
  'use strict';
4
4
 
@@ -15,7 +15,7 @@ var p5 = (function () {
15
15
  * @property {String} VERSION
16
16
  * @final
17
17
  */
18
- const VERSION = '2.2.1';
18
+ const VERSION = '2.2.2-rc.0';
19
19
 
20
20
  // GRAPHICS RENDERER
21
21
  /**
@@ -61240,6 +61240,40 @@ var p5 = (function () {
61240
61240
  * }
61241
61241
  * ```
61242
61242
  *
61243
+ * 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.
61244
+ *
61245
+ * ```js example
61246
+ * let myFilter;
61247
+ *
61248
+ * function setup() {
61249
+ * createCanvas(100, 100, WEBGL);
61250
+ * myFilter = buildFilterShader(noiseShaderCallback);
61251
+ * describe('Evolving animated cloud-like noise in cyan and magenta');
61252
+ * }
61253
+ *
61254
+ * function noiseShaderCallback() {
61255
+ * let time = uniformFloat();
61256
+ * filterColor.begin();
61257
+ * let coord = filterColor.texCoord;
61258
+ *
61259
+ * //generate a value roughly between 0 and 1
61260
+ * let noiseVal = noise(coord.x, coord.y, time / 2000);
61261
+ *
61262
+ * let result = mix(
61263
+ * [1, 0, 1, 1], // Magenta
61264
+ * [0, 1, 1, 1], // Cyan
61265
+ * noiseVal
61266
+ * );
61267
+ * filterColor.set(result);
61268
+ * filterColor.end();
61269
+ * }
61270
+ *
61271
+ * function draw() {
61272
+ * myFilter.setUniform("time", millis());
61273
+ * filter(myFilter);
61274
+ * }
61275
+ * ```
61276
+ *
61243
61277
  * Like the `modify()` method on shaders,
61244
61278
  * 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>
61245
61279
  * instead of JavaScript.
@@ -61254,15 +61288,17 @@ var p5 = (function () {
61254
61288
  * @beta
61255
61289
  * @submodule p5.strands
61256
61290
  * @param {Function} callback A function building a p5.strands shader.
61291
+ * @param {Object} [scope] An optional scope object passed to .modify().
61257
61292
  * @returns {p5.Shader} The material shader
61258
61293
  */
61259
61294
  /**
61260
61295
  * @method buildFilterShader
61261
61296
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
61297
+ * @param {Object} [scope] An optional scope object passed to .modify().
61262
61298
  * @returns {p5.Shader} The material shader
61263
61299
  */
61264
- fn.buildFilterShader = function (callback) {
61265
- return this.baseFilterShader().modify(callback);
61300
+ fn.buildFilterShader = function (callback, scope) {
61301
+ return this.baseFilterShader().modify(callback, scope);
61266
61302
  };
61267
61303
 
61268
61304
  /**
@@ -62082,15 +62118,17 @@ var p5 = (function () {
62082
62118
  * @submodule p5.strands
62083
62119
  * @beta
62084
62120
  * @param {Function} callback A function building a p5.strands shader.
62121
+ * @param {Object} [scope] An optional scope object passed to .modify().
62085
62122
  * @returns {p5.Shader} The material shader.
62086
62123
  */
62087
62124
  /**
62088
62125
  * @method buildMaterialShader
62089
62126
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62127
+ * @param {Object} [scope] An optional scope object passed to .modify().
62090
62128
  * @returns {p5.Shader} The material shader.
62091
62129
  */
62092
- fn.buildMaterialShader = function (cb) {
62093
- return this.baseMaterialShader().modify(cb);
62130
+ fn.buildMaterialShader = function (cb, scope) {
62131
+ return this.baseMaterialShader().modify(cb, scope);
62094
62132
  };
62095
62133
 
62096
62134
  /**
@@ -62189,7 +62227,7 @@ var p5 = (function () {
62189
62227
  /**
62190
62228
  * Returns the base shader used for filters.
62191
62229
  *
62192
- * Calling <a href="#/p5/buildMaterialShader">`buildFilterShader(shaderFunction)`</a>
62230
+ * Calling <a href="#/p5/buildFilterShader">`buildFilterShader(shaderFunction)`</a>
62193
62231
  * is equivalent to calling `baseFilterShader().modify(shaderFunction)`.
62194
62232
  *
62195
62233
  * Read <a href="#/p5/buildFilterShader">the `buildFilterShader` reference</a> or
@@ -62298,15 +62336,17 @@ var p5 = (function () {
62298
62336
  * @submodule p5.strands
62299
62337
  * @beta
62300
62338
  * @param {Function} callback A function building a p5.strands shader.
62339
+ * @param {Object} [scope] An optional scope object passed to .modify().
62301
62340
  * @returns {p5.Shader} The normal shader.
62302
62341
  */
62303
62342
  /**
62304
62343
  * @method buildNormalShader
62305
62344
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62345
+ * @param {Object} [scope] An optional scope object passed to .modify().
62306
62346
  * @returns {p5.Shader} The normal shader.
62307
62347
  */
62308
- fn.buildNormalShader = function (cb) {
62309
- return this.baseNormalShader().modify(cb);
62348
+ fn.buildNormalShader = function (cb, scope) {
62349
+ return this.baseNormalShader().modify(cb, scope);
62310
62350
  };
62311
62351
 
62312
62352
  /**
@@ -62462,15 +62502,17 @@ var p5 = (function () {
62462
62502
  * @submodule p5.strands
62463
62503
  * @beta
62464
62504
  * @param {Function} callback A function building a p5.strands shader.
62505
+ * @param {Object} [scope] An optional scope object passed to .modify().
62465
62506
  * @returns {p5.Shader} The color shader.
62466
62507
  */
62467
62508
  /**
62468
62509
  * @method buildColorShader
62469
62510
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62511
+ * @param {Object} [scope] An optional scope object passed to .modify().
62470
62512
  * @returns {p5.Shader} The color shader.
62471
62513
  */
62472
- fn.buildColorShader = function (cb) {
62473
- return this.baseColorShader().modify(cb);
62514
+ fn.buildColorShader = function (cb, scope) {
62515
+ return this.baseColorShader().modify(cb, scope);
62474
62516
  };
62475
62517
 
62476
62518
  /**
@@ -62717,15 +62759,17 @@ var p5 = (function () {
62717
62759
  * @submodule p5.strands
62718
62760
  * @beta
62719
62761
  * @param {Function} callback A function building a p5.strands shader.
62762
+ * @param {Object} [scope] An optional scope object passed to .modify().
62720
62763
  * @returns {p5.Shader} The stroke shader.
62721
62764
  */
62722
62765
  /**
62723
62766
  * @method buildStrokeShader
62724
62767
  * @param {Object} hooks An object specifying p5.strands hooks in GLSL.
62768
+ * @param {Object} [scope] An optional scope object passed to .modify().
62725
62769
  * @returns {p5.Shader} The stroke shader.
62726
62770
  */
62727
- fn.buildStrokeShader = function (cb) {
62728
- return this.baseStrokeShader().modify(cb);
62771
+ fn.buildStrokeShader = function (cb, scope) {
62772
+ return this.baseStrokeShader().modify(cb, scope);
62729
62773
  };
62730
62774
 
62731
62775
  /**
@@ -69204,7 +69248,7 @@ var p5 = (function () {
69204
69248
  const baseType = orig?.baseType ?? BaseType.FLOAT;
69205
69249
 
69206
69250
  let newValueID;
69207
- if (value instanceof StrandsNode) {
69251
+ if (value?.isStrandsNode) {
69208
69252
  newValueID = value.id;
69209
69253
  } else {
69210
69254
  const newVal = primitiveConstructorNode(
@@ -69259,7 +69303,7 @@ var p5 = (function () {
69259
69303
  const baseType = orig?.baseType ?? BaseType.FLOAT;
69260
69304
 
69261
69305
  let newValueID;
69262
- if (value instanceof StrandsNode) {
69306
+ if (value?.isStrandsNode) {
69263
69307
  newValueID = value.id;
69264
69308
  } else {
69265
69309
  const newVal = primitiveConstructorNode(
@@ -69489,7 +69533,7 @@ var p5 = (function () {
69489
69533
  const { dag, cfg } = strandsContext;
69490
69534
  let dependsOn;
69491
69535
  let node;
69492
- if (nodeOrValue instanceof StrandsNode) {
69536
+ if (nodeOrValue?.isStrandsNode) {
69493
69537
  node = nodeOrValue;
69494
69538
  } else {
69495
69539
  const { id, dimension } = primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, nodeOrValue);
@@ -69689,6 +69733,20 @@ var p5 = (function () {
69689
69733
 
69690
69734
  function primitiveConstructorNode(strandsContext, typeInfo, dependsOn) {
69691
69735
  const cfg = strandsContext.cfg;
69736
+ dependsOn = (Array.isArray(dependsOn) ? dependsOn : [dependsOn])
69737
+ .flat(Infinity)
69738
+ .map(a => {
69739
+ if (
69740
+ a.isStrandsNode &&
69741
+ a.typeInfo().baseType === BaseType.INT &&
69742
+ // TODO: handle ivec inputs instead of just int scalars
69743
+ a.typeInfo().dimension === 1
69744
+ ) {
69745
+ return castToFloat(strandsContext, a);
69746
+ } else {
69747
+ return a;
69748
+ }
69749
+ });
69692
69750
  const { mappedDependencies, inferredTypeInfo } = mapPrimitiveDepsToIDs(strandsContext, typeInfo, dependsOn);
69693
69751
 
69694
69752
  const finalType = {
@@ -69704,6 +69762,24 @@ var p5 = (function () {
69704
69762
  return { id, dimension: finalType.dimension, components: mappedDependencies };
69705
69763
  }
69706
69764
 
69765
+ function castToFloat(strandsContext, dep) {
69766
+ const { id, dimension } = functionCallNode(
69767
+ strandsContext,
69768
+ strandsContext.backend.getTypeName('float', dep.typeInfo().dimension),
69769
+ [dep],
69770
+ {
69771
+ overloads: [{
69772
+ params: [dep.typeInfo()],
69773
+ returnType: {
69774
+ ...dep.typeInfo(),
69775
+ baseType: BaseType.FLOAT,
69776
+ },
69777
+ }],
69778
+ }
69779
+ );
69780
+ return createStrandsNode(id, dimension, strandsContext);
69781
+ }
69782
+
69707
69783
  function structConstructorNode(strandsContext, structTypeInfo, rawUserArgs) {
69708
69784
  const { cfg, dag } = strandsContext;
69709
69785
  const { properties } = structTypeInfo;
@@ -69923,7 +69999,7 @@ var p5 = (function () {
69923
69999
  // This may not be the most efficient way, as we swizzle each component individually,
69924
70000
  // so that .xyz becomes .x, .y, .z
69925
70001
  let scalars = [];
69926
- if (value instanceof StrandsNode) {
70002
+ if (value?.isStrandsNode) {
69927
70003
  if (value.dimension === 1) {
69928
70004
  scalars = Array(chars.length).fill(value);
69929
70005
  } else if (value.dimension === chars.length) {
@@ -96589,7 +96665,7 @@ var p5 = (function () {
96589
96665
 
96590
96666
  try {
96591
96667
  const ast = parse(code, {
96592
- ecmaVersion: 2021,
96668
+ ecmaVersion: 'latest',
96593
96669
  sourceType: 'module',
96594
96670
  locations: true // This helps us get the line number.
96595
96671
  });
@@ -110022,12 +110098,10 @@ var p5 = (function () {
110022
110098
  const vertString = tokens[vertexTokens[tokenInd]];
110023
110099
  let vertParts = vertString.split('/');
110024
110100
 
110025
- // TODO: Faces can technically use negative numbers to refer to the
110026
- // previous nth vertex. I haven't seen this used in practice, but
110027
- // it might be good to implement this in the future.
110028
-
110029
110101
  for (let i = 0; i < vertParts.length; i++) {
110030
- vertParts[i] = parseInt(vertParts[i]) - 1;
110102
+ let index = parseInt(vertParts[i]);
110103
+ if (index > 0) index -= 1; // OBJ uses 1-based indexing
110104
+ vertParts[i] = index;
110031
110105
  }
110032
110106
 
110033
110107
  if (!usedVerts[vertString]) {
@@ -110036,11 +110110,11 @@ var p5 = (function () {
110036
110110
 
110037
110111
  if (usedVerts[vertString][currentMaterial] === undefined) {
110038
110112
  const vertIndex = model.vertices.length;
110039
- model.vertices.push(loadedVerts.v[vertParts[0]].copy());
110040
- model.uvs.push(loadedVerts.vt[vertParts[1]] ?
110041
- loadedVerts.vt[vertParts[1]].slice() : [0, 0]);
110042
- model.vertexNormals.push(loadedVerts.vn[vertParts[2]] ?
110043
- loadedVerts.vn[vertParts[2]].copy() : new Vector());
110113
+ model.vertices.push(loadedVerts.v.at(vertParts[0]).copy());
110114
+ model.uvs.push(loadedVerts.vt.at(vertParts[1]) ?
110115
+ loadedVerts.vt.at(vertParts[1]).slice() : [0, 0]);
110116
+ model.vertexNormals.push(loadedVerts.vn.at(vertParts[2]) ?
110117
+ loadedVerts.vn.at(vertParts[2]).copy() : new Vector());
110044
110118
 
110045
110119
  usedVerts[vertString][currentMaterial] = vertIndex;
110046
110120
  face.push(vertIndex);
@@ -120920,7 +120994,7 @@ var p5 = (function () {
120920
120994
 
120921
120995
  if (!p5.Font.hasGlyphData(this.states.textFont)) {
120922
120996
  console.log(
120923
- 'WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported'
120997
+ 'WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported. Make sure to set the font using textFont() before drawing text.'
120924
120998
  );
120925
120999
  return;
120926
121000
  }
@@ -132152,7 +132226,7 @@ var p5 = (function () {
132152
132226
  let initialVar = this.initialCb();
132153
132227
 
132154
132228
  // Convert to StrandsNode if it's not already one
132155
- if (!(initialVar instanceof StrandsNode)) {
132229
+ if (!(initialVar?.isStrandsNode)) {
132156
132230
  const { id, dimension } = primitiveConstructorNode(this.strandsContext, { baseType: BaseType.FLOAT, dimension: 1 }, initialVar);
132157
132231
  initialVar = createStrandsNode(id, dimension, this.strandsContext);
132158
132232
  }
@@ -132314,7 +132388,7 @@ var p5 = (function () {
132314
132388
  function getBuiltinGlobalNode(strandsContext, name) {
132315
132389
  const spec = BUILTIN_GLOBAL_SPECS[name];
132316
132390
  if (!spec) return null
132317
-
132391
+
132318
132392
  const cache = _getBuiltinGlobalsCache(strandsContext);
132319
132393
  const uniformName = `_p5_global_${name}`;
132320
132394
  const cached = cache.nodes.get(uniformName);
@@ -132412,7 +132486,7 @@ var p5 = (function () {
132412
132486
  }
132413
132487
 
132414
132488
  // Convert value to a StrandsNode if it isn't already
132415
- const valueNode = value instanceof StrandsNode ? value : p5.strandsNode(value);
132489
+ const valueNode = value?.isStrandsNode ? value : p5.strandsNode(value);
132416
132490
 
132417
132491
  // Create a new CFG block for the early return
132418
132492
  const earlyReturnBlockID = createBasicBlock(cfg, BlockType.DEFAULT);
@@ -132627,12 +132701,17 @@ var p5 = (function () {
132627
132701
  fn[typeInfo.fnName] = function(...args) {
132628
132702
  if (strandsContext.active) {
132629
132703
  if (args.length === 1 && args[0].dimension && args[0].dimension === typeInfo.dimension) {
132630
- const { id, dimension } = functionCallNode(strandsContext, typeInfo.fnName, args, {
132631
- overloads: [{
132632
- params: [args[0].typeInfo()],
132633
- returnType: typeInfo,
132634
- }]
132635
- });
132704
+ const { id, dimension } = functionCallNode(
132705
+ strandsContext,
132706
+ strandsContext.backend.getTypeName(typeInfo.baseType, typeInfo.dimension),
132707
+ args,
132708
+ {
132709
+ overloads: [{
132710
+ params: [args[0].typeInfo()],
132711
+ returnType: typeInfo,
132712
+ }]
132713
+ }
132714
+ );
132636
132715
  return createStrandsNode(id, dimension, strandsContext);
132637
132716
  } else {
132638
132717
  // For vector types with a single argument, repeat it for each component
@@ -132689,7 +132768,7 @@ var p5 = (function () {
132689
132768
  const oldDependsOn = dag.dependsOn[structNode.id];
132690
132769
  const newDependsOn = [...oldDependsOn];
132691
132770
  let newValueID;
132692
- if (val instanceof StrandsNode) {
132771
+ if (val?.isStrandsNode) {
132693
132772
  newValueID = val.id;
132694
132773
  }
132695
132774
  else {
@@ -132721,7 +132800,7 @@ var p5 = (function () {
132721
132800
  return args;
132722
132801
  }
132723
132802
  function enforceReturnTypeMatch(strandsContext, expectedType, returned, hookName) {
132724
- if (!(returned instanceof StrandsNode)) {
132803
+ if (!(returned?.isStrandsNode)) {
132725
132804
  // try {
132726
132805
  const result = primitiveConstructorNode(strandsContext, expectedType, returned);
132727
132806
  return result.id;
@@ -132743,7 +132822,12 @@ var p5 = (function () {
132743
132822
  };
132744
132823
  if (receivedType.dimension !== expectedType.dimension) {
132745
132824
  if (receivedType.dimension !== 1) {
132746
- userError('type error', `You have returned a vector with ${receivedType.dimension} components in ${hookName} when a ${expectedType.baseType + expectedType.dimension} was expected!`);
132825
+ const receivedTypeDisplay = receivedType.baseType + (receivedType.dimension > 1 ? receivedType.dimension : '');
132826
+ const expectedTypeDisplay = expectedType.baseType + expectedType.dimension;
132827
+ userError('type error',
132828
+ `You have returned a ${receivedTypeDisplay} in ${hookName} when a ${expectedTypeDisplay} was expected!\n\n` +
132829
+ `Make sure your hook returns the correct type.`
132830
+ );
132747
132831
  }
132748
132832
  else {
132749
132833
  const result = primitiveConstructorNode(strandsContext, expectedType, returned);
@@ -132830,10 +132914,27 @@ var p5 = (function () {
132830
132914
  const handleRetVal = (retNode) => {
132831
132915
  if(isStructType(expectedReturnType)) {
132832
132916
  const expectedStructType = structType(expectedReturnType);
132833
- if (retNode instanceof StrandsNode) {
132917
+ if (retNode?.isStrandsNode) {
132834
132918
  const returnedNode = getNodeDataFromID(strandsContext.dag, retNode.id);
132835
132919
  if (returnedNode.baseType !== expectedStructType.typeName) {
132836
- userError("type error", `You have returned a ${retNode.baseType} from ${hookType.name} when a ${expectedStructType.typeName} was expected.`);
132920
+ const receivedTypeName = returnedNode.baseType || 'undefined';
132921
+ const receivedDim = dag.dimensions[retNode.id];
132922
+ const receivedTypeDisplay = receivedDim > 1 ?
132923
+ `${receivedTypeName}${receivedDim}` : receivedTypeName;
132924
+
132925
+ const expectedProps = expectedStructType.properties
132926
+ .map(p => p.name).join(', ');
132927
+ userError('type error',
132928
+ `You have returned a ${receivedTypeDisplay} from ${hookType.name} when a ${expectedStructType.typeName} was expected.\n\n` +
132929
+ `The ${expectedStructType.typeName} struct has these properties: { ${expectedProps} }\n\n` +
132930
+ `Instead of returning a different type, you should modify and return the ${expectedStructType.typeName} struct that was passed to your hook.\n\n` +
132931
+ `For example:\n` +
132932
+ `${hookType.name}((inputs) => {\n` +
132933
+ ` // Modify properties of inputs\n` +
132934
+ ` inputs.someProperty = ...;\n` +
132935
+ ` return inputs; // Return the modified struct\n` +
132936
+ `})`
132937
+ );
132837
132938
  }
132838
132939
  const newDeps = returnedNode.dependsOn.slice();
132839
132940
  for (let i = 0; i < expectedStructType.properties.length; i++) {
@@ -132852,10 +132953,14 @@ var p5 = (function () {
132852
132953
  const propName = expectedProp.name;
132853
132954
  const receivedValue = retNode[propName];
132854
132955
  if (receivedValue === undefined) {
132855
- userError('type error', `You've returned an incomplete struct from ${hookType.name}.\n` +
132856
- `Expected: { ${expectedReturnType.properties.map(p => p.name).join(', ')} }\n` +
132857
- `Received: { ${Object.keys(retNode).join(', ')} }\n` +
132858
- `All of the properties are required!`);
132956
+ const expectedProps = expectedReturnType.properties.map(p => p.name).join(', ');
132957
+ const receivedProps = Object.keys(retNode).join(', ');
132958
+ userError('type error',
132959
+ `You've returned an incomplete ${expectedStructType.typeName} struct from ${hookType.name}.\n\n` +
132960
+ `Expected properties: { ${expectedProps} }\n` +
132961
+ `Received properties: { ${receivedProps} }\n\n` +
132962
+ `All properties are required! Make sure to include all properties in the returned struct.`
132963
+ );
132859
132964
  }
132860
132965
  const expectedTypeInfo = expectedProp.dataType;
132861
132966
  const returnedPropID = enforceReturnTypeMatch(strandsContext, expectedTypeInfo, receivedValue, hookType.name);