p5 2.3.0 → 2.3.1-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 (103) hide show
  1. package/README.md +3 -11
  2. package/dist/accessibility/color_namer.js +7 -7
  3. package/dist/accessibility/index.js +7 -7
  4. package/dist/app.js +7 -7
  5. package/dist/app.node.js +7 -7
  6. package/dist/color/color_conversion.js +7 -7
  7. package/dist/color/creating_reading.js +1 -1
  8. package/dist/color/index.js +2 -2
  9. package/dist/color/p5.Color.js +1 -1
  10. package/dist/color/setting.js +2 -2
  11. package/dist/{constants-Dv6ZqA6s.js → constants-Bx3_xAam.js} +1 -1
  12. package/dist/core/constants.js +1 -1
  13. package/dist/core/environment.js +1 -1
  14. package/dist/core/filterShaders.js +1 -1
  15. package/dist/core/friendly_errors/fes_core.js +1 -1
  16. package/dist/core/friendly_errors/file_errors.js +1 -1
  17. package/dist/core/friendly_errors/index.js +1 -1
  18. package/dist/core/friendly_errors/param_validator.js +1 -1
  19. package/dist/core/friendly_errors/sketch_verifier.js +1 -1
  20. package/dist/core/helpers.js +1 -1
  21. package/dist/core/init.js +7 -7
  22. package/dist/core/internationalization.js +1 -1
  23. package/dist/core/legacy.js +7 -7
  24. package/dist/core/main.js +7 -7
  25. package/dist/core/p5.Graphics.js +4 -4
  26. package/dist/core/p5.Renderer.js +3 -3
  27. package/dist/core/p5.Renderer2D.js +7 -7
  28. package/dist/core/p5.Renderer3D.js +4 -4
  29. package/dist/core/rendering.js +4 -4
  30. package/dist/{creating_reading-DLkHH80h.js → creating_reading-YUSK33h8.js} +8 -0
  31. package/dist/dom/dom.js +2 -2
  32. package/dist/dom/index.js +2 -2
  33. package/dist/dom/p5.Element.js +2 -2
  34. package/dist/dom/p5.MediaElement.js +2 -2
  35. package/dist/events/pointer.js +15 -0
  36. package/dist/image/const.js +1 -1
  37. package/dist/image/filterRenderer2D.js +6 -6
  38. package/dist/image/image.js +4 -4
  39. package/dist/image/index.js +4 -4
  40. package/dist/image/loading_displaying.js +4 -4
  41. package/dist/image/p5.Image.js +3 -3
  42. package/dist/io/files.js +4 -4
  43. package/dist/io/index.js +4 -4
  44. package/dist/{ir_builders-C8mrXj5z.js → ir_builders-CMXkjMoV.js} +34 -24
  45. package/dist/{main-BR2ALC_6.js → main-BpW7VbDr.js} +39 -208
  46. package/dist/math/Matrices/Matrix.js +1 -1
  47. package/dist/math/Matrices/MatrixNumjs.js +1 -1
  48. package/dist/math/calculation.js +669 -84
  49. package/dist/math/index.js +1 -1
  50. package/dist/math/p5.Matrix.js +1 -1
  51. package/dist/math/p5.Vector.js +9 -1
  52. package/dist/math/patch-vector.js +3 -1
  53. package/dist/math/trigonometry.js +399 -48
  54. package/dist/{p5.Renderer-XOvhEbJn.js → p5.Renderer-op0Y1WO6.js} +2 -2
  55. package/dist/{rendering-C5lX6zKm.js → rendering-SZ71KIDM.js} +24 -9
  56. package/dist/shape/2d_primitives.js +1 -1
  57. package/dist/shape/attributes.js +4 -3
  58. package/dist/shape/custom_shapes.js +205 -3
  59. package/dist/shape/index.js +2 -2
  60. package/dist/strands/ir_builders.js +1 -1
  61. package/dist/strands/p5.strands.js +26 -9
  62. package/dist/strands/strands_FES.js +8 -1
  63. package/dist/strands/strands_api.js +316 -21
  64. package/dist/strands/strands_conditionals.js +1 -1
  65. package/dist/strands/strands_for.js +1 -1
  66. package/dist/strands/strands_node.js +1 -1
  67. package/dist/strands/strands_ternary.js +1 -1
  68. package/dist/{strands_glslBackend-D6G3UyCs.js → strands_glslBackend-DMhOnoGl.js} +2 -2
  69. package/dist/type/index.js +3 -3
  70. package/dist/type/p5.Font.js +13 -4
  71. package/dist/type/textCore.js +3 -3
  72. package/dist/webgl/3d_primitives.js +4 -4
  73. package/dist/webgl/GeometryBuilder.js +1 -1
  74. package/dist/webgl/ShapeBuilder.js +1 -1
  75. package/dist/webgl/enums.js +1 -1
  76. package/dist/webgl/index.js +6 -6
  77. package/dist/webgl/interaction.js +1 -1
  78. package/dist/webgl/light.js +4 -4
  79. package/dist/webgl/loading.js +4 -4
  80. package/dist/webgl/material.js +4 -4
  81. package/dist/webgl/p5.Camera.js +4 -4
  82. package/dist/webgl/p5.Framebuffer.js +4 -4
  83. package/dist/webgl/p5.Geometry.js +1 -1
  84. package/dist/webgl/p5.Quat.js +1 -1
  85. package/dist/webgl/p5.RendererGL.js +6 -6
  86. package/dist/webgl/p5.Shader.js +5 -1
  87. package/dist/webgl/p5.Texture.js +4 -4
  88. package/dist/webgl/strands_glslBackend.js +2 -2
  89. package/dist/webgl/text.js +4 -4
  90. package/dist/webgl/utils.js +4 -4
  91. package/dist/webgpu/index.js +2 -2
  92. package/dist/webgpu/p5.RendererWebGPU.js +2 -2
  93. package/dist/webgpu/strands_wgslBackend.js +2 -2
  94. package/lib/p5.esm.js +1765 -405
  95. package/lib/p5.esm.min.js +1 -1
  96. package/lib/p5.js +1765 -405
  97. package/lib/p5.min.js +1 -1
  98. package/lib/p5.webgpu.esm.js +34 -3
  99. package/lib/p5.webgpu.js +34 -3
  100. package/lib/p5.webgpu.min.js +1 -1
  101. package/package.json +1 -1
  102. package/types/global.d.ts +5539 -2604
  103. package/types/p5.d.ts +2917 -1432
package/lib/p5.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! p5.js v2.3.0 May 28, 2026 */
1
+ /*! p5.js v2.3.1-rc.1 June 24, 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.3.0';
18
+ const VERSION = '2.3.1-rc.1';
19
19
 
20
20
  // GRAPHICS RENDERER
21
21
  /**
@@ -11360,6 +11360,14 @@ var p5 = (function () {
11360
11360
  * The version of `color()` with four parameters interprets them as RGBA, HSBA,
11361
11361
  * or HSLA colors, depending on the current `colorMode()`. The last parameter
11362
11362
  * sets the alpha (transparency) value.
11363
+ * In p5.strands shader callbacks, `color()` accepts the same input
11364
+ * formats but returns a `vec4` instead of a `p5.Color` object, with
11365
+ * RGBA components normalized to the 0–1 range. All colors in strands
11366
+ * are RGB-based; `colorMode()` has no effect inside shader callbacks.
11367
+ * Color utility functions such as `red()`, `green()`, `blue()`,
11368
+ * `alpha()`, `hue()`, `saturation()`, `brightness()`, and
11369
+ * `lightness()` also return values in the 0–1 range when used in
11370
+ * strands.
11363
11371
  *
11364
11372
  * @method color
11365
11373
  * @param {Number} gray number specifying value between white and black.
@@ -17533,7 +17541,7 @@ var p5 = (function () {
17533
17541
  */
17534
17542
 
17535
17543
 
17536
- class Image {
17544
+ let Image$1 = class Image {
17537
17545
  constructor(width, height) {
17538
17546
  this.width = width;
17539
17547
  this.height = height;
@@ -19316,7 +19324,7 @@ var p5 = (function () {
19316
19324
  }
19317
19325
  }
19318
19326
  }
19319
- }
19327
+ };
19320
19328
  function encodeAndDownloadGif(pImg, filename) {
19321
19329
  const props = pImg.gifProperties;
19322
19330
 
@@ -19618,9 +19626,9 @@ var p5 = (function () {
19618
19626
  * @param {Number} width
19619
19627
  * @param {Number} height
19620
19628
  */
19621
- p5.Image = Image;
19629
+ p5.Image = Image$1;
19622
19630
 
19623
- Image.prototype._friendlyError = p5._friendlyError;
19631
+ Image$1.prototype._friendlyError = p5._friendlyError;
19624
19632
 
19625
19633
  /**
19626
19634
  * The image's width in pixels.
@@ -23468,6 +23476,14 @@ var p5 = (function () {
23468
23476
  * @property z
23469
23477
  * @name z
23470
23478
  */
23479
+
23480
+ /**
23481
+ * The dimensions of the vector
23482
+ * @type {Number}
23483
+ * @for p5.Vector
23484
+ * @property dimensions
23485
+ * @name dimensions
23486
+ */
23471
23487
  }
23472
23488
 
23473
23489
  if (typeof p5 !== 'undefined') {
@@ -24015,6 +24031,47 @@ var p5 = (function () {
24015
24031
  }
24016
24032
  }
24017
24033
 
24034
+ class RectPrimitive extends ShapePrimitive {
24035
+ #x;
24036
+ #y;
24037
+ #w;
24038
+ #h;
24039
+ #tl;
24040
+ #tr;
24041
+ #br;
24042
+ #bl;
24043
+ #vertexCapacity = 1;
24044
+
24045
+ constructor(startVertex, x, y, w, h, tl, tr, br, bl) {
24046
+ super(startVertex);
24047
+ this.#x = x;
24048
+ this.#y = y;
24049
+ this.#w = w;
24050
+ this.#h = h;
24051
+ this.#tl = tl;
24052
+ this.#tr = tr;
24053
+ this.#br = br;
24054
+ this.#bl = bl;
24055
+ }
24056
+
24057
+ get x() { return this.#x; }
24058
+ get y() { return this.#y; }
24059
+ get w() { return this.#w; }
24060
+ get h() { return this.#h; }
24061
+ get tl() { return this.#tl; }
24062
+ get tr() { return this.#tr; }
24063
+ get br() { return this.#br; }
24064
+ get bl() { return this.#bl; }
24065
+
24066
+ get vertexCapacity() {
24067
+ return this.#vertexCapacity;
24068
+ }
24069
+
24070
+ accept(visitor) {
24071
+ visitor.visitRectPrimitive(this);
24072
+ }
24073
+ }
24074
+
24018
24075
  // ---- TESSELLATION PRIMITIVES ----
24019
24076
 
24020
24077
  class TriangleFan extends ShapePrimitive {
@@ -24497,6 +24554,42 @@ var p5 = (function () {
24497
24554
  return primitive.addToShape(this);
24498
24555
  }
24499
24556
 
24557
+ rectPrimitive(x, y, w, h, tl, tr, br, bl) {
24558
+ const startVertex = this.#createVertex(new Vector(x, y));
24559
+ const primitive = new RectPrimitive(startVertex, x, y, w, h, tl, tr, br, bl);
24560
+ return primitive.addToShape(this);
24561
+ }
24562
+
24563
+ point(x, y) {
24564
+ const v0 = this.#createVertex(new Vector(x, y));
24565
+ const primitive = new Point(v0);
24566
+ return primitive.addToShape(this);
24567
+ }
24568
+
24569
+ line(x1, y1, x2, y2) {
24570
+ const v0 = this.#createVertex(new Vector(x1, y1));
24571
+ const v1 = this.#createVertex(new Vector(x2, y2));
24572
+ const primitive = new Line(v0, v1);
24573
+ return primitive.addToShape(this);
24574
+ }
24575
+
24576
+ triangle(x1, y1, x2, y2, x3, y3) {
24577
+ const v0 = this.#createVertex(new Vector(x1, y1));
24578
+ const v1 = this.#createVertex(new Vector(x2, y2));
24579
+ const v2 = this.#createVertex(new Vector(x3, y3));
24580
+ const primitive = new Triangle(v0, v1, v2);
24581
+ return primitive.addToShape(this);
24582
+ }
24583
+
24584
+ quad(x1, y1, x2, y2, x3, y3, x4, y4) {
24585
+ const v0 = this.#createVertex(new Vector(x1, y1));
24586
+ const v1 = this.#createVertex(new Vector(x2, y2));
24587
+ const v2 = this.#createVertex(new Vector(x3, y3));
24588
+ const v3 = this.#createVertex(new Vector(x4, y4));
24589
+ const primitive = new Quad(v0, v1, v2, v3);
24590
+ return primitive.addToShape(this);
24591
+ }
24592
+
24500
24593
  beginContour(shapeKind = PATH) {
24501
24594
  if (this.at(-1)?.kind === EMPTY_PATH) {
24502
24595
  this.contours.pop();
@@ -24601,6 +24694,9 @@ var p5 = (function () {
24601
24694
  visitEllipsePrimitive(ellipse) {
24602
24695
  throw new Error('Method visitEllipsePrimitive() has not been implemented.');
24603
24696
  }
24697
+ visitRectPrimitive(rect) {
24698
+ throw new Error('Method visitRectPrimitive() has not been implemented.');
24699
+ }
24604
24700
 
24605
24701
  // isolated primitives
24606
24702
  visitPoint(point) {
@@ -24804,6 +24900,62 @@ var p5 = (function () {
24804
24900
  this.path.moveTo(centerX + radiusX, centerY);
24805
24901
  this.path.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, 2 * Math.PI);
24806
24902
  }
24903
+ visitRectPrimitive(rect) {
24904
+ const x = rect.x;
24905
+ const y = rect.y;
24906
+ const w = rect.w;
24907
+ const h = rect.h;
24908
+ let tl = rect.tl;
24909
+ let tr = rect.tr;
24910
+ let br = rect.br;
24911
+ let bl = rect.bl;
24912
+
24913
+ if (typeof tl === 'undefined') {
24914
+ this.path.rect(x, y, w, h);
24915
+ } else {
24916
+ if (typeof tr === 'undefined') {
24917
+ tr = tl;
24918
+ }
24919
+ if (typeof br === 'undefined') {
24920
+ br = tr;
24921
+ }
24922
+ if (typeof bl === 'undefined') {
24923
+ bl = br;
24924
+ }
24925
+
24926
+ const absW = Math.abs(w);
24927
+ const absH = Math.abs(h);
24928
+ const hw = absW / 2;
24929
+ const hh = absH / 2;
24930
+
24931
+ if (absW < 2 * tl) {
24932
+ tl = hw;
24933
+ }
24934
+ if (absH < 2 * tl) {
24935
+ tl = hh;
24936
+ }
24937
+ if (absW < 2 * tr) {
24938
+ tr = hw;
24939
+ }
24940
+ if (absH < 2 * tr) {
24941
+ tr = hh;
24942
+ }
24943
+ if (absW < 2 * br) {
24944
+ br = hw;
24945
+ }
24946
+ if (absH < 2 * br) {
24947
+ br = hh;
24948
+ }
24949
+ if (absW < 2 * bl) {
24950
+ bl = hw;
24951
+ }
24952
+ if (absH < 2 * bl) {
24953
+ bl = hh;
24954
+ }
24955
+
24956
+ this.path.roundRect(x, y, w, h, [tl, tr, br, bl]);
24957
+ }
24958
+ }
24807
24959
  visitQuadStrip(quadStrip) {
24808
24960
  for (let i = 0; i < quadStrip.vertices.length - 3; i += 2) {
24809
24961
  const v0 = quadStrip.vertices[i];
@@ -25000,6 +25152,72 @@ var p5 = (function () {
25000
25152
  verts.push(new Vertex(vertexProps));
25001
25153
  }
25002
25154
 
25155
+ this.contours.push(verts);
25156
+ }
25157
+ visitRectPrimitive(rect) {
25158
+ const x = rect.x;
25159
+ const y = rect.y;
25160
+ const w = rect.w;
25161
+ const h = rect.h;
25162
+ let tl = rect.tl;
25163
+ let tr = rect.tr;
25164
+ let br = rect.br;
25165
+ let bl = rect.bl;
25166
+
25167
+ const startVertex = rect.vertices[0];
25168
+ const getVertexProps = (px, py) => {
25169
+ const props = {};
25170
+ for (const [key, value] of Object.entries(startVertex)) {
25171
+ if (key === 'position') continue;
25172
+ props[key] = value;
25173
+ }
25174
+ props.position = new Vector(px, py);
25175
+ return new Vertex(props);
25176
+ };
25177
+
25178
+ const verts = [];
25179
+ if (typeof tl === 'undefined') {
25180
+ verts.push(getVertexProps(x, y));
25181
+ verts.push(getVertexProps(x + w, y));
25182
+ verts.push(getVertexProps(x + w, y + h));
25183
+ verts.push(getVertexProps(x, y + h));
25184
+ verts.push(getVertexProps(x, y));
25185
+ } else {
25186
+ if (typeof tr === 'undefined') tr = tl;
25187
+ if (typeof br === 'undefined') br = tr;
25188
+ if (typeof bl === 'undefined') bl = br;
25189
+
25190
+ const absW = Math.abs(w);
25191
+ const absH = Math.abs(h);
25192
+ const hw = absW / 2;
25193
+ const hh = absH / 2;
25194
+
25195
+ if (absW < 2 * tl) tl = hw;
25196
+ if (absH < 2 * tl) tl = hh;
25197
+ if (absW < 2 * tr) tr = hw;
25198
+ if (absH < 2 * tr) tr = hh;
25199
+ if (absW < 2 * br) br = hw;
25200
+ if (absH < 2 * br) br = hh;
25201
+ if (absW < 2 * bl) bl = hw;
25202
+ if (absH < 2 * bl) bl = hh;
25203
+
25204
+ const addCornerArc = (cx, cy, rx, ry, startAngle, endAngle) => {
25205
+ const perimeter = Math.PI / 2 * (rx + ry) / 2;
25206
+ const numPoints = Math.max(1, Math.ceil(this.curveDetail * perimeter));
25207
+ for (let i = 0; i <= numPoints; i++) {
25208
+ const angle = startAngle + (endAngle - startAngle) * (i / numPoints);
25209
+ verts.push(getVertexProps(cx + rx * Math.cos(angle), cy + ry * Math.sin(angle)));
25210
+ }
25211
+ };
25212
+
25213
+ addCornerArc(x + tl, y + tl, tl, tl, Math.PI, 1.5 * Math.PI);
25214
+ addCornerArc(x + w - tr, y + tr, tr, tr, 1.5 * Math.PI, 2 * Math.PI);
25215
+ addCornerArc(x + w - br, y + h - br, br, br, 0, 0.5 * Math.PI);
25216
+ addCornerArc(x + bl, y + h - bl, bl, bl, 0.5 * Math.PI, Math.PI);
25217
+
25218
+ verts.push(verts[0]);
25219
+ }
25220
+
25003
25221
  this.contours.push(verts);
25004
25222
  }
25005
25223
  }
@@ -26844,7 +27062,7 @@ var p5 = (function () {
26844
27062
  // get(x,y,w,h)
26845
27063
  }
26846
27064
 
26847
- const region = new Image(w*pd, h*pd);
27065
+ const region = new Image$1(w*pd, h*pd);
26848
27066
  region.pixelDensity(pd);
26849
27067
  region.canvas
26850
27068
  .getContext('2d')
@@ -30605,8 +30823,9 @@ var p5 = (function () {
30605
30823
  * Sets the width of the stroke used for points, lines, and the outlines of
30606
30824
  * shapes.
30607
30825
  *
30608
- * Note: `strokeWeight()` is affected by transformations, especially calls to
30609
- * <a href="#/p5/scale">scale()</a>.
30826
+ * Note: In 2D mode, `strokeWeight()` is affected by transformations,
30827
+ * especially calls to <a href="#/p5/scale">scale()</a>. It isn't affected by
30828
+ * transformations in WebGL and WebGPU modes.
30610
30829
  *
30611
30830
  * Calling `strokeWeight()` without an argument returns the current stroke weight as a number.
30612
30831
  *
@@ -38986,8 +39205,19 @@ var p5 = (function () {
38986
39205
 
38987
39206
  } else {
38988
39207
  // Non-GIF Section
38989
- const blob = new Blob([data]);
38990
- const img = await createImageBitmap(blob);
39208
+ const img = await new Promise((resolve, reject) => {
39209
+ const img = new Image();
39210
+ const blob = new Blob([data], { type: contentType });
39211
+ const url = URL.createObjectURL(blob);
39212
+
39213
+ img.onerror = e => reject(e);
39214
+ img.onload = () => {
39215
+ URL.revokeObjectURL(url);
39216
+ resolve(img);
39217
+ };
39218
+
39219
+ img.src = url;
39220
+ });
38991
39221
 
38992
39222
  pImg.width = pImg.canvas.width = img.width;
38993
39223
  pImg.height = pImg.canvas.height = img.height;
@@ -55057,7 +55287,11 @@ var p5 = (function () {
55057
55287
  // the next time a shader is used. However, the texture() function
55058
55288
  // works differently and is global p5 state. If the p5 state has
55059
55289
  // been cleared, we also need to clear the value in uSampler to match.
55060
- fillShader.setUniform("uSampler", this.states._tex || empty);
55290
+ this._settingFillUniforms = true;
55291
+ if (this.states._tex || !fillShader._userSetSampler) {
55292
+ fillShader.setUniform("uSampler", this.states._tex || empty);
55293
+ }
55294
+ this._settingFillUniforms = false;
55061
55295
  fillShader.setUniform(
55062
55296
  "uTint",
55063
55297
  this.states.tint?._getRGBA([255, 255, 255, 255]) ?? [255, 255, 255, 255]
@@ -55180,7 +55414,7 @@ var p5 = (function () {
55180
55414
  _getEmptyTexture() {
55181
55415
  if (!this._emptyTexture) {
55182
55416
  // a plain white texture RGBA, full alpha, single pixel.
55183
- const im = new Image(1, 1);
55417
+ const im = new Image$1(1, 1);
55184
55418
  im.set(0, 0, 255);
55185
55419
  this._emptyTexture = new Texture(this, im);
55186
55420
  }
@@ -60624,7 +60858,7 @@ var p5 = (function () {
60624
60858
  * @returns {String} The GLSL version used by the shader.
60625
60859
  */
60626
60860
  version() {
60627
- const match = /#version (.+)$/.exec(this.vertSrc());
60861
+ const match = /#version (.+)$/m.exec(this.vertSrc());
60628
60862
  if (match) {
60629
60863
  return match[1];
60630
60864
  } else {
@@ -61628,6 +61862,10 @@ var p5 = (function () {
61628
61862
  return;
61629
61863
  }
61630
61864
 
61865
+ if (uniformName === 'uSampler' && !this._renderer._settingFillUniforms) {
61866
+ this._userSetSampler = true;
61867
+ }
61868
+
61631
61869
  // In p5.strands-related code, where some of the code may be in
61632
61870
  // p5.webgpu.js instead of the main p5.js build, we generally use
61633
61871
  // duck typing instead of instanceof to avoid accidentally importing
@@ -63939,7 +64177,7 @@ var p5 = (function () {
63939
64177
  * // Replace alpha in the color with dithering by
63940
64178
  * // randomly setting pixel colors to 0 based on opacity
63941
64179
  * let a = 1;
63942
- * if (noise(pixelInputs.position.xy) > pixelInputs.color.a) {
64180
+ * if (random() > pixelInputs.color.a) {
63943
64181
  * a = 0;
63944
64182
  * }
63945
64183
  * pixelInputs.color.a = a;
@@ -65769,11 +66007,7 @@ var p5 = (function () {
65769
66007
  * <a href="#/p5/angleMode">angleMode()</a> is `DEGREES`, then values are
65770
66008
  * returned in the range 0 to 180.
65771
66009
  *
65772
- * @method acos
65773
- * @param {Number} value value whose arc cosine is to be returned.
65774
- * @return {Number} arc cosine of the given value.
65775
- *
65776
- * @example
66010
+ * ```js example
65777
66011
  * function setup() {
65778
66012
  * createCanvas(100, 100);
65779
66013
  *
@@ -65791,8 +66025,9 @@ var p5 = (function () {
65791
66025
  *
65792
66026
  * describe('The numbers 3.142, -1, and 3.142 written on separate rows.');
65793
66027
  * }
66028
+ * ```
65794
66029
  *
65795
- * @example
66030
+ * ```js example
65796
66031
  * function setup() {
65797
66032
  * createCanvas(100, 100);
65798
66033
  *
@@ -65810,6 +66045,52 @@ var p5 = (function () {
65810
66045
  *
65811
66046
  * describe('The numbers 3.927, -0.707, and 2.356 written on separate rows.');
65812
66047
  * }
66048
+ * ```
66049
+ *
66050
+ * `acos()` can also be used in shaders with p5.strands. The following example
66051
+ * uses `acos()` to create a pulsing color transition on a shape.
66052
+ *
66053
+ * ```js example
66054
+ * let myShader;
66055
+ *
66056
+ * function setup() {
66057
+ * createCanvas(100, 100, WEBGL);
66058
+ * myShader = buildColorShader(shaderCallback);
66059
+ * describe('A sphere that pulses between orange and teal.');
66060
+ * }
66061
+ *
66062
+ * function shaderCallback() {
66063
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66064
+ * let t = millis() * 0.001;
66065
+ *
66066
+ * // acos(cos(t)) creates a triangle wave that goes from 0 to PI and back.
66067
+ * // Dividing by PI normalizes the result to the 0 to 1 range.
66068
+ * let value = acos(cos(t)) / PI;
66069
+ *
66070
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66071
+ * let orange = [1, 0.5, 0, 1];
66072
+ * let teal = [0, 0.8, 0.8, 1];
66073
+ *
66074
+ * finalColor.begin();
66075
+ *
66076
+ * // mix() blends between orange (when value = 0) and teal (when value = 1).
66077
+ * // acos() creates a pulsing effect by turning smooth oscillation into a triangle wave.
66078
+ * finalColor.set(mix(orange, teal, value));
66079
+ *
66080
+ * finalColor.end();
66081
+ * }
66082
+ *
66083
+ * function draw() {
66084
+ * background(220);
66085
+ * shader(myShader);
66086
+ * noStroke();
66087
+ * sphere(30);
66088
+ * }
66089
+ * ```
66090
+ *
66091
+ * @method acos
66092
+ * @param {Number} value value whose arc cosine is to be returned.
66093
+ * @return {Number} arc cosine of the given value.
65813
66094
  */
65814
66095
  fn.acos = function(ratio) {
65815
66096
  return this._fromRadians(Math.acos(ratio));
@@ -65824,11 +66105,7 @@ var p5 = (function () {
65824
66105
  * the <a href="#/p5/angleMode">angleMode()</a> is `DEGREES` then values are
65825
66106
  * returned in the range -90 to 90.
65826
66107
  *
65827
- * @method asin
65828
- * @param {Number} value value whose arc sine is to be returned.
65829
- * @return {Number} arc sine of the given value.
65830
- *
65831
- * @example
66108
+ * ```js example
65832
66109
  * function setup() {
65833
66110
  * createCanvas(100, 100);
65834
66111
  *
@@ -65846,8 +66123,9 @@ var p5 = (function () {
65846
66123
  *
65847
66124
  * describe('The numbers 1.047, 0.866, and 1.047 written on separate rows.');
65848
66125
  * }
66126
+ * ```
65849
66127
  *
65850
- * @example
66128
+ * ```js example
65851
66129
  * function setup() {
65852
66130
  * createCanvas(100, 100);
65853
66131
  *
@@ -65865,6 +66143,52 @@ var p5 = (function () {
65865
66143
  *
65866
66144
  * describe('The numbers 4.189, -0.866, and -1.047 written on separate rows.');
65867
66145
  * }
66146
+ * ```
66147
+ *
66148
+ * `asin()` can also be used in shaders with p5.strands. The following example
66149
+ * uses `asin()` to create a smooth color transition on a shape.
66150
+ *
66151
+ * ```js example
66152
+ * let myShader;
66153
+ *
66154
+ * function setup() {
66155
+ * createCanvas(100, 100, WEBGL);
66156
+ * myShader = buildColorShader(shaderCallback);
66157
+ * describe('A sphere that smoothly shifts between green and purple.');
66158
+ * }
66159
+ *
66160
+ * function shaderCallback() {
66161
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66162
+ * let t = millis() * 0.001;
66163
+ *
66164
+ * // asin(sin(t)) returns a value between -PI/2 and PI/2.
66165
+ * // Dividing by PI/2 normalizes to -1 to 1, then adding 1 and multiplying by 0.5
66166
+ * // remaps to the 0 to 1 range.
66167
+ * let value = (asin(sin(t)) / (PI / 2) + 1) * 0.5;
66168
+ *
66169
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66170
+ * let green = [0, 1, 0.5, 1];
66171
+ * let purple = [0.5, 0, 1, 1];
66172
+ *
66173
+ * finalColor.begin();
66174
+ *
66175
+ * // mix() blends between green (when value = 0) and purple (when value = 1).
66176
+ * finalColor.set(mix(green, purple, value));
66177
+ *
66178
+ * finalColor.end();
66179
+ * }
66180
+ *
66181
+ * function draw() {
66182
+ * background(220);
66183
+ * shader(myShader);
66184
+ * noStroke();
66185
+ * sphere(30);
66186
+ * }
66187
+ * ```
66188
+ *
66189
+ * @method asin
66190
+ * @param {Number} value value whose arc sine is to be returned.
66191
+ * @return {Number} arc sine of the given value.
65868
66192
  */
65869
66193
  fn.asin = function(ratio) {
65870
66194
  return this._fromRadians(Math.asin(ratio));
@@ -65879,11 +66203,7 @@ var p5 = (function () {
65879
66203
  * (about 1.57). If the <a href="#/p5/angleMode">angleMode()</a> is `DEGREES`
65880
66204
  * then values are returned in the range -90 to 90.
65881
66205
  *
65882
- * @method atan
65883
- * @param {Number} value value whose arc tangent is to be returned.
65884
- * @return {Number} arc tangent of the given value.
65885
- *
65886
- * @example
66206
+ * ```js example
65887
66207
  * function setup() {
65888
66208
  * createCanvas(100, 100);
65889
66209
  *
@@ -65901,8 +66221,9 @@ var p5 = (function () {
65901
66221
  *
65902
66222
  * describe('The numbers 1.047, 1.732, and 1.047 written on separate rows.');
65903
66223
  * }
66224
+ * ```
65904
66225
  *
65905
- * @example
66226
+ * ```js example
65906
66227
  * function setup() {
65907
66228
  * createCanvas(100, 100);
65908
66229
  *
@@ -65920,6 +66241,55 @@ var p5 = (function () {
65920
66241
  *
65921
66242
  * describe('The numbers 4.189, 1.732, and 1.047 written on separate rows.');
65922
66243
  * }
66244
+ * ```
66245
+ *
66246
+ * `atan()` can also be used in shaders with p5.strands. The following example
66247
+ * uses `atan()` to create a soft color transition on a shape.
66248
+ *
66249
+ * ```js example
66250
+ * let myShader;
66251
+ *
66252
+ * function setup() {
66253
+ * createCanvas(100, 100, WEBGL);
66254
+ * myShader = buildColorShader(shaderCallback);
66255
+ * describe('A sphere that softly shifts between pink and lime.');
66256
+ * }
66257
+ *
66258
+ * function shaderCallback() {
66259
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66260
+ * // sin() oscillates the input between -5 and 5, so atan() gets both positive and negative values.
66261
+ * let t = sin(millis() * 0.001) * 5;
66262
+ *
66263
+ * // atan(t) returns values between -PI/2 and PI/2.
66264
+ * // Dividing by PI/2 normalizes to -1 to 1, then adding 1 and multiplying by 0.5
66265
+ * // remaps to the 0 to 1 range.
66266
+ * // atan() compresses the wide range of t into a smooth S-curve (soft clipping).
66267
+ * let value = (atan(t) / (PI / 2) + 1) * 0.5;
66268
+ *
66269
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66270
+ * let pink = [1, 0, 0.5, 1];
66271
+ * let lime = [0.5, 1, 0, 1];
66272
+ *
66273
+ * finalColor.begin();
66274
+ *
66275
+ * // mix() blends between pink (when value = 0) and lime (when value = 1).
66276
+ * // atan() creates a soft, eased transition instead of a linear blend.
66277
+ * finalColor.set(mix(pink, lime, value));
66278
+ *
66279
+ * finalColor.end();
66280
+ * }
66281
+ *
66282
+ * function draw() {
66283
+ * background(220);
66284
+ * shader(myShader);
66285
+ * noStroke();
66286
+ * sphere(30);
66287
+ * }
66288
+ * ```
66289
+ *
66290
+ * @method atan
66291
+ * @param {Number} value value whose arc tangent is to be returned.
66292
+ * @return {Number} arc tangent of the given value.
65923
66293
  */
65924
66294
  fn.atan = function(ratio) {
65925
66295
  return this._fromRadians(Math.atan(ratio));
@@ -66003,11 +66373,7 @@ var p5 = (function () {
66003
66373
  * calculates the cosine of an angle, using radians by default, or according
66004
66374
  * to if <a href="#/p5/angleMode">angleMode()</a> setting (RADIANS or DEGREES).
66005
66375
  *
66006
- * @method cos
66007
- * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66008
- * @return {Number} cosine of the angle.
66009
- *
66010
- * @example
66376
+ * ```js example
66011
66377
  * function setup() {
66012
66378
  * createCanvas(100, 100);
66013
66379
  *
@@ -66025,8 +66391,9 @@ var p5 = (function () {
66025
66391
  * line(50, y, x, y);
66026
66392
  * circle(x, y, 20);
66027
66393
  * }
66394
+ * ```
66028
66395
  *
66029
- * @example
66396
+ * ```js example
66030
66397
  * function setup() {
66031
66398
  * createCanvas(100, 100);
66032
66399
  *
@@ -66043,8 +66410,9 @@ var p5 = (function () {
66043
66410
  * // Draw the point.
66044
66411
  * point(x, y);
66045
66412
  * }
66413
+ * ```
66046
66414
  *
66047
- * @example
66415
+ * ```js example
66048
66416
  * function setup() {
66049
66417
  * createCanvas(100, 100);
66050
66418
  *
@@ -66061,6 +66429,51 @@ var p5 = (function () {
66061
66429
  * // Draw the point.
66062
66430
  * point(x, y);
66063
66431
  * }
66432
+ * ```
66433
+ *
66434
+ * `cos()` can also be used in shaders with p5.strands. The following example
66435
+ * uses `cos()` to smoothly oscillate the color of a shape over time.
66436
+ *
66437
+ * ```js example
66438
+ * let myShader;
66439
+ *
66440
+ * function setup() {
66441
+ * createCanvas(100, 100, WEBGL);
66442
+ * myShader = buildColorShader(shaderCallback);
66443
+ * describe('A sphere that fades between yellow and blue.');
66444
+ * }
66445
+ *
66446
+ * function shaderCallback() {
66447
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66448
+ * let t = millis() * 0.001;
66449
+ *
66450
+ * // cos(t) oscillates between -1 and 1.
66451
+ * // 0.5 + 0.5 * cos(t) remaps this to the 0 to 1 range.
66452
+ * let value = 0.5 + 0.5 * cos(t);
66453
+ *
66454
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66455
+ * let yellow = [1, 1, 0, 1];
66456
+ * let blue = [0, 0, 1, 1];
66457
+ *
66458
+ * finalColor.begin();
66459
+ *
66460
+ * // mix() blends between yellow (when value = 0) and blue (when value = 1).
66461
+ * finalColor.set(mix(yellow, blue, value));
66462
+ *
66463
+ * finalColor.end();
66464
+ * }
66465
+ *
66466
+ * function draw() {
66467
+ * background(220);
66468
+ * shader(myShader);
66469
+ * noStroke();
66470
+ * sphere(30);
66471
+ * }
66472
+ * ```
66473
+ *
66474
+ * @method cos
66475
+ * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66476
+ * @return {Number} cosine of the angle.
66064
66477
  */
66065
66478
  fn.cos = function(angle) {
66066
66479
  return Math.cos(this._toRadians(angle));
@@ -66074,11 +66487,7 @@ var p5 = (function () {
66074
66487
  * calculates the sine of an angle, using radians by default, or according to
66075
66488
  * if <a href="#/p5/angleMode">angleMode()</a> setting (RADIANS or DEGREES).
66076
66489
  *
66077
- * @method sin
66078
- * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66079
- * @return {Number} sine of the angle.
66080
- *
66081
- * @example
66490
+ * ```js example
66082
66491
  * function setup() {
66083
66492
  * createCanvas(100, 100);
66084
66493
  *
@@ -66096,8 +66505,9 @@ var p5 = (function () {
66096
66505
  * line(50, y, x, y);
66097
66506
  * circle(x, y, 20);
66098
66507
  * }
66508
+ * ```
66099
66509
  *
66100
- * @example
66510
+ * ```js example
66101
66511
  * function setup() {
66102
66512
  * createCanvas(100, 100);
66103
66513
  *
@@ -66114,8 +66524,9 @@ var p5 = (function () {
66114
66524
  * // Draw the point.
66115
66525
  * point(x, y);
66116
66526
  * }
66527
+ * ```
66117
66528
  *
66118
- * @example
66529
+ * ```js example
66119
66530
  * function setup() {
66120
66531
  * createCanvas(100, 100);
66121
66532
  *
@@ -66132,6 +66543,51 @@ var p5 = (function () {
66132
66543
  * // Draw the point.
66133
66544
  * point(x, y);
66134
66545
  * }
66546
+ * ```
66547
+ *
66548
+ * `sin()` can also be used in shaders with p5.strands. The following example
66549
+ * uses `sin()` to oscillate the color of a shape over time.
66550
+ *
66551
+ * ```js example
66552
+ * let myShader;
66553
+ *
66554
+ * function setup() {
66555
+ * createCanvas(100, 100, WEBGL);
66556
+ * myShader = buildColorShader(shaderCallback);
66557
+ * describe('A sphere that pulses between cyan and magenta.');
66558
+ * }
66559
+ *
66560
+ * function shaderCallback() {
66561
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66562
+ * let t = millis() * 0.001;
66563
+ *
66564
+ * // sin(t) oscillates between -1 and 1.
66565
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
66566
+ * let value = 0.5 + 0.5 * sin(t);
66567
+ *
66568
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66569
+ * let cyan = [0, 1, 1, 1];
66570
+ * let magenta = [1, 0, 1, 1];
66571
+ *
66572
+ * finalColor.begin();
66573
+ *
66574
+ * // mix() blends between cyan (when value = 0) and magenta (when value = 1).
66575
+ * finalColor.set(mix(cyan, magenta, value));
66576
+ *
66577
+ * finalColor.end();
66578
+ * }
66579
+ *
66580
+ * function draw() {
66581
+ * background(220);
66582
+ * shader(myShader);
66583
+ * noStroke();
66584
+ * sphere(30);
66585
+ * }
66586
+ * ```
66587
+ *
66588
+ * @method sin
66589
+ * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66590
+ * @return {Number} sine of the angle.
66135
66591
  */
66136
66592
  fn.sin = function(angle) {
66137
66593
  return Math.sin(this._toRadians(angle));
@@ -66146,11 +66602,7 @@ var p5 = (function () {
66146
66602
  * by default, or according to
66147
66603
  * if <a href="#/p5/angleMode">angleMode()</a> setting (RADIANS or DEGREES).
66148
66604
  *
66149
- * @method tan
66150
- * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66151
- * @return {Number} tangent of the angle.
66152
- *
66153
- * @example
66605
+ * ```js example
66154
66606
  * function setup() {
66155
66607
  * createCanvas(100, 100);
66156
66608
  *
@@ -66167,6 +66619,53 @@ var p5 = (function () {
66167
66619
  * // Draw the point.
66168
66620
  * point(x, y);
66169
66621
  * }
66622
+ * ```
66623
+ *
66624
+ * `tan()` can also be used in shaders with p5.strands. The following example
66625
+ * uses `tan()` to create rapid color transitions on a shape.
66626
+ *
66627
+ * ```js example
66628
+ * let myShader;
66629
+ *
66630
+ * function setup() {
66631
+ * createCanvas(100, 100, WEBGL);
66632
+ * myShader = buildColorShader(shaderCallback);
66633
+ * describe('A sphere with rapidly shifting colors.');
66634
+ * }
66635
+ *
66636
+ * function shaderCallback() {
66637
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.0005 to slow it down.
66638
+ * let t = millis() * 0.0005;
66639
+ *
66640
+ * // tan(t) can grow to very large values (even infinity) at certain angles.
66641
+ * // 0.5 + 0.5 * tan(t) shifts the range but can still go way past 0 or 1.
66642
+ * // min(max(..., 0), 1) clamps the result to the 0 to 1 range.
66643
+ * let value = min(max(0.5 + 0.5 * tan(t), 0), 1);
66644
+ *
66645
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66646
+ * let orange = [1, 0.5, 0, 1];
66647
+ * let blue = [0, 0.5, 1, 1];
66648
+ *
66649
+ * finalColor.begin();
66650
+ *
66651
+ * // mix() blends between orange (when value = 0) and blue (when value = 1).
66652
+ * // tan() creates rapid, dramatic color shifts as it spikes and resets.
66653
+ * finalColor.set(mix(orange, blue, value));
66654
+ *
66655
+ * finalColor.end();
66656
+ * }
66657
+ *
66658
+ * function draw() {
66659
+ * background(220);
66660
+ * shader(myShader);
66661
+ * noStroke();
66662
+ * sphere(30);
66663
+ * }
66664
+ * ```
66665
+ *
66666
+ * @method tan
66667
+ * @param {Number} angle the angle, in radians by default, or according to if <a href="/reference/p5/angleMode/">angleMode()</a> setting (RADIANS or DEGREES).
66668
+ * @return {Number} tangent of the angle.
66170
66669
  */
66171
66670
  fn.tan = function(angle) {
66172
66671
  return Math.tan(this._toRadians(angle));
@@ -66182,11 +66681,7 @@ var p5 = (function () {
66182
66681
  * quarter of a full rotation. The same angle is 2 &times; &pi; &divide; 4
66183
66682
  * (about 1.57) radians.
66184
66683
  *
66185
- * @method degrees
66186
- * @param {Number} radians radians value to convert to degrees.
66187
- * @return {Number} converted angle.
66188
- *
66189
- * @example
66684
+ * ```js example
66190
66685
  * function setup() {
66191
66686
  * createCanvas(100, 100);
66192
66687
  *
@@ -66201,6 +66696,54 @@ var p5 = (function () {
66201
66696
  *
66202
66697
  * describe('The text "0.79 rad = 45˚".');
66203
66698
  * }
66699
+ * ```
66700
+ *
66701
+ * `degrees()` can also be used in shaders with p5.strands. The following example
66702
+ * uses `degrees()` to convert a radian value to degrees inside a shader.
66703
+ *
66704
+ * ```js example
66705
+ * let myShader;
66706
+ *
66707
+ * function setup() {
66708
+ * createCanvas(100, 100, WEBGL);
66709
+ * myShader = buildColorShader(shaderCallback);
66710
+ * describe('A sphere that cycles through warm colors.');
66711
+ * }
66712
+ *
66713
+ * function shaderCallback() {
66714
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
66715
+ * let t = millis() * 0.001;
66716
+ *
66717
+ * // degrees() converts the radian value t to degrees.
66718
+ * // (deg % 360) wraps the degrees into a 0-360 range.
66719
+ * // Dividing by 360 normalizes to the 0 to 1 range.
66720
+ * let deg = degrees(t);
66721
+ * let value = (deg % 360) / 360;
66722
+ *
66723
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66724
+ * let red = [1, 0, 0, 1];
66725
+ * let yellow = [1, 1, 0, 1];
66726
+ *
66727
+ * finalColor.begin();
66728
+ *
66729
+ * // mix() blends between red (when value = 0) and yellow (when value = 1).
66730
+ * // degrees() creates a cycling sawtooth pattern as time increases.
66731
+ * finalColor.set(mix(red, yellow, value));
66732
+ *
66733
+ * finalColor.end();
66734
+ * }
66735
+ *
66736
+ * function draw() {
66737
+ * background(220);
66738
+ * shader(myShader);
66739
+ * noStroke();
66740
+ * sphere(30);
66741
+ * }
66742
+ * ```
66743
+ *
66744
+ * @method degrees
66745
+ * @param {Number} radians radians value to convert to degrees.
66746
+ * @return {Number} converted angle.
66204
66747
  */
66205
66748
  fn.degrees = angle => angle * RAD_TO_DEG;
66206
66749
 
@@ -66214,11 +66757,7 @@ var p5 = (function () {
66214
66757
  * quarter of a full rotation. The same angle is 2 &times; &pi; &divide; 4
66215
66758
  * (about 1.57) radians.
66216
66759
  *
66217
- * @method radians
66218
- * @param {Number} degrees degree value to convert to radians.
66219
- * @return {Number} converted angle.
66220
- *
66221
- * @example
66760
+ * ```js example
66222
66761
  * function setup() {
66223
66762
  * createCanvas(100, 100);
66224
66763
  *
@@ -66233,6 +66772,56 @@ var p5 = (function () {
66233
66772
  *
66234
66773
  * describe('The text "45˚ = 0.785 rad".');
66235
66774
  * }
66775
+ * ```
66776
+ *
66777
+ * `radians()` can also be used in shaders with p5.strands. The following example
66778
+ * uses `radians()` to convert degrees to radians inside a shader.
66779
+ *
66780
+ * ```js example
66781
+ * let myShader;
66782
+ *
66783
+ * function setup() {
66784
+ * createCanvas(100, 100, WEBGL);
66785
+ * myShader = buildColorShader(shaderCallback);
66786
+ * describe('A sphere that fades between red and white.');
66787
+ * }
66788
+ *
66789
+ * function shaderCallback() {
66790
+ * // shaderCallback runs on the GPU. millis() gives ms since start.
66791
+ * // Multiply by 0.05 and mod 360 to cycle through 0-360 degrees over time.
66792
+ * let deg = (millis() * 0.05) % 360;
66793
+ *
66794
+ * // radians() converts degrees to radians so sin() can use them.
66795
+ * let rad = radians(deg);
66796
+ *
66797
+ * // sin(rad) oscillates between -1 and 1.
66798
+ * // 0.5 + 0.5 * sin(rad) remaps this to the 0 to 1 range.
66799
+ * let value = 0.5 + 0.5 * sin(rad);
66800
+ *
66801
+ * // Each color is [R, G, B, A] with values from 0 to 1.
66802
+ * let red = [1, 0, 0, 1];
66803
+ * let white = [1, 1, 1, 1];
66804
+ *
66805
+ * finalColor.begin();
66806
+ *
66807
+ * // mix() blends between red (when value = 0) and white (when value = 1).
66808
+ * // radians() converts the degree input so sin() can produce smooth oscillation.
66809
+ * finalColor.set(mix(red, white, value));
66810
+ *
66811
+ * finalColor.end();
66812
+ * }
66813
+ *
66814
+ * function draw() {
66815
+ * background(220);
66816
+ * shader(myShader);
66817
+ * noStroke();
66818
+ * sphere(30);
66819
+ * }
66820
+ * ```
66821
+ *
66822
+ * @method radians
66823
+ * @param {Number} degrees degree value to convert to radians.
66824
+ * @return {Number} converted angle.
66236
66825
  */
66237
66826
  fn.radians = angle => angle * DEG_TO_RAD;
66238
66827
 
@@ -67218,7 +67807,7 @@ var p5 = (function () {
67218
67807
  _detectSourceType() {
67219
67808
  const obj = this.src;
67220
67809
  this.isFramebufferTexture = obj instanceof FramebufferTexture;
67221
- this.isSrcP5Image = obj instanceof Image;
67810
+ this.isSrcP5Image = obj instanceof Image$1;
67222
67811
  this.isSrcP5Graphics = obj instanceof Graphics;
67223
67812
  this.isSrcP5Renderer = obj instanceof Renderer;
67224
67813
  this.isImageData = typeof ImageData !== 'undefined' && obj instanceof ImageData;
@@ -70161,6 +70750,13 @@ var p5 = (function () {
70161
70750
  throw new Error(prefixedMessage);
70162
70751
  }
70163
70752
 
70753
+ function dimensionMismatchError(declaredDim,actualDim,varName){
70754
+ userError(
70755
+ 'dimension mismatch',
70756
+ `Cannot assign a value of dimension ${actualDim} to \`${varName}\`, which expects dimension ${declaredDim}.`
70757
+ );
70758
+ }
70759
+
70164
70760
  /////////////////////////////////
70165
70761
  // Public functions for strands runtime
70166
70762
  /////////////////////////////////
@@ -70449,6 +71045,16 @@ var p5 = (function () {
70449
71045
 
70450
71046
  // For varying variables, we need both assignment generation AND a way to reference by identifier
70451
71047
  if (this._originalIdentifier) {
71048
+ const valueDim = value?.isStrandsNode
71049
+ ? value.dimension
71050
+ : (Array.isArray(value) ? value.length : 1);
71051
+ if (valueDim !== this._originalDimension && valueDim !== 1){
71052
+ dimensionMismatchError(
71053
+ this._originalDimension,
71054
+ valueDim,
71055
+ this._originalIdentifier
71056
+ );
71057
+ }
70452
71058
  // Create a variable node for the target (the varying variable)
70453
71059
  const { id: targetVarID } = variableNode(
70454
71060
  this.strandsContext,
@@ -70501,6 +71107,16 @@ var p5 = (function () {
70501
71107
 
70502
71108
  // For varying variables, create swizzle assignment
70503
71109
  if (this._originalIdentifier) {
71110
+ const valueDim = value?.isStrandsNode
71111
+ ? value.dimension
71112
+ : (Array.isArray(value) ? value.length : 1);
71113
+ if (valueDim !== swizzlePattern.length && valueDim !== 1){
71114
+ dimensionMismatchError(
71115
+ swizzlePattern.length,
71116
+ valueDim,
71117
+ `${this._originalIdentifier}.${swizzlePattern}`
71118
+ );
71119
+ }
70504
71120
  // Create a variable node for the target with swizzle
70505
71121
  const { id: targetVarID } = variableNode(
70506
71122
  this.strandsContext,
@@ -71049,38 +71665,24 @@ var p5 = (function () {
71049
71665
  return createStrandsNode(id, dimension, strandsContext);
71050
71666
  }
71051
71667
 
71052
- function structConstructorNode(strandsContext, structTypeInfo, rawUserArgs) {
71668
+ function structConstructorNode(strandsContext, structTypeInfo, dependsOn) {
71053
71669
  const { cfg, dag } = strandsContext;
71054
71670
  const { properties } = structTypeInfo;
71055
71671
 
71056
- if (!(rawUserArgs.length === properties.length)) {
71672
+ if (dependsOn.length !== properties.length) {
71057
71673
  userError('type error',
71058
- `You've tried to construct a ${structTypeInfo.typeName} struct with ${rawUserArgs.length} properties, but it expects ${properties.length} properties.\n` +
71674
+ `You've tried to construct a ${structTypeInfo.typeName} struct with ${dependsOn.length} properties, but it expects ${properties.length} properties.\n` +
71059
71675
  `The properties it expects are:\n` +
71060
- `${properties.map(prop => prop.name + ' ' + prop.DataType.baseType + prop.DataType.dimension)}`
71676
+ `${properties.map(prop => `${prop.name}: ${prop.dataType.baseType}${prop.dataType.dimension}`).join(', ')}`
71061
71677
  );
71062
71678
  }
71063
71679
 
71064
- const dependsOn = [];
71065
- for (let i = 0; i < properties.length; i++) {
71066
- const expectedProperty = properties[i];
71067
- const { originalNodeID, mappedDependencies } = mapPrimitiveDepsToIDs(strandsContext, expectedProperty.dataType, rawUserArgs[i]);
71068
- if (originalNodeID) {
71069
- dependsOn.push(originalNodeID);
71070
- }
71071
- else {
71072
- dependsOn.push(
71073
- constructTypeFromIDs(strandsContext, expectedProperty.dataType, mappedDependencies)
71074
- );
71075
- }
71076
- }
71077
-
71078
71680
  const nodeData = createNodeData({
71079
71681
  nodeType: NodeType.OPERATION,
71080
71682
  opCode: OpCode.Nary.CONSTRUCTOR,
71081
71683
  dimension: properties.length,
71082
- baseType: structTypeInfo.typeName ,
71083
- dependsOn
71684
+ baseType: structTypeInfo.typeName,
71685
+ dependsOn,
71084
71686
  });
71085
71687
  const id = getOrCreateNode(dag, nodeData);
71086
71688
  recordInBasicBlock(cfg, cfg.currentBlock, id);
@@ -71277,7 +71879,11 @@ var p5 = (function () {
71277
71879
  scalars.push(createStrandsNode(id, dimension, strandsContext));
71278
71880
  }
71279
71881
  } else {
71280
- userError('type error', `Swizzle assignment: RHS vector does not match LHS vector (need ${chars.length}, got ${value.dimension}).`);
71882
+ dimensionMismatchError(
71883
+ chars.length,
71884
+ value.dimension,
71885
+ `${target._originalIdentifier || 'value'}.${property}`
71886
+ );
71281
71887
  }
71282
71888
  } else if (Array.isArray(value)) {
71283
71889
  const flat = value.flat(Infinity);
@@ -71751,7 +72357,7 @@ var p5 = (function () {
71751
72357
  }
71752
72358
  const dag = strandsContext.dag;
71753
72359
  const rootNode = getNodeDataFromID(dag, rootNodeID);
71754
- if (isStructType(returnType)) {
72360
+ if (isStructType(returnType) && rootNode.identifier) {
71755
72361
  const structTypeInfo = returnType;
71756
72362
  for (let i = 0; i < structTypeInfo.properties.length; i++) {
71757
72363
  const prop = structTypeInfo.properties[i];
@@ -72042,7 +72648,7 @@ var p5 = (function () {
72042
72648
  _arraysEqual: (a, b) => JSON.stringify(a) === JSON.stringify(b),
72043
72649
  _getEmptyTexture: () => {
72044
72650
  if (!this._emptyTexture) {
72045
- const im = new Image(1, 1);
72651
+ const im = new Image$1(1, 1);
72046
72652
  im.set(0, 0, 255);
72047
72653
  this._emptyTexture = new Texture(this._renderer, im);
72048
72654
  }
@@ -72474,8 +73080,6 @@ var p5 = (function () {
72474
73080
  }
72475
73081
  }
72476
73082
 
72477
- const styleEmpty = 'rgba(0,0,0,0)';
72478
-
72479
73083
  class Renderer2D extends Renderer {
72480
73084
  constructor(pInst, w, h, isMainCanvas, elt, attributes = {}) {
72481
73085
  super(pInst, w, h, isMainCanvas);
@@ -72634,7 +73238,7 @@ var p5 = (function () {
72634
73238
  }
72635
73239
  this.push();
72636
73240
  this.resetMatrix();
72637
- if (args[0] instanceof Image) {
73241
+ if (args[0] instanceof Image$1) {
72638
73242
  const img = args[0];
72639
73243
  if (args[1] >= 0) {
72640
73244
  // set transparency of background
@@ -72907,10 +73511,12 @@ var p5 = (function () {
72907
73511
  ctx.save();
72908
73512
  ctx.clearRect(0, 0, img.canvas.width, img.canvas.height);
72909
73513
 
73514
+ const tint = this.states.tint._getRGBA([255, 255, 255, 255]);
73515
+
72910
73516
  if (
72911
- this.states.tint[0] < 255 ||
72912
- this.states.tint[1] < 255 ||
72913
- this.states.tint[2] < 255
73517
+ tint[0] < 255 ||
73518
+ tint[1] < 255 ||
73519
+ tint[2] < 255
72914
73520
  ) {
72915
73521
  // Color tint: we need to use the multiply blend mode to change the colors.
72916
73522
  // However, the canvas implementation of this destroys the alpha channel of
@@ -72933,16 +73539,16 @@ var p5 = (function () {
72933
73539
 
72934
73540
  // Apply color tint
72935
73541
  ctx.globalCompositeOperation = 'multiply';
72936
- ctx.fillStyle = `rgb(${this.states.tint.slice(0, 3).join(', ')})`;
73542
+ ctx.fillStyle = `rgb(${tint.slice(0, 3).join(', ')})`;
72937
73543
  ctx.fillRect(0, 0, img.canvas.width, img.canvas.height);
72938
73544
 
72939
73545
  // Replace the alpha channel with the original alpha * the alpha tint
72940
73546
  ctx.globalCompositeOperation = 'destination-in';
72941
- ctx.globalAlpha = this.states.tint[3] / 255;
73547
+ ctx.globalAlpha = tint[3] / 255;
72942
73548
  ctx.drawImage(img.canvas, 0, 0);
72943
73549
  } else {
72944
73550
  // If we only need to change the alpha, we can skip all the extra work!
72945
- ctx.globalAlpha = this.states.tint[3] / 255;
73551
+ ctx.globalAlpha = tint[3] / 255;
72946
73552
  ctx.drawImage(img.canvas, 0, 0);
72947
73553
  }
72948
73554
 
@@ -73028,7 +73634,7 @@ var p5 = (function () {
73028
73634
  // round down to get integer numbers
73029
73635
  x = Math.floor(x);
73030
73636
  y = Math.floor(y);
73031
- if (imgOrCol instanceof Graphics || imgOrCol instanceof Image) {
73637
+ if (imgOrCol instanceof Graphics || imgOrCol instanceof Image$1) {
73032
73638
  this.drawingContext.save();
73033
73639
  this.drawingContext.setTransform(1, 0, 0, 1, 0, 0);
73034
73640
  this.drawingContext.scale(
@@ -73168,96 +73774,32 @@ var p5 = (function () {
73168
73774
  }
73169
73775
 
73170
73776
  line(x1, y1, x2, y2) {
73171
- const ctx = this.drawingContext;
73172
- if (!this.states.strokeColor) {
73173
- return this;
73174
- } else if (this._getStroke() === styleEmpty) {
73175
- return this;
73176
- }
73177
- if (this._clipping) {
73178
- const tempPath = new Path2D();
73179
- tempPath.moveTo(x1, y1);
73180
- tempPath.lineTo(x2, y2);
73181
- const currentTransform = this.drawingContext.getTransform();
73182
- const clipBaseTransform = this._clipBaseTransform.inverse();
73183
- const relativeTransform = clipBaseTransform.multiply(currentTransform);
73184
- this.clipPath.addPath(tempPath, relativeTransform);
73185
- return this;
73186
- }
73187
- ctx.beginPath();
73188
- ctx.moveTo(x1, y1);
73189
- ctx.lineTo(x2, y2);
73190
- ctx.stroke();
73777
+ const shape = new p5$2.Shape({ position: new p5$2.Vector(0, 0) });
73778
+ shape.beginShape();
73779
+ shape.line(x1, y1, x2, y2);
73780
+ shape.endShape();
73781
+ this.drawShape(shape);
73191
73782
 
73192
73783
  return this;
73193
73784
  }
73194
73785
 
73195
73786
  point(x, y) {
73196
- const ctx = this.drawingContext;
73197
- if (!this.states.strokeColor) {
73198
- return this;
73199
- } else if (this._getStroke() === styleEmpty) {
73200
- return this;
73201
- }
73202
- const s = this._getStroke();
73203
- const f = this._getFill();
73204
- if (this._clipping) {
73205
- const tempPath = new Path2D();
73206
- const drawingContextWidth = this.drawingContext.lineWidth;
73207
- tempPath.arc(x, y, drawingContextWidth / 2, 0, TWO_PI);
73208
- const currentTransform = this.drawingContext.getTransform();
73209
- const clipBaseTransform = this._clipBaseTransform.inverse();
73210
- const relativeTransform = clipBaseTransform.multiply(currentTransform);
73211
- this.clipPath.addPath(tempPath, relativeTransform);
73212
- return this;
73213
- }
73214
- this._setFill(s);
73215
- ctx.beginPath();
73216
- ctx.arc(x, y, ctx.lineWidth / 2, 0, TWO_PI, false);
73217
- ctx.fill();
73218
- this._setFill(f);
73787
+ const shape = new p5$2.Shape({ position: new p5$2.Vector(0, 0) });
73788
+ shape.beginShape();
73789
+ shape.point(x, y);
73790
+ shape.endShape();
73791
+ this.drawShape(shape);
73219
73792
 
73220
73793
  return this;
73221
73794
  }
73222
73795
 
73223
73796
  quad(x1, y1, x2, y2, x3, y3, x4, y4) {
73224
- const ctx = this.drawingContext;
73225
- const doFill = !!this.states.fillColor,
73226
- doStroke = this.states.strokeColor;
73227
- if (doFill && !doStroke) {
73228
- if (this._getFill() === styleEmpty) {
73229
- return this;
73230
- }
73231
- } else if (!doFill && doStroke) {
73232
- if (this._getStroke() === styleEmpty) {
73233
- return this;
73234
- }
73235
- }
73236
- if (this._clipping) {
73237
- const tempPath = new Path2D();
73238
- tempPath.moveTo(x1, y1);
73239
- tempPath.lineTo(x2, y2);
73240
- tempPath.lineTo(x3, y3);
73241
- tempPath.lineTo(x4, y4);
73242
- tempPath.closePath();
73243
- const currentTransform = this.drawingContext.getTransform();
73244
- const clipBaseTransform = this._clipBaseTransform.inverse();
73245
- const relativeTransform = clipBaseTransform.multiply(currentTransform);
73246
- this.clipPath.addPath(tempPath, relativeTransform);
73247
- return this;
73248
- }
73249
- ctx.beginPath();
73250
- ctx.moveTo(x1, y1);
73251
- ctx.lineTo(x2, y2);
73252
- ctx.lineTo(x3, y3);
73253
- ctx.lineTo(x4, y4);
73254
- ctx.closePath();
73255
- if (doFill) {
73256
- ctx.fill();
73257
- }
73258
- if (doStroke) {
73259
- ctx.stroke();
73260
- }
73797
+ const shape = new p5$2.Shape({ position: new p5$2.Vector(0, 0) });
73798
+ shape.beginShape();
73799
+ shape.quad(x1, y1, x2, y2, x3, y3, x4, y4);
73800
+ shape.endShape();
73801
+ this.drawShape(shape);
73802
+
73261
73803
  return this;
73262
73804
  }
73263
73805
 
@@ -73270,134 +73812,29 @@ var p5 = (function () {
73270
73812
  let tr = args[5];
73271
73813
  let br = args[6];
73272
73814
  let bl = args[7];
73273
- const ctx = this.drawingContext;
73274
- const doFill = !!this.states.fillColor,
73275
- doStroke = this.states.strokeColor;
73276
- if (doFill && !doStroke) {
73277
- if (this._getFill() === styleEmpty) {
73278
- return this;
73279
- }
73280
- } else if (!doFill && doStroke) {
73281
- if (this._getStroke() === styleEmpty) {
73282
- return this;
73283
- }
73284
- }
73285
- if (this._clipping) {
73286
- const tempPath = new Path2D();
73287
- if (typeof tl === 'undefined') {
73288
- tempPath.rect(x, y, w, h);
73289
- } else {
73290
- tempPath.roundRect(x, y, w, h, [tl, tr, br, bl]);
73291
- }
73292
- const currentTransform = this.drawingContext.getTransform();
73293
- const clipBaseTransform = this._clipBaseTransform.inverse();
73294
- const relativeTransform = clipBaseTransform.multiply(currentTransform);
73295
- this.clipPath.addPath(tempPath, relativeTransform);
73296
- return this;
73297
- }
73298
- ctx.beginPath();
73299
- if (typeof tl === 'undefined') {
73300
- // No rounded corners
73301
- ctx.rect(x, y, w, h);
73302
- } else {
73303
- // At least one rounded corner
73304
- // Set defaults when not specified
73305
- if (typeof tr === 'undefined') {
73306
- tr = tl;
73307
- }
73308
- if (typeof br === 'undefined') {
73309
- br = tr;
73310
- }
73311
- if (typeof bl === 'undefined') {
73312
- bl = br;
73313
- }
73314
73815
 
73315
- // corner rounding must always be positive
73316
- const absW = Math.abs(w);
73317
- const absH = Math.abs(h);
73318
- const hw = absW / 2;
73319
- const hh = absH / 2;
73320
-
73321
- // Clip radii
73322
- if (absW < 2 * tl) {
73323
- tl = hw;
73324
- }
73325
- if (absH < 2 * tl) {
73326
- tl = hh;
73327
- }
73328
- if (absW < 2 * tr) {
73329
- tr = hw;
73330
- }
73331
- if (absH < 2 * tr) {
73332
- tr = hh;
73333
- }
73334
- if (absW < 2 * br) {
73335
- br = hw;
73336
- }
73337
- if (absH < 2 * br) {
73338
- br = hh;
73339
- }
73340
- if (absW < 2 * bl) {
73341
- bl = hw;
73342
- }
73343
- if (absH < 2 * bl) {
73344
- bl = hh;
73345
- }
73816
+ const shape = new p5$2.Shape({ position: new p5$2.Vector(0, 0) });
73817
+ shape.beginShape();
73818
+ shape.rectPrimitive(x, y, w, h, tl, tr, br, bl);
73819
+ shape.endShape();
73820
+ this.drawShape(shape);
73346
73821
 
73347
- ctx.roundRect(x, y, w, h, [tl, tr, br, bl]);
73348
- }
73349
- if (doFill) {
73350
- ctx.fill();
73351
- }
73352
- if (doStroke) {
73353
- ctx.stroke();
73354
- }
73355
73822
  return this;
73356
73823
  }
73357
73824
 
73358
-
73359
73825
  triangle(args) {
73360
- const ctx = this.drawingContext;
73361
- const doFill = !!this.states.fillColor,
73362
- doStroke = this.states.strokeColor;
73363
73826
  const x1 = args[0],
73364
73827
  y1 = args[1];
73365
73828
  const x2 = args[2],
73366
73829
  y2 = args[3];
73367
73830
  const x3 = args[4],
73368
73831
  y3 = args[5];
73369
- if (doFill && !doStroke) {
73370
- if (this._getFill() === styleEmpty) {
73371
- return this;
73372
- }
73373
- } else if (!doFill && doStroke) {
73374
- if (this._getStroke() === styleEmpty) {
73375
- return this;
73376
- }
73377
- }
73378
- if (this._clipping) {
73379
- const tempPath = new Path2D();
73380
- tempPath.moveTo(x1, y1);
73381
- tempPath.lineTo(x2, y2);
73382
- tempPath.lineTo(x3, y3);
73383
- tempPath.closePath();
73384
- const currentTransform = this.drawingContext.getTransform();
73385
- const clipBaseTransform = this._clipBaseTransform.inverse();
73386
- const relativeTransform = clipBaseTransform.multiply(currentTransform);
73387
- this.clipPath.addPath(tempPath, relativeTransform);
73388
- return this;
73389
- }
73390
- ctx.beginPath();
73391
- ctx.moveTo(x1, y1);
73392
- ctx.lineTo(x2, y2);
73393
- ctx.lineTo(x3, y3);
73394
- ctx.closePath();
73395
- if (doFill) {
73396
- ctx.fill();
73397
- }
73398
- if (doStroke) {
73399
- ctx.stroke();
73400
- }
73832
+
73833
+ const shape = new p5$2.Shape({ position: new p5$2.Vector(0, 0) });
73834
+ shape.beginShape();
73835
+ shape.triangle(x1, y1, x2, y2, x3, y3);
73836
+ shape.endShape();
73837
+ this.drawShape(shape);
73401
73838
 
73402
73839
  return this;
73403
73840
  }
@@ -102730,6 +103167,7 @@ var p5 = (function () {
102730
103167
  const events = [
102731
103168
  'pointerdown',
102732
103169
  'pointerup',
103170
+ 'pointercancel',
102733
103171
  'pointermove',
102734
103172
  'dragend',
102735
103173
  'dragover',
@@ -103789,6 +104227,10 @@ var p5 = (function () {
103789
104227
  this._activePointers.set(e.pointerId, e);
103790
104228
  this._setMouseButton(e);
103791
104229
 
104230
+ if (this.mouseIsPressed && e.buttons === 0) {
104231
+ this._onpointerup(e);
104232
+ }
104233
+
103792
104234
  if (
103793
104235
  !this.mouseIsPressed &&
103794
104236
  typeof this._customActions.mouseMoved === 'function'
@@ -104115,6 +104557,16 @@ var p5 = (function () {
104115
104557
  fn._ondragend = fn._onpointerup;
104116
104558
  fn._ondragover = fn._onpointermove;
104117
104559
 
104560
+ fn._onpointercancel = function(e) {
104561
+ this._activePointers.delete(e.pointerId);
104562
+ this._setMouseButton(e);
104563
+ this._updatePointerCoords(e);
104564
+
104565
+ if (this._activePointers.size === 0) {
104566
+ this.mouseIsPressed = false;
104567
+ }
104568
+ };
104569
+
104118
104570
  /**
104119
104571
  * A function that's called once after a mouse button is pressed and released.
104120
104572
  *
@@ -106347,11 +106799,7 @@ var p5 = (function () {
106347
106799
  * -5 and 5 are both five units away from zero, so calling `abs(-5)` and
106348
106800
  * `abs(5)` both return 5. The absolute value of a number is always positive.
106349
106801
  *
106350
- * @method abs
106351
- * @param {Number} n number to compute.
106352
- * @return {Number} absolute value of given number.
106353
- *
106354
- * @example
106802
+ * ```js example
106355
106803
  * function setup() {
106356
106804
  * createCanvas(100, 100);
106357
106805
  *
@@ -106371,6 +106819,55 @@ var p5 = (function () {
106371
106819
  * // from the middle.
106372
106820
  * rect(0, 100 - h, 100, h);
106373
106821
  * }
106822
+ * ```
106823
+ *
106824
+ * `abs()` can also be used in shaders with p5.strands. The following example
106825
+ * uses `abs()` to create a mirror effect on the color of a shape.
106826
+ *
106827
+ * ```js example
106828
+ * let myShader;
106829
+ *
106830
+ * function setup() {
106831
+ * createCanvas(100, 100, WEBGL);
106832
+ * myShader = buildColorShader(shaderCallback);
106833
+ * describe('A sphere with colors that fold back like a mirror.');
106834
+ * }
106835
+ *
106836
+ * function shaderCallback() {
106837
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
106838
+ * let t = millis() * 0.001;
106839
+ *
106840
+ * // sin(t) goes between -1 and 1 over time.
106841
+ * let sinVal = sin(t);
106842
+ *
106843
+ * // abs() folds the negative values to positive.
106844
+ * // Now value goes between 0 and 1, creating a mirror effect.
106845
+ * let value = abs(sinVal);
106846
+ *
106847
+ * // Each color is [R, G, B, A] with values from 0 to 1.
106848
+ * let navy = [0.2, 0.2, 0.8, 1];
106849
+ * let coral = [0.8, 0.2, 0.2, 1];
106850
+ *
106851
+ * finalColor.begin();
106852
+ *
106853
+ * // mix() blends between navy (when value = 0) and coral (when value = 1).
106854
+ * finalColor.set(mix(navy, coral, value));
106855
+ *
106856
+ * finalColor.end();
106857
+ * }
106858
+ *
106859
+ * function draw() {
106860
+ * background(220);
106861
+ * shader(myShader);
106862
+ * noStroke();
106863
+ * sphere(30);
106864
+ * }
106865
+ * ```
106866
+ *
106867
+ * @method abs
106868
+ * @param {Number} n number to compute.
106869
+ * @return {Number} absolute value of given number.
106870
+ *
106374
106871
  */
106375
106872
  fn.abs = Math.abs;
106376
106873
 
@@ -106381,11 +106878,7 @@ var p5 = (function () {
106381
106878
  * For example, calling `ceil(9.03)` and `ceil(9.97)` both return the value
106382
106879
  * 10.
106383
106880
  *
106384
- * @method ceil
106385
- * @param {Number} n number to round up.
106386
- * @return {Integer} rounded up number.
106387
- *
106388
- * @example
106881
+ * ```js example
106389
106882
  * function setup() {
106390
106883
  * createCanvas(100, 100);
106391
106884
  *
@@ -106410,6 +106903,57 @@ var p5 = (function () {
106410
106903
  *
106411
106904
  * describe('Two rectangles. The one on the left is dark red and the one on the right is bright red.');
106412
106905
  * }
106906
+ * ```
106907
+ *
106908
+ * `ceil()` can also be used in shaders with p5.strands. The following example
106909
+ * uses `ceil()` to create a stepped color effect on a shape.
106910
+ *
106911
+ * ```js example
106912
+ * let myShader;
106913
+ *
106914
+ * function setup() {
106915
+ * createCanvas(100, 100, WEBGL);
106916
+ * myShader = buildColorShader(shaderCallback);
106917
+ * describe('A sphere with stepped color bands.');
106918
+ * }
106919
+ *
106920
+ * function shaderCallback() {
106921
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
106922
+ * let t = millis() * 0.001;
106923
+ *
106924
+ * // sin(t) goes between -1 and 1.
106925
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
106926
+ * let sinVal = 0.5 + 0.5 * sin(t);
106927
+ *
106928
+ * // Multiply by 4 then ceil to get the next whole number up.
106929
+ * // Divide by 4 to bring the result back to the 0 to 1 range.
106930
+ * // This creates 4 distinct stepped color levels: 0.25, 0.5, 0.75, 1.
106931
+ * let value = ceil(sinVal * 4) / 4;
106932
+ *
106933
+ * // Each color is [R, G, B, A] with values from 0 to 1.
106934
+ * let cyan = [0, 0.5, 1, 1];
106935
+ * let orange = [1, 0.5, 0, 1];
106936
+ *
106937
+ * finalColor.begin();
106938
+ *
106939
+ * // mix() blends between cyan (when value = 0) and orange (when value = 1).
106940
+ * // ceil() creates sharp steps between color levels.
106941
+ * finalColor.set(mix(cyan, orange, value));
106942
+ *
106943
+ * finalColor.end();
106944
+ * }
106945
+ *
106946
+ * function draw() {
106947
+ * background(220);
106948
+ * shader(myShader);
106949
+ * noStroke();
106950
+ * sphere(30);
106951
+ * }
106952
+ * ```
106953
+ *
106954
+ * @method ceil
106955
+ * @param {Number} n number to round up.
106956
+ * @return {Integer} rounded up number.
106413
106957
  */
106414
106958
  fn.ceil = Math.ceil;
106415
106959
 
@@ -106547,11 +107091,7 @@ var p5 = (function () {
106547
107091
  * Calculates the value of Euler's number e (2.71828...) raised to the power
106548
107092
  * of a number.
106549
107093
  *
106550
- * @method exp
106551
- * @param {Number} n exponent to raise.
106552
- * @return {Number} e^n
106553
- *
106554
- * @example
107094
+ * ```js example
106555
107095
  * function setup() {
106556
107096
  * createCanvas(100, 100);
106557
107097
  *
@@ -106575,8 +107115,9 @@ var p5 = (function () {
106575
107115
  *
106576
107116
  * describe('A series of circles that grow exponentially from top left to bottom right.');
106577
107117
  * }
107118
+ * ```
106578
107119
  *
106579
- * @example
107120
+ * ```js example
106580
107121
  * function setup() {
106581
107122
  * createCanvas(100, 100);
106582
107123
  *
@@ -106597,6 +107138,53 @@ var p5 = (function () {
106597
107138
  * // Draw a point.
106598
107139
  * point(x, y);
106599
107140
  * }
107141
+ * ```
107142
+ *
107143
+ * `exp()` can also be used in shaders with p5.strands. The following example
107144
+ * uses `exp()` to create an accelerating color transition on a shape.
107145
+ *
107146
+ * ```js example
107147
+ * let myShader;
107148
+ *
107149
+ * function setup() {
107150
+ * createCanvas(100, 100, WEBGL);
107151
+ * myShader = buildColorShader(shaderCallback);
107152
+ * describe('A sphere that brightens with accelerating speed.');
107153
+ * }
107154
+ *
107155
+ * function shaderCallback() {
107156
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.0005 to slow it.
107157
+ * let t = millis() * 0.0005;
107158
+ *
107159
+ * // exp(t) grows slowly at first, then accelerates (exponential growth).
107160
+ * // Multiply by 0.01 to keep it from growing too fast.
107161
+ * // min(..., 1) caps the value at 1 so it doesn't go past white.
107162
+ * let value = min(exp(t) * 0.01, 1);
107163
+ *
107164
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107165
+ * let darkBlue = [0.1, 0.1, 0.3, 1];
107166
+ * let lightYellow = [1, 1, 0.5, 1];
107167
+ *
107168
+ * finalColor.begin();
107169
+ *
107170
+ * // mix() blends between darkBlue (when value = 0) and lightYellow (when value = 1).
107171
+ * // Because exp() accelerates, the color transition gets faster over time.
107172
+ * finalColor.set(mix(darkBlue, lightYellow, value));
107173
+ *
107174
+ * finalColor.end();
107175
+ * }
107176
+ *
107177
+ * function draw() {
107178
+ * background(220);
107179
+ * shader(myShader);
107180
+ * noStroke();
107181
+ * sphere(30);
107182
+ * }
107183
+ * ```
107184
+ *
107185
+ * @method exp
107186
+ * @param {Number} n exponent to raise.
107187
+ * @return {Number} e^n
106600
107188
  */
106601
107189
  fn.exp = Math.exp;
106602
107190
 
@@ -106604,11 +107192,7 @@ var p5 = (function () {
106604
107192
  * Calculates the closest integer value that is less than or equal to the
106605
107193
  * value of a number.
106606
107194
  *
106607
- * @method floor
106608
- * @param {Number} n number to round down.
106609
- * @return {Integer} rounded down number.
106610
- *
106611
- * @example
107195
+ * ```js example
106612
107196
  * function setup() {
106613
107197
  * createCanvas(100, 100);
106614
107198
  *
@@ -106631,6 +107215,57 @@ var p5 = (function () {
106631
107215
  *
106632
107216
  * describe('Two rectangles. The one on the left is bright red and the one on the right is black.');
106633
107217
  * }
107218
+ * ```
107219
+ *
107220
+ * `floor()` can also be used in shaders with p5.strands. The following example
107221
+ * uses `floor()` to create banding effects on a shape.
107222
+ *
107223
+ * ```js example
107224
+ * let myShader;
107225
+ *
107226
+ * function setup() {
107227
+ * createCanvas(100, 100, WEBGL);
107228
+ * myShader = buildColorShader(shaderCallback);
107229
+ * describe('A sphere with posterized color bands.');
107230
+ * }
107231
+ *
107232
+ * function shaderCallback() {
107233
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107234
+ * let t = millis() * 0.001;
107235
+ *
107236
+ * // sin(t) goes between -1 and 1.
107237
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
107238
+ * let sinVal = 0.5 + 0.5 * sin(t);
107239
+ *
107240
+ * // Multiply by 4 then floor to get the next whole number down.
107241
+ * // Divide by 4 to bring the result back to the 0 to 1 range.
107242
+ * // This creates 5 distinct stepped color levels: 0, 0.25, 0.5, 0.75, 1.
107243
+ * let value = floor(sinVal * 4) / 4;
107244
+ *
107245
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107246
+ * let darkPurple = [0.2, 0, 0.8, 1];
107247
+ * let brightTeal = [0.2, 1, 0.8, 1];
107248
+ *
107249
+ * finalColor.begin();
107250
+ *
107251
+ * // mix() blends between darkPurple (when value = 0) and brightTeal (when value = 1).
107252
+ * // The floor() creates visible banding/posterization in the color.
107253
+ * finalColor.set(mix(darkPurple, brightTeal, value));
107254
+ *
107255
+ * finalColor.end();
107256
+ * }
107257
+ *
107258
+ * function draw() {
107259
+ * background(220);
107260
+ * shader(myShader);
107261
+ * noStroke();
107262
+ * sphere(30);
107263
+ * }
107264
+ * ```
107265
+ *
107266
+ * @method floor
107267
+ * @param {Number} n number to round down.
107268
+ * @return {Integer} rounded down number.
106634
107269
  */
106635
107270
  fn.floor = Math.floor;
106636
107271
 
@@ -106647,13 +107282,7 @@ var p5 = (function () {
106647
107282
  * number outside of the original interval. For example, calling
106648
107283
  * `lerp(0, 10, 1.5)` will return 15.
106649
107284
  *
106650
- * @method lerp
106651
- * @param {Number} start first value.
106652
- * @param {Number} stop second value.
106653
- * @param {Number} amt number.
106654
- * @return {Number} lerped value.
106655
- *
106656
- * @example
107285
+ * ```js example
106657
107286
  * function setup() {
106658
107287
  * createCanvas(100, 100);
106659
107288
  *
@@ -106681,8 +107310,9 @@ var p5 = (function () {
106681
107310
  *
106682
107311
  * describe('Five points in a horizontal line. The outer points are black and the inner points are gray.');
106683
107312
  * }
107313
+ * ```
106684
107314
  *
106685
- * @example
107315
+ * ```js example
106686
107316
  * let x = 50;
106687
107317
  * let y = 50;
106688
107318
  * let targetX = 50;
@@ -106712,6 +107342,54 @@ var p5 = (function () {
106712
107342
  * x = mouseX;
106713
107343
  * y = mouseY;
106714
107344
  * }
107345
+ * ```
107346
+ *
107347
+ * `lerp()` can also be used in shaders with p5.strands, where it maps to the
107348
+ * <a href="#/p5/mix">mix()</a> function in GLSL. The following example
107349
+ * uses `lerp()` to blend colors on a shape over time.
107350
+ *
107351
+ * ```js example
107352
+ * let myShader;
107353
+ *
107354
+ * function setup() {
107355
+ * createCanvas(100, 100, WEBGL);
107356
+ * myShader = buildColorShader(shaderCallback);
107357
+ * describe('A sphere that blends between teal and coral.');
107358
+ * }
107359
+ *
107360
+ * function shaderCallback() {
107361
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107362
+ * let t = millis() * 0.001;
107363
+ *
107364
+ * // sin(t) goes between -1 and 1 over time.
107365
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
107366
+ * let value = 0.5 + 0.5 * sin(t);
107367
+ *
107368
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107369
+ * let teal = [0, 0.8, 0.8, 1];
107370
+ * let coral = [1, 0.5, 0.3, 1];
107371
+ *
107372
+ * finalColor.begin();
107373
+ *
107374
+ * // lerp() blends teal (when value = 0) and coral (when value = 1).
107375
+ * finalColor.set(lerp(teal, coral, value));
107376
+ *
107377
+ * finalColor.end();
107378
+ * }
107379
+ *
107380
+ * function draw() {
107381
+ * background(220);
107382
+ * shader(myShader);
107383
+ * noStroke();
107384
+ * sphere(30);
107385
+ * }
107386
+ * ```
107387
+ *
107388
+ * @method lerp
107389
+ * @param {Number} start first value.
107390
+ * @param {Number} stop second value.
107391
+ * @param {Number} amt number.
107392
+ * @return {Number} lerped value.
106715
107393
  */
106716
107394
  fn.lerp = function(start, stop, amt) {
106717
107395
  // p5._validateParameters('lerp', arguments);
@@ -106724,11 +107402,7 @@ var p5 = (function () {
106724
107402
  * `log()` expects the `n` parameter to be a value greater than 0 because
106725
107403
  * the natural logarithm is defined that way.
106726
107404
  *
106727
- * @method log
106728
- * @param {Number} n number greater than 0.
106729
- * @return {Number} natural logarithm of n.
106730
- *
106731
- * @example
107405
+ * ```js example
106732
107406
  * function setup() {
106733
107407
  * createCanvas(100, 100);
106734
107408
  *
@@ -106744,8 +107418,9 @@ var p5 = (function () {
106744
107418
  *
106745
107419
  * describe('Two white circles. The circle at the top-left is small. The circle at the bottom-right is about five times larger.');
106746
107420
  * }
107421
+ * ```
106747
107422
  *
106748
- * @example
107423
+ * ```js example
106749
107424
  * function setup() {
106750
107425
  * createCanvas(100, 100);
106751
107426
  *
@@ -106766,6 +107441,53 @@ var p5 = (function () {
106766
107441
  * // Draw a point.
106767
107442
  * point(x, y);
106768
107443
  * }
107444
+ * ```
107445
+ *
107446
+ * `log()` can also be used in shaders with p5.strands. The following example
107447
+ * uses `log()` to create a decelerating color transition on a shape.
107448
+ *
107449
+ * ```js example
107450
+ * let myShader;
107451
+ *
107452
+ * function setup() {
107453
+ * createCanvas(100, 100, WEBGL);
107454
+ * myShader = buildColorShader(shaderCallback);
107455
+ * describe('A sphere that slowly shifts from purple to yellow.');
107456
+ * }
107457
+ *
107458
+ * function shaderCallback() {
107459
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107460
+ * let t = millis() * 0.001;
107461
+ *
107462
+ * // log(1 + t * 2) grows at a moderate pace over time.
107463
+ * // Multiply by 0.4 to bring it into the 0 to 1 range.
107464
+ * // min(..., 1) caps the value at 1.
107465
+ * let value = min(log(1 + t * 2) * 0.4, 1);
107466
+ *
107467
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107468
+ * let purple = [0.5, 0, 0.5, 1];
107469
+ * let yellow = [1, 1, 0, 1];
107470
+ *
107471
+ * finalColor.begin();
107472
+ *
107473
+ * // mix() blends between purple (when value = 0) and yellow (when value = 1).
107474
+ * // Because log() slows down over time, the color transition decelerates.
107475
+ * finalColor.set(mix(purple, yellow, value));
107476
+ *
107477
+ * finalColor.end();
107478
+ * }
107479
+ *
107480
+ * function draw() {
107481
+ * background(220);
107482
+ * shader(myShader);
107483
+ * noStroke();
107484
+ * sphere(30);
107485
+ * }
107486
+ * ```
107487
+ *
107488
+ * @method log
107489
+ * @param {Number} n number greater than 0.
107490
+ * @return {Number} natural logarithm of n.
106769
107491
  */
106770
107492
  fn.log = Math.log;
106771
107493
 
@@ -106833,16 +107555,7 @@ var p5 = (function () {
106833
107555
  * constrains the remapped value to the target range. For example,
106834
107556
  * `map(11, 0, 10, 0, 100, true)` returns 100.
106835
107557
  *
106836
- * @method map
106837
- * @param {Number} value the value to be remapped.
106838
- * @param {Number} start1 lower bound of the value's current range.
106839
- * @param {Number} stop1 upper bound of the value's current range.
106840
- * @param {Number} start2 lower bound of the value's target range.
106841
- * @param {Number} stop2 upper bound of the value's target range.
106842
- * @param {Boolean} [withinBounds] constrain the value to the newly mapped range.
106843
- * @return {Number} remapped number.
106844
- *
106845
- * @example
107558
+ * ```js example
106846
107559
  * function setup() {
106847
107560
  * createCanvas(100, 100);
106848
107561
  *
@@ -106861,8 +107574,9 @@ var p5 = (function () {
106861
107574
  * // Draw the bottom line.
106862
107575
  * line(0, 75, 0, x);
106863
107576
  * }
107577
+ * ```
106864
107578
  *
106865
- * @example
107579
+ * ```js example
106866
107580
  * function setup() {
106867
107581
  * createCanvas(100, 100);
106868
107582
  *
@@ -106881,6 +107595,58 @@ var p5 = (function () {
106881
107595
  * // Draw the circle.
106882
107596
  * circle(50, 50, 20);
106883
107597
  * }
107598
+ * ```
107599
+ *
107600
+ * `map()` can also be used in shaders with p5.strands. The following example
107601
+ * uses `map()` to remap time values to color in a shader.
107602
+ *
107603
+ * ```js example
107604
+ * let myShader;
107605
+ *
107606
+ * function setup() {
107607
+ * createCanvas(100, 100, WEBGL);
107608
+ * myShader = buildColorShader(shaderCallback);
107609
+ * describe('A sphere that shifts between cyan and orange over time.');
107610
+ * }
107611
+ *
107612
+ * function shaderCallback() {
107613
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107614
+ * let t = millis() * 0.001;
107615
+ *
107616
+ * // sin(t) goes between -1 and 1 over time.
107617
+ * let sinVal = sin(t);
107618
+ *
107619
+ * // map() remaps this from the range [-1, 1] to the range [0, 1].
107620
+ * let value = map(sinVal, -1, 1, 0, 1);
107621
+ *
107622
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107623
+ * let cyan = [0, 0.5, 1, 1];
107624
+ * let orange = [1, 0.5, 0, 1];
107625
+ *
107626
+ * finalColor.begin();
107627
+ *
107628
+ * // mix() blends between cyan (when value = 0) and orange (when value = 1).
107629
+ * finalColor.set(mix(cyan, orange, value));
107630
+ *
107631
+ * finalColor.end();
107632
+ * }
107633
+ *
107634
+ * function draw() {
107635
+ * background(220);
107636
+ * shader(myShader);
107637
+ * noStroke();
107638
+ * sphere(30);
107639
+ * }
107640
+ * ```
107641
+ *
107642
+ * @method map
107643
+ * @param {Number} value the value to be remapped.
107644
+ * @param {Number} start1 lower bound of the value's current range.
107645
+ * @param {Number} stop1 upper bound of the value's current range.
107646
+ * @param {Number} start2 lower bound of the value's target range.
107647
+ * @param {Number} stop2 upper bound of the value's target range.
107648
+ * @param {Boolean} [withinBounds] constrain the value to the newly mapped range.
107649
+ * @return {Number} remapped number.
106884
107650
  */
106885
107651
  fn.map = function(n, start1, stop1, start2, stop2, withinBounds) {
106886
107652
  // p5._validateParameters('map', arguments);
@@ -106904,12 +107670,7 @@ var p5 = (function () {
106904
107670
  * The version of `max()` with two or more parameters interprets them as
106905
107671
  * individual numbers and returns the largest number.
106906
107672
  *
106907
- * @method max
106908
- * @param {Number} n0 first number to compare.
106909
- * @param {Number} n1 second number to compare.
106910
- * @return {Number} maximum number.
106911
- *
106912
- * @example
107673
+ * ```js example
106913
107674
  * function setup() {
106914
107675
  * createCanvas(100, 100);
106915
107676
  *
@@ -106927,8 +107688,9 @@ var p5 = (function () {
106927
107688
  *
106928
107689
  * describe('The number 20 written in the middle of a gray square.');
106929
107690
  * }
107691
+ * ```
106930
107692
  *
106931
- * @example
107693
+ * ```js example
106932
107694
  * function setup() {
106933
107695
  * createCanvas(100, 100);
106934
107696
  *
@@ -106949,6 +107711,53 @@ var p5 = (function () {
106949
107711
  *
106950
107712
  * describe('The number 20 written in the middle of a gray square.');
106951
107713
  * }
107714
+ * ```
107715
+ *
107716
+ * `max()` can also be used in shaders with p5.strands. The following example
107717
+ * uses `max()` to clamp values in a shader.
107718
+ *
107719
+ * ```js example
107720
+ * let myShader;
107721
+ *
107722
+ * function setup() {
107723
+ * createCanvas(100, 100, WEBGL);
107724
+ * myShader = buildColorShader(shaderCallback);
107725
+ * describe('A sphere that shifts from rose to steelBlue and stops.');
107726
+ * }
107727
+ *
107728
+ * function shaderCallback() {
107729
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107730
+ * let t = millis() * 0.001;
107731
+ *
107732
+ * // 1 - t * 0.2 decreases steadily over time.
107733
+ * // max(..., 0) ensures the value never goes below 0.
107734
+ * let value = max(1 - t * 0.2, 0);
107735
+ *
107736
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107737
+ * let steelBlue = [0, 0.3, 0.8, 1];
107738
+ * let rose = [1, 0.3, 0.8, 1];
107739
+ *
107740
+ * finalColor.begin();
107741
+ *
107742
+ * // mix() blends between steelBlue (when value = 0) and rose (when value = 1).
107743
+ * // max() clamps the blend so the color stops changing once it reaches steelBlue.
107744
+ * finalColor.set(mix(steelBlue, rose, value));
107745
+ *
107746
+ * finalColor.end();
107747
+ * }
107748
+ *
107749
+ * function draw() {
107750
+ * background(220);
107751
+ * shader(myShader);
107752
+ * noStroke();
107753
+ * sphere(30);
107754
+ * }
107755
+ * ```
107756
+ *
107757
+ * @method max
107758
+ * @param {Number} n0 first number to compare.
107759
+ * @param {Number} n1 second number to compare.
107760
+ * @return {Number} maximum number.
106952
107761
  */
106953
107762
  /**
106954
107763
  * @method max
@@ -106980,12 +107789,7 @@ var p5 = (function () {
106980
107789
  * The version of `min()` with two or more parameters interprets them as
106981
107790
  * individual numbers and returns the smallest number.
106982
107791
  *
106983
- * @method min
106984
- * @param {Number} n0 first number to compare.
106985
- * @param {Number} n1 second number to compare.
106986
- * @return {Number} minimum number.
106987
- *
106988
- * @example
107792
+ * ```js example
106989
107793
  * function setup() {
106990
107794
  * createCanvas(100, 100);
106991
107795
  *
@@ -107003,8 +107807,9 @@ var p5 = (function () {
107003
107807
  *
107004
107808
  * describe('The number 5 written in the middle of a gray square.');
107005
107809
  * }
107810
+ * ```
107006
107811
  *
107007
- * @example
107812
+ * ```js example
107008
107813
  * function setup() {
107009
107814
  * createCanvas(100, 100);
107010
107815
  *
@@ -107025,6 +107830,53 @@ var p5 = (function () {
107025
107830
  *
107026
107831
  * describe('The number 5 written in the middle of a gray square.');
107027
107832
  * }
107833
+ * ```
107834
+ *
107835
+ * `min()` can also be used in shaders with p5.strands. The following example
107836
+ * uses `min()` to clamp values in a shader.
107837
+ *
107838
+ * ```js example
107839
+ * let myShader;
107840
+ *
107841
+ * function setup() {
107842
+ * createCanvas(100, 100, WEBGL);
107843
+ * myShader = buildColorShader(shaderCallback);
107844
+ * describe('A sphere that shifts from red to green and stops.');
107845
+ * }
107846
+ *
107847
+ * function shaderCallback() {
107848
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
107849
+ * let t = millis() * 0.001;
107850
+ *
107851
+ * // t * 0.2 grows steadily over time.
107852
+ * // min(..., 1) caps the value at 1 so it doesn't go past the target color.
107853
+ * let value = min(t * 0.2, 1);
107854
+ *
107855
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107856
+ * let deepRed = [0.8, 0, 0.2, 1];
107857
+ * let yellowGreen = [0.8, 1, 0.2, 1];
107858
+ *
107859
+ * finalColor.begin();
107860
+ *
107861
+ * // mix() blends between deepRed (when value = 0) and yellowGreen (when value = 1).
107862
+ * // min() clamps the blend so the color stops changing once it reaches yellowGreen.
107863
+ * finalColor.set(mix(deepRed, yellowGreen, value));
107864
+ *
107865
+ * finalColor.end();
107866
+ * }
107867
+ *
107868
+ * function draw() {
107869
+ * background(220);
107870
+ * shader(myShader);
107871
+ * noStroke();
107872
+ * sphere(30);
107873
+ * }
107874
+ * ```
107875
+ *
107876
+ * @method min
107877
+ * @param {Number} n0 first number to compare.
107878
+ * @param {Number} n1 second number to compare.
107879
+ * @return {Number} minimum number.
107028
107880
  */
107029
107881
  /**
107030
107882
  * @method min
@@ -107093,12 +107945,7 @@ var p5 = (function () {
107093
107945
  * 2 &times; 2 &times; 2. `pow(2, -3)` evaluates 1 &#247;
107094
107946
  * (2 &times; 2 &times; 2).
107095
107947
  *
107096
- * @method pow
107097
- * @param {Number} n base of the exponential expression.
107098
- * @param {Number} e power by which to raise the base.
107099
- * @return {Number} n^e.
107100
- *
107101
- * @example
107948
+ * ```js example
107102
107949
  * function setup() {
107103
107950
  * createCanvas(100, 100);
107104
107951
  *
@@ -107125,6 +107972,52 @@ var p5 = (function () {
107125
107972
  *
107126
107973
  * describe('A series of circles that grow exponentially from top left to bottom right.');
107127
107974
  * }
107975
+ * ```
107976
+ *
107977
+ * `pow()` can also be used in shaders with p5.strands. The following example
107978
+ * uses `pow()` to create a gamma curve effect on colors in a shader.
107979
+ *
107980
+ * ```js example
107981
+ * let myShader;
107982
+ *
107983
+ * function setup() {
107984
+ * createCanvas(100, 100, WEBGL);
107985
+ * myShader = buildColorShader(shaderCallback);
107986
+ * describe('A sphere with colors that shift with a power curve.');
107987
+ * }
107988
+ *
107989
+ * function shaderCallback() {
107990
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.0005 to slow it.
107991
+ * let t = millis() * 0.0005;
107992
+ *
107993
+ * // pow(t, 2) squares the time value: it starts slow then accelerates.
107994
+ * let value = pow(t, 2);
107995
+ *
107996
+ * // Each color is [R, G, B, A] with values from 0 to 1.
107997
+ * let deepBlue = [0, 0.1, 0.5, 1];
107998
+ * let gold = [1, 0.8, 0, 1];
107999
+ *
108000
+ * finalColor.begin();
108001
+ *
108002
+ * // mix() blends between deepBlue (when value = 0) and gold (when value = 1).
108003
+ * // Because pow() accelerates, the color transition gets faster over time.
108004
+ * finalColor.set(mix(deepBlue, gold, value));
108005
+ *
108006
+ * finalColor.end();
108007
+ * }
108008
+ *
108009
+ * function draw() {
108010
+ * background(220);
108011
+ * shader(myShader);
108012
+ * noStroke();
108013
+ * sphere(30);
108014
+ * }
108015
+ * ```
108016
+ *
108017
+ * @method pow
108018
+ * @param {Number} n base of the exponential expression.
108019
+ * @param {Number} e power by which to raise the base.
108020
+ * @return {Number} n^e.
107128
108021
  */
107129
108022
  fn.pow = Math.pow;
107130
108023
 
@@ -107137,12 +108030,7 @@ var p5 = (function () {
107137
108030
  * decimal places to use when rounding. For example, `round(12.34, 1)` returns
107138
108031
  * 12.3. `decimals` is 0 by default.
107139
108032
  *
107140
- * @method round
107141
- * @param {Number} n number to round.
107142
- * @param {Number} [decimals] number of decimal places to round to, default is 0.
107143
- * @return {Integer} rounded number.
107144
- *
107145
- * @example
108033
+ * ```js example
107146
108034
  * function setup() {
107147
108035
  * createCanvas(100, 100);
107148
108036
  *
@@ -107160,8 +108048,9 @@ var p5 = (function () {
107160
108048
  *
107161
108049
  * describe('The number 4 written in middle of the canvas.');
107162
108050
  * }
108051
+ * ```
107163
108052
  *
107164
- * @example
108053
+ * ```js example
107165
108054
  * function setup() {
107166
108055
  * createCanvas(100, 100);
107167
108056
  *
@@ -107179,6 +108068,57 @@ var p5 = (function () {
107179
108068
  *
107180
108069
  * describe('The number 12.78 written in middle of canvas.');
107181
108070
  * }
108071
+ * ```
108072
+ *
108073
+ * `round()` can also be used in shaders with p5.strands. The following example
108074
+ * uses `round()` to quantize colors in a shader.
108075
+ *
108076
+ * ```js example
108077
+ * let myShader;
108078
+ *
108079
+ * function setup() {
108080
+ * createCanvas(100, 100, WEBGL);
108081
+ * myShader = buildColorShader(shaderCallback);
108082
+ * describe('A sphere with posterized quantized colors.');
108083
+ * }
108084
+ *
108085
+ * function shaderCallback() {
108086
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
108087
+ * let t = millis() * 0.001;
108088
+ *
108089
+ * // sin(t) goes between -1 and 1.
108090
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
108091
+ * let sinVal = 0.5 + 0.5 * sin(t);
108092
+ *
108093
+ * // Multiply by 4 then round to get 5 distinct levels (0, 0.25, 0.5, 0.75, 1).
108094
+ * // Divide by 4 to bring the result back to the 0 to 1 range.
108095
+ * let value = round(sinVal * 4) / 4;
108096
+ *
108097
+ * // Each color is [R, G, B, A] with values from 0 to 1.
108098
+ * let mutedBlue = [0.3, 0.4, 0.7, 1];
108099
+ * let rose = [0.8, 0.3, 0.4, 1];
108100
+ *
108101
+ * finalColor.begin();
108102
+ *
108103
+ * // mix() blends between mutedBlue (when value = 0) and rose (when value = 1).
108104
+ * // The round() creates stepped bands of color like a posterization effect.
108105
+ * finalColor.set(mix(mutedBlue, rose, value));
108106
+ *
108107
+ * finalColor.end();
108108
+ * }
108109
+ *
108110
+ * function draw() {
108111
+ * background(220);
108112
+ * shader(myShader);
108113
+ * noStroke();
108114
+ * sphere(30);
108115
+ * }
108116
+ * ```
108117
+ *
108118
+ * @method round
108119
+ * @param {Number} n number to round.
108120
+ * @param {Number} [decimals] number of decimal places to round to, default is 0.
108121
+ * @return {Integer} rounded number.
107182
108122
  */
107183
108123
  fn.round = function(n, decimals) {
107184
108124
  if (!decimals) {
@@ -107249,11 +108189,7 @@ var p5 = (function () {
107249
108189
  * always returns a positive value. `sqrt()` doesn't work with negative arguments
107250
108190
  * such as `sqrt(-9)`.
107251
108191
  *
107252
- * @method sqrt
107253
- * @param {Number} n non-negative number to square root.
107254
- * @return {Number} square root of number.
107255
- *
107256
- * @example
108192
+ * ```js example
107257
108193
  * function setup() {
107258
108194
  * createCanvas(100, 100);
107259
108195
  *
@@ -107269,8 +108205,9 @@ var p5 = (function () {
107269
108205
  *
107270
108206
  * describe('Two white circles. The circle at the top-left is small. The circle at the bottom-right is ten times larger.');
107271
108207
  * }
108208
+ * ```
107272
108209
  *
107273
- * @example
108210
+ * ```js example
107274
108211
  * function setup() {
107275
108212
  * createCanvas(100, 100);
107276
108213
  *
@@ -107291,6 +108228,63 @@ var p5 = (function () {
107291
108228
  * // Draw the point.
107292
108229
  * point(x, y);
107293
108230
  * }
108231
+ * ```
108232
+ *
108233
+ * `sqrt()` can also be used in shaders with p5.strands. The following example
108234
+ * uses `sqrt()` to create a smooth ease-out curve on color and size.
108235
+ *
108236
+ * ```js example
108237
+ * let myShader;
108238
+ *
108239
+ * function setup() {
108240
+ * createCanvas(100, 100, WEBGL);
108241
+ * myShader = buildColorShader(shaderCallback);
108242
+ * describe('A sphere that grows and shifts from navy to orange with an ease-out curve.');
108243
+ * }
108244
+ *
108245
+ * function shaderCallback() {
108246
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
108247
+ * let t = millis() * 0.001;
108248
+ *
108249
+ * // sin(t) goes between -1 and 1.
108250
+ * // 0.5 + 0.5 * sin(t) remaps this to the 0 to 1 range.
108251
+ * let sinVal = 0.5 + 0.5 * sin(t);
108252
+ *
108253
+ * // sqrt(sinVal) creates an ease-out curve: fast start, slow finish.
108254
+ * // Since sinVal is in [0,1], sqrt() stays in [0,1].
108255
+ * let value = sqrt(sinVal);
108256
+ *
108257
+ * // Each color is [R, G, B, A] with values from 0 to 1.
108258
+ * let navy = [0, 0.1, 0.4, 1];
108259
+ * let brightOrange = [1, 0.6, 0, 1];
108260
+ *
108261
+ * finalColor.begin();
108262
+ *
108263
+ * // mix() blends between navy (when value = 0) and brightOrange (when value = 1).
108264
+ * // The sqrt() ease-out makes the color change fast at first, then slow down.
108265
+ * finalColor.set(mix(navy, brightOrange, value));
108266
+ *
108267
+ * finalColor.end();
108268
+ * }
108269
+ *
108270
+ * function drawShape() {
108271
+ * let t = millis() * 0.001;
108272
+ * let sinVal = 0.5 + 0.5 * sin(t);
108273
+ * let size = 10 + sqrt(sinVal) * 30;
108274
+ * sphere(size);
108275
+ * }
108276
+ *
108277
+ * function draw() {
108278
+ * background(220);
108279
+ * shader(myShader);
108280
+ * noStroke();
108281
+ * drawShape();
108282
+ * }
108283
+ * ```
108284
+ *
108285
+ * @method sqrt
108286
+ * @param {Number} n non-negative number to square root.
108287
+ * @return {Number} square root of number.
107294
108288
  */
107295
108289
  fn.sqrt = Math.sqrt;
107296
108290
 
@@ -107300,11 +108294,7 @@ var p5 = (function () {
107300
108294
  * A number's fractional part includes its decimal values. For example,
107301
108295
  * `fract(12.34)` returns 0.34.
107302
108296
  *
107303
- * @method fract
107304
- * @param {Number} n number whose fractional part will be found.
107305
- * @returns {Number} fractional part of n.
107306
- *
107307
- * @example
108297
+ * ```js example
107308
108298
  * function setup() {
107309
108299
  * createCanvas(100, 100);
107310
108300
  *
@@ -107324,6 +108314,53 @@ var p5 = (function () {
107324
108314
  *
107325
108315
  * describe('The number 56.78 written above the number 0.78.');
107326
108316
  * }
108317
+ * ```
108318
+ *
108319
+ * `fract()` can also be used in shaders with p5.strands. The following example
108320
+ * uses `fract()` to create repeating patterns in a shader.
108321
+ *
108322
+ * ```js example
108323
+ * let myShader;
108324
+ *
108325
+ * function setup() {
108326
+ * createCanvas(100, 100, WEBGL);
108327
+ * myShader = buildColorShader(shaderCallback);
108328
+ * describe('A sphere with a repeating gradient pattern.');
108329
+ * }
108330
+ *
108331
+ * function shaderCallback() {
108332
+ * // shaderCallback runs on the GPU. millis() gives ms since start; multiply by 0.001 for seconds.
108333
+ * let t = millis() * 0.001;
108334
+ *
108335
+ * // Multiply by 0.5 to slow the animation to half speed.
108336
+ * // fract(t * 0.5) extracts only the decimal part of the number.
108337
+ * // This creates a smooth sawtooth wave that repeats every 2 seconds.
108338
+ * let value = fract(t * 0.5);
108339
+ *
108340
+ * // Each color is [R, G, B, A] with values from 0 to 1.
108341
+ * let cyan = [0, 0.5, 1, 1];
108342
+ * let orange = [1, 0.5, 0, 1];
108343
+ *
108344
+ * finalColor.begin();
108345
+ *
108346
+ * // mix() blends between cyan (when value = 0) and orange (when value = 1).
108347
+ * // Because fract() resets to 0 each cycle, the color loops smoothly.
108348
+ * finalColor.set(mix(cyan, orange, value));
108349
+ *
108350
+ * finalColor.end();
108351
+ * }
108352
+ *
108353
+ * function draw() {
108354
+ * background(220);
108355
+ * shader(myShader);
108356
+ * noStroke();
108357
+ * sphere(30);
108358
+ * }
108359
+ * ```
108360
+ *
108361
+ * @method fract
108362
+ * @param {Number} n number whose fractional part will be found.
108363
+ * @returns {Number} fractional part of n.
107327
108364
  */
107328
108365
  fn.fract = function(toConvert) {
107329
108366
  // p5._validateParameters('fract', arguments);
@@ -108455,6 +109492,8 @@ var p5 = (function () {
108455
109492
  }
108456
109493
 
108457
109494
  /**
109495
+ * @private
109496
+ * @internal
108458
109497
  * Each of the following decorators validates the data on vector operations.
108459
109498
  * These ensure that the arguments are consistently formatted, and that
108460
109499
  * pre-conditions are met.
@@ -120924,7 +121963,7 @@ var p5 = (function () {
120924
121963
  * coordinates of the bounding box's bottom-left corner. See
120925
121964
  * <a href="#/p5/textAlign">textAlign()</a> for more ways to align text.
120926
121965
  *
120927
- * The fourth parameter, `options`, is also optional. `font.textToPoints()`
121966
+ * The fourth parameter, `options`, is also optional. `font.textToContours()`
120928
121967
  * expects an object with the following properties:
120929
121968
  *
120930
121969
  * `sampleFactor` is the ratio of the text's path length to the number of
@@ -121007,6 +122046,15 @@ var p5 = (function () {
121007
122046
  *
121008
122047
  * The generated model (a Geometry object) can be manipulated further—rotated, scaled,
121009
122048
  * or styled with shaders—to create engaging, interactive visual art.
122049
+ *
122050
+ * The `options` parameter is also optional. `font.textToModel()` expects an object
122051
+ * with the following properties:
122052
+ *
122053
+ * `extrude` is the depth to extrude the text. It defaults to 0. A value of 0 produces
122054
+ * flat text; higher values create thicker, 3D models.
122055
+ *
122056
+ * `sampleFactor` is a factor controlling the level of detail for the text contours.
122057
+ * It defaults to 1. Higher values result in smoother curves.
121010
122058
  *
121011
122059
  * @param {String} str The text string to convert into a 3D model.
121012
122060
  * @param {Number} x The x-coordinate for the starting position of the text.
@@ -124889,7 +125937,7 @@ var p5 = (function () {
124889
125937
  }
124890
125938
 
124891
125939
  // Create image from data
124892
- const region = new Image(w * framebuffer.density, h * framebuffer.density);
125940
+ const region = new Image$1(w * framebuffer.density, h * framebuffer.density);
124893
125941
  region.imageData = region.canvas.getContext('2d').createImageData(
124894
125942
  region.width,
124895
125943
  region.height
@@ -134982,19 +136030,116 @@ var p5 = (function () {
134982
136030
 
134983
136031
  for (const name of Object.keys(BUILTIN_GLOBAL_SPECS)) {
134984
136032
  const spec = BUILTIN_GLOBAL_SPECS[name];
134985
- Object.defineProperty(window, name, {
134986
- get: () => {
136033
+ const backingKey = `_strands_${name}`;
136034
+
136035
+ // Define on window for global mode only
136036
+ const inst = getRuntimeP5Instance();
136037
+ if (inst?._isGlobal) {
136038
+ Object.defineProperty(window, name, {
136039
+ get: () => {
136040
+ if (strandsContext.active) {
136041
+ return getBuiltinGlobalNode(strandsContext, name);
136042
+ }
136043
+ const inst = getRuntimeP5Instance();
136044
+ return spec.get(inst);
136045
+ },
136046
+ configurable: true,
136047
+ });
136048
+ }
136049
+
136050
+ // Capture original descriptor (held in closure for the getter to delegate to)
136051
+ const originalProtoDesc = Object.getOwnPropertyDescriptor(strandsContext.p5.prototype, name);
136052
+
136053
+ // Define on p5.prototype for instance mode
136054
+ Object.defineProperty(strandsContext.p5.prototype, name, {
136055
+ get: function() {
134987
136056
  if (strandsContext.active) {
134988
136057
  return getBuiltinGlobalNode(strandsContext, name);
134989
136058
  }
134990
- const inst = getRuntimeP5Instance();
134991
- return spec.get(inst);
136059
+ // If our setter stored a value on this instance, return it
136060
+ if (Object.prototype.hasOwnProperty.call(this, backingKey)) {
136061
+ return this[backingKey];
136062
+ }
136063
+ // Delegate to original getter (e.g. width -> this._renderer?.width)
136064
+ if (originalProtoDesc?.get) {
136065
+ return originalProtoDesc.get.call(this);
136066
+ }
136067
+ // Fall back to original value for data properties (like mouseX)
136068
+ return originalProtoDesc?.value;
134992
136069
  },
136070
+ set: function(val) {
136071
+ this[backingKey] = val;
136072
+ },
136073
+ configurable: true,
134993
136074
  });
136075
+
136076
+ // Define on p5.Graphics.prototype for graphics mode
136077
+ const GraphicsProto = strandsContext.p5?.Graphics?.prototype;
136078
+ if (GraphicsProto) {
136079
+ const originalDesc = Object.getOwnPropertyDescriptor(GraphicsProto, name);
136080
+
136081
+ Object.defineProperty(GraphicsProto, name, {
136082
+ get: function() {
136083
+ if (strandsContext.active) {
136084
+ return getBuiltinGlobalNode(strandsContext, name);
136085
+ }
136086
+ // Delegate to original getter if it exists (class-level getters like width, deltaTime)
136087
+ if (originalDesc?.get) {
136088
+ return originalDesc.get.call(this);
136089
+ }
136090
+ return this[backingKey];
136091
+ },
136092
+ set: function(val) {
136093
+ if (originalDesc?.set) {
136094
+ originalDesc.set.call(this, val);
136095
+ } else {
136096
+ this[backingKey] = val;
136097
+ }
136098
+ },
136099
+ configurable: true,
136100
+ });
136101
+ }
134994
136102
  }
134995
136103
  strandsContext._builtinGlobalsAccessorsInstalled = true;
134996
136104
  }
134997
136105
 
136106
+ function installInstanceIndexAccessor(strandsContext) {
136107
+ if (strandsContext._instanceIndexAccessorInstalled) return;
136108
+
136109
+ const getRuntimeP5Instance = () => strandsContext.renderer?._pInst || strandsContext.p5?.instance;
136110
+
136111
+ const instanceIndexGetter = function() {
136112
+ if (strandsContext.active) {
136113
+ const node = variableNode(strandsContext, { baseType: BaseType.INT, dimension: 1 }, strandsContext.backend.instanceIdReference());
136114
+ return createStrandsNode(node.id, node.dimension, strandsContext);
136115
+ }
136116
+ return undefined;
136117
+ };
136118
+
136119
+ const inst = getRuntimeP5Instance();
136120
+ if (inst?._isGlobal) {
136121
+ Object.defineProperty(window, 'instanceIndex', {
136122
+ get: instanceIndexGetter,
136123
+ configurable: true,
136124
+ });
136125
+ }
136126
+
136127
+ Object.defineProperty(strandsContext.p5.prototype, 'instanceIndex', {
136128
+ get: instanceIndexGetter,
136129
+ configurable: true,
136130
+ });
136131
+
136132
+ const GraphicsProto = strandsContext.p5?.Graphics?.prototype;
136133
+ if (GraphicsProto) {
136134
+ Object.defineProperty(GraphicsProto, 'instanceIndex', {
136135
+ get: instanceIndexGetter,
136136
+ configurable: true,
136137
+ });
136138
+ }
136139
+
136140
+ strandsContext._instanceIndexAccessorInstalled = true;
136141
+ }
136142
+
134998
136143
  //////////////////////////////////////////////
134999
136144
  // Prototype mirroring helpers
135000
136145
  //////////////////////////////////////////////
@@ -135168,7 +136313,7 @@ var p5 = (function () {
135168
136313
  const originalLerp = fn.lerp;
135169
136314
  augmentFn(fn, p5, 'lerp', function (...args) {
135170
136315
  if (strandsContext.active) {
135171
- return fn.mix(...args);
136316
+ return this.mix(...args);
135172
136317
  } else {
135173
136318
  return originalLerp.apply(this, args);
135174
136319
  }
@@ -135191,6 +136336,139 @@ var p5 = (function () {
135191
136336
  return result;
135192
136337
  });
135193
136338
 
136339
+ const originalColor = fn.color;
136340
+ augmentFn(fn, p5, 'color', function (...args) {
136341
+ if (!strandsContext.active) {
136342
+ return originalColor.apply(this, args);
136343
+ }
136344
+ // Reuse p5's parser - handles hex strings, rgb(), CSS named colors, numerics
136345
+ const c = originalColor.apply(this, args);
136346
+ // _getRGBA() returns [r, g, b, a] normalized to 0-1
136347
+ const rgba = c._getRGBA();
136348
+ const { id, dimension } = primitiveConstructorNode(
136349
+ strandsContext,
136350
+ { baseType: BaseType.FLOAT, dimension: null },
136351
+ rgba
136352
+ );
136353
+ return createStrandsNode(id, dimension, strandsContext);
136354
+ });
136355
+ const originalLerpColor = fn.lerpColor;
136356
+ augmentFn(fn, p5, 'lerpColor', function (...args) {
136357
+ if (!strandsContext.active) {
136358
+ return originalLerpColor.apply(this, args);
136359
+ }
136360
+ // In strands, colors are vec4s - lerpColor maps directly to GLSL mix()
136361
+ return this.mix(...args);
136362
+ });
136363
+ // Component accessors: extract scalar channels from a vec4 color
136364
+ const originalRed = fn.red;
136365
+ augmentFn(fn, p5, 'red', function (...args) {
136366
+ if (!strandsContext.active) {
136367
+ return originalRed.apply(this, args);
136368
+ }
136369
+ return p5.strandsNode(args[0]).x;
136370
+ });
136371
+
136372
+ const originalGreen = fn.green;
136373
+ augmentFn(fn, p5, 'green', function (...args) {
136374
+ if (!strandsContext.active) {
136375
+ return originalGreen.apply(this, args);
136376
+ }
136377
+ return p5.strandsNode(args[0]).y;
136378
+ });
136379
+
136380
+ const originalBlue = fn.blue;
136381
+ augmentFn(fn, p5, 'blue', function (...args) {
136382
+ if (!strandsContext.active) {
136383
+ return originalBlue.apply(this, args);
136384
+ }
136385
+ return p5.strandsNode(args[0]).z;
136386
+ });
136387
+
136388
+ const originalAlpha = fn.alpha;
136389
+ augmentFn(fn, p5, 'alpha', function (...args) {
136390
+ if (!strandsContext.active) {
136391
+ return originalAlpha.apply(this, args);
136392
+ }
136393
+ return p5.strandsNode(args[0]).w;
136394
+ });
136395
+
136396
+ // RGB to HSB conversion based on:
136397
+ // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
136398
+ // Using mix/step to avoid branching, via the compact form from:
136399
+ // http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
136400
+ const _rgb2hsb = (instance, colorNode) => {
136401
+ const r = colorNode.x;
136402
+ const g = colorNode.y;
136403
+ const b = colorNode.z;
136404
+ const K = instance.vec4(0, -1/3, 2/3, -1);
136405
+ const p = instance.mix(
136406
+ instance.vec4(b, g, K.w, K.z),
136407
+ instance.vec4(g, b, K.x, K.y),
136408
+ instance.step(b, g)
136409
+ );
136410
+ const q = instance.mix(
136411
+ instance.vec4(p.x, p.y, p.w, r),
136412
+ instance.vec4(r, p.y, p.z, p.x),
136413
+ instance.step(p.x, r)
136414
+ );
136415
+ const d = q.x.sub(instance.min(q.w, q.y));
136416
+ const e = p5.strandsNode(1e-10);
136417
+ const h = instance.abs(q.z.add(q.w.sub(q.y).div(d.mult(6).add(e))));
136418
+ const s = d.div(q.x.add(e));
136419
+ return instance.vec3(h, s, q.x);
136420
+ };
136421
+
136422
+ const _rgb2hsl = (instance, colorNode) => {
136423
+ const r = colorNode.x;
136424
+ const g = colorNode.y;
136425
+ const b = colorNode.z;
136426
+ const maxC = instance.max(r, instance.max(g, b));
136427
+ const minC = instance.min(r, instance.min(g, b));
136428
+ const l = maxC.add(minC).div(2);
136429
+ const d = maxC.sub(minC);
136430
+ const e = p5.strandsNode(1e-10);
136431
+ const s = instance.mix(
136432
+ p5.strandsNode(0),
136433
+ d.div(p5.strandsNode(1).sub(instance.abs(l.mult(2).sub(1)))),
136434
+ instance.step(e, d)
136435
+ );
136436
+ const h_rg = instance.mod(g.sub(b).div(d.add(e)), p5.strandsNode(6)).div(6);
136437
+ const h_gb = b.sub(r).div(d.add(e)).add(2).div(6);
136438
+ const h_br = r.sub(g).div(d.add(e)).add(4).div(6);
136439
+ const isR = instance.step(maxC.sub(e), r).mult(instance.step(r.sub(e), maxC));
136440
+ const isG = instance.step(maxC.sub(e), g).mult(instance.step(g.sub(e), maxC));
136441
+ const h = instance.mix(instance.mix(h_br, h_gb, isG), h_rg, isR);
136442
+ return instance.vec3(h, s, l);
136443
+ };
136444
+ const originalHue = fn.hue;
136445
+ augmentFn(fn, p5, 'hue', function (...args) {
136446
+ if (!strandsContext.active) return originalHue.apply(this, args);
136447
+ const colorNode = p5.strandsNode(args[0]);
136448
+ return _rgb2hsl(this, this.vec3(colorNode.x, colorNode.y, colorNode.z)).x;
136449
+ });
136450
+
136451
+ const originalSaturation = fn.saturation;
136452
+ augmentFn(fn, p5, 'saturation', function (...args) {
136453
+ if (!strandsContext.active) return originalSaturation.apply(this, args);
136454
+ const colorNode = p5.strandsNode(args[0]);
136455
+ return _rgb2hsl(this, this.vec3(colorNode.x, colorNode.y, colorNode.z)).y;
136456
+ });
136457
+
136458
+ const originalBrightness = fn.brightness;
136459
+ augmentFn(fn, p5, 'brightness', function (...args) {
136460
+ if (!strandsContext.active) return originalBrightness.apply(this, args);
136461
+ const colorNode = p5.strandsNode(args[0]);
136462
+ return _rgb2hsb(this, this.vec3(colorNode.x, colorNode.y, colorNode.z)).z;
136463
+ });
136464
+
136465
+ const originalLightness = fn.lightness;
136466
+ augmentFn(fn, p5, 'lightness', function (...args) {
136467
+ if (!strandsContext.active) return originalLightness.apply(this, args);
136468
+ const colorNode = p5.strandsNode(args[0]);
136469
+ return _rgb2hsl(this, this.vec3(colorNode.x, colorNode.y, colorNode.z)).z;
136470
+ });
136471
+
135194
136472
  augmentFn(fn, p5, 'getTexture', function (...rawArgs) {
135195
136473
  if (strandsContext.active) {
135196
136474
  const { id, dimension } = strandsContext.backend.createGetTextureCall(strandsContext, rawArgs);
@@ -135216,6 +136494,7 @@ var p5 = (function () {
135216
136494
  const originalNoise = fn.noise;
135217
136495
  const originalNoiseDetail = fn.noiseDetail;
135218
136496
  const originalRandom = fn.random;
136497
+ const originalRandomGaussian=fn.randomGaussian;
135219
136498
  const originalRandomSeed = fn.randomSeed;
135220
136499
  const originalMillis = fn.millis;
135221
136500
 
@@ -135359,6 +136638,20 @@ var p5 = (function () {
135359
136638
  }
135360
136639
  });
135361
136640
 
136641
+ augmentFn(fn, p5, 'randomGaussian', function(...args){
136642
+ if(!strandsContext.active){
136643
+ return originalRandomGaussian.apply(this, args);
136644
+ }
136645
+ const mean = args.length >= 1 ? args[0] : 0;
136646
+ const stdDev = args.length >= 2 ? args[1] : 1;
136647
+
136648
+ const u1 = this.max(this.random(), 1e-6);
136649
+ const u2 = this.random();
136650
+ const z = this.sqrt(this.log(u1).mult(-2)).mult(this.cos(u2.mult(2*Math.PI)));
136651
+
136652
+ return z.mult(stdDev).add(mean);
136653
+ });
136654
+
135362
136655
  augmentFn(fn, p5, 'millis', function (...args) {
135363
136656
  if (!strandsContext.active) {
135364
136657
  return originalMillis.apply(this, args);
@@ -135550,6 +136843,17 @@ var p5 = (function () {
135550
136843
  return createStrandsNode(propNode.id, propNode.dimension, strandsContext, onRebind);
135551
136844
  },
135552
136845
  set(val) {
136846
+ const valDim = val?.isStrandsNode
136847
+ ? val.dimension
136848
+ : (Array.isArray(val) ? val.length : 1);
136849
+ if( valDim !== propertyType.dataType.dimension && valDim !== 1){
136850
+ dimensionMismatchError(
136851
+ propertyType.dataType.dimension,
136852
+ valDim,
136853
+ `${param.name}.${propertyType.name}`
136854
+ );
136855
+ }
136856
+
135553
136857
  const oldDependsOn = dag.dependsOn[structNode.id];
135554
136858
  const newDependsOn = [...oldDependsOn];
135555
136859
  let newValueID;
@@ -135627,6 +136931,7 @@ var p5 = (function () {
135627
136931
  }
135628
136932
  function createShaderHooksFunctions(strandsContext, fn, shader) {
135629
136933
  installBuiltinGlobalAccessors(strandsContext);
136934
+ installInstanceIndexAccessor(strandsContext);
135630
136935
 
135631
136936
  // Add shader context to hooks before spreading
135632
136937
  const vertexHooksWithContext = Object.fromEntries(
@@ -135659,6 +136964,54 @@ var p5 = (function () {
135659
136964
  hook.set = function(result) {
135660
136965
  hook._result = result;
135661
136966
  };
136967
+ hook._active = false;
136968
+
136969
+ const numStructArgs = hookType.parameters.filter(
136970
+ param => param.type && param.type.properties
136971
+ ).length;
136972
+ let argIdx = -1;
136973
+ if (numStructArgs === 1) {
136974
+ argIdx = hookType.parameters.findIndex(
136975
+ param => param.type && param.type.properties
136976
+ );
136977
+ }
136978
+ if (argIdx >= 0) {
136979
+ const structParam = hookType.parameters[argIdx];
136980
+ if (structParam.type.properties) {
136981
+ const nameMatch = /^get([A-Z0-9]\w*)$/.exec(hookType.name);
136982
+ const displayName = nameMatch
136983
+ ? nameMatch[1][0].toLowerCase() + nameMatch[1].slice(1)
136984
+ : hookType.name;
136985
+ for (const prop of structParam.type.properties) {
136986
+ const key = prop.name;
136987
+ Object.defineProperty(hook, key, {
136988
+ get() {
136989
+ if (!this._active) {
136990
+ userError(
136991
+ 'scope error',
136992
+ `It looks like you're trying to access "${displayName}.${key}" outside of its begin()/end() block.\n\n` +
136993
+ `Properties of ${displayName} are only available between ` +
136994
+ `${displayName}.begin() and ${displayName}.end().\n\n` +
136995
+ `To share data between hooks, use sharedVec3() or sharedFloat() ` +
136996
+ `to pass values between them.`
136997
+ );
136998
+ }
136999
+ return this._args[this._argIdx][key];
137000
+ },
137001
+ set(val) {
137002
+ if (!this._active) {
137003
+ userError(
137004
+ 'scope error',
137005
+ `It looks like you're trying to set "${displayName}.${key}" outside of its begin()/end() block.`
137006
+ );
137007
+ }
137008
+ this._args[this._argIdx][key] = val;
137009
+ },
137010
+ enumerable: true,
137011
+ });
137012
+ }
137013
+ }
137014
+ }
135662
137015
 
135663
137016
  let entryBlockID;
135664
137017
  function setupHook() {
@@ -135667,25 +137020,14 @@ var p5 = (function () {
135667
137020
  addEdge(cfg, cfg.currentBlock, entryBlockID);
135668
137021
  pushBlock(cfg, entryBlockID);
135669
137022
  const args = createHookArguments(strandsContext, hookType.parameters);
135670
- const numStructArgs = hookType.parameters.filter(param => param.type.properties).length;
135671
- let argIdx = -1;
135672
- if (numStructArgs === 1) {
135673
- argIdx = hookType.parameters.findIndex(param => param.type.properties);
135674
- }
137023
+ hook._active = true;
137024
+ hook._args = args;
137025
+ hook._argIdx = argIdx;
135675
137026
  hook._properties = [];
135676
137027
  for (let i = 0; i < args.length; i++) {
135677
137028
  if (i === argIdx) {
135678
137029
  for (const key of args[argIdx].structProperties || []) {
135679
137030
  hook._properties.push(key);
135680
- Object.defineProperty(hook, key, {
135681
- get() {
135682
- return args[argIdx][key];
135683
- },
135684
- set(val) {
135685
- args[argIdx][key] = val;
135686
- },
135687
- enumerable: true,
135688
- });
135689
137031
  }
135690
137032
  if (hookType.returnType?.typeName === hookType.parameters[argIdx].type.typeName) {
135691
137033
  hook.set(args[argIdx]);
@@ -135698,6 +137040,7 @@ var p5 = (function () {
135698
137040
  return args;
135699
137041
  }
135700
137042
  function finishHook() {
137043
+ hook._active = false;
135701
137044
  const userReturned = hook._result;
135702
137045
  strandsContext.activeHook = undefined;
135703
137046
 
@@ -136136,18 +137479,20 @@ var p5 = (function () {
136136
137479
  */
136137
137480
 
136138
137481
  /**
136139
- * @method instanceID
137482
+ * @property instanceIndex
136140
137483
  * @beta
136141
137484
  * @description
136142
137485
  * Returns the index of the current instance when drawing multiple copies of a
136143
137486
  * shape with <a href="#/p5/model">`model(count)`</a>. The first instance has an
136144
- * ID of `0`, the second has `1`, and so on.
137487
+ * index of `0`, the second has `1`, and so on.
136145
137488
  *
136146
137489
  * This lets each copy of a shape behave differently. For example, you can use
136147
- * the ID to place instances at different positions, give them different colors,
137490
+ * the index to place instances at different positions, give them different colors,
136148
137491
  * or animate them at different speeds.
136149
137492
  *
136150
- * `instanceID()` can only be used inside a p5.strands shader callback.
137493
+ * `instanceIndex` can only be used inside a p5.strands shader callback.
137494
+ *
137495
+ * (Note: `instanceID()` is also available as a function for compatibility.)
136151
137496
  *
136152
137497
  * ```js example
136153
137498
  * let instancesShader;
@@ -136170,7 +137515,7 @@ var p5 = (function () {
136170
137515
  * // Spread spheres evenly across the canvas based on their index
136171
137516
  * let spacing = width / count;
136172
137517
  * worldInputs.position.x +=
136173
- * (instanceID() - (count - 1) / 2) * spacing;
137518
+ * (instanceIndex - (count - 1) / 2) * spacing;
136174
137519
  * worldInputs.end();
136175
137520
  * }
136176
137521
  *
@@ -136184,7 +137529,7 @@ var p5 = (function () {
136184
137529
  * }
136185
137530
  * ```
136186
137531
  *
136187
- * If you are using WebGPU mode, a common pattern is to use `instanceID()` to look up data made with
137532
+ * If you are using WebGPU mode, a common pattern is to use `instanceIndex` to look up data made with
136188
137533
  * <a href="#/p5/createStorage">`createStorage()`</a>.
136189
137534
  * This lets you give each instance different properties.
136190
137535
  *
@@ -136227,7 +137572,7 @@ var p5 = (function () {
136227
137572
  * let itemColor = sharedVec4();
136228
137573
  *
136229
137574
  * worldInputs.begin();
136230
- * let item = data[instanceID()];
137575
+ * let item = data[instanceIndex];
136231
137576
  * itemColor = item.color;
136232
137577
  * worldInputs.position += item.position;
136233
137578
  * worldInputs.end();
@@ -136249,7 +137594,22 @@ var p5 = (function () {
136249
137594
  * This can be paired with <a href="#/p5/buildComputeShader">`buildComputeShader`</a>
136250
137595
  * to update the data being read.
136251
137596
  *
136252
- * @webgpu
137597
+ * @type {*}
137598
+ */
137599
+
137600
+ /**
137601
+ * @method instanceID
137602
+ * @beta
137603
+ * @deprecated Use <a href="#/p5/instanceIndex">`instanceIndex`</a> instead.
137604
+ * @description
137605
+ * A function alias for <a href="#/p5/instanceIndex">`instanceIndex`</a>, kept for compatibility.
137606
+ * Prefer using <a href="#/p5/instanceIndex">`instanceIndex`</a> directly as a value instead.
137607
+ *
137608
+ * Returns the index of the current instance when drawing multiple copies of a
137609
+ * shape with <a href="#/p5/model">`model(count)`</a>.
137610
+ *
137611
+ * `instanceID()` can only be used inside a p5.strands shader callback.
137612
+ *
136253
137613
  * @returns {*} The index of the current instance.
136254
137614
  */
136255
137615