q5 2.9.22 → 2.9.23

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 (69) hide show
  1. package/.vscode/launch.json +26 -0
  2. package/bun.lockb +0 -0
  3. package/p5-tests/js/chai_helpers.js +20 -0
  4. package/p5-tests/js/mocha_setup.js +2 -0
  5. package/p5-tests/js/modernizr.js +5 -0
  6. package/p5-tests/js/p5_helpers.js +135 -0
  7. package/p5-tests/js/sinon.js +5949 -0
  8. package/p5-tests/mocha.css +289 -0
  9. package/p5-tests/test.html +71 -0
  10. package/p5-tests/unit/color/color_conversion.js +68 -0
  11. package/p5-tests/unit/color/creating_reading.js +217 -0
  12. package/p5-tests/unit/color/p5.Color.js +1000 -0
  13. package/p5-tests/unit/color/setting.js +289 -0
  14. package/p5-tests/unit/core/2d_primitives.js +490 -0
  15. package/p5-tests/unit/core/attributes.js +115 -0
  16. package/p5-tests/unit/core/curves.js +139 -0
  17. package/p5-tests/unit/core/environment.js +248 -0
  18. package/p5-tests/unit/core/error_helpers.js +1158 -0
  19. package/p5-tests/unit/core/main.js +340 -0
  20. package/p5-tests/unit/core/p5.Element.js +773 -0
  21. package/p5-tests/unit/core/p5.Graphics.js +179 -0
  22. package/p5-tests/unit/core/preload.js +285 -0
  23. package/p5-tests/unit/core/rendering.js +116 -0
  24. package/p5-tests/unit/core/structure.js +293 -0
  25. package/p5-tests/unit/core/transform.js +144 -0
  26. package/p5-tests/unit/core/version.js +28 -0
  27. package/p5-tests/unit/core/vertex.js +137 -0
  28. package/p5-tests/unit/dom/dom.js +2146 -0
  29. package/p5-tests/unit/events/acceleration.js +213 -0
  30. package/p5-tests/unit/events/keyboard.js +179 -0
  31. package/p5-tests/unit/events/mouse.js +487 -0
  32. package/p5-tests/unit/events/touch.js +180 -0
  33. package/p5-tests/unit/image/downloading.js +379 -0
  34. package/p5-tests/unit/image/filters.js +92 -0
  35. package/p5-tests/unit/image/loading.js +413 -0
  36. package/p5-tests/unit/image/p5.Image.js +201 -0
  37. package/p5-tests/unit/image/pixels.js +234 -0
  38. package/p5-tests/unit/io/files.js +378 -0
  39. package/p5-tests/unit/io/loadBytes.js +149 -0
  40. package/p5-tests/unit/io/loadImage.js +123 -0
  41. package/p5-tests/unit/io/loadJSON.js +185 -0
  42. package/p5-tests/unit/io/loadModel.js +215 -0
  43. package/p5-tests/unit/io/loadShader.js +176 -0
  44. package/p5-tests/unit/io/loadStrings.js +140 -0
  45. package/p5-tests/unit/io/loadTable.js +183 -0
  46. package/p5-tests/unit/io/loadXML.js +127 -0
  47. package/p5-tests/unit/io/saveModel.js +113 -0
  48. package/p5-tests/unit/io/saveTable.js +142 -0
  49. package/p5-tests/unit/math/calculation.js +452 -0
  50. package/p5-tests/unit/math/noise.js +66 -0
  51. package/p5-tests/unit/math/p5.Vector.js +1886 -0
  52. package/p5-tests/unit/math/random.js +177 -0
  53. package/p5-tests/unit/math/trigonometry.js +144 -0
  54. package/p5-tests/unit/spec.js +50 -0
  55. package/p5-tests/unit/typography/attributes.js +120 -0
  56. package/p5-tests/unit/typography/loadFont.js +162 -0
  57. package/p5-tests/unit/typography/p5.Font.js +63 -0
  58. package/p5-tests/unit/utilities/conversion.js +329 -0
  59. package/p5-tests/unit/utilities/time_date.js +133 -0
  60. package/package.json +1 -1
  61. package/q5.js +48 -37
  62. package/q5.min.js +1 -1
  63. package/src/q5-2d-image.js +3 -1
  64. package/src/q5-core.js +3 -1
  65. package/src/q5-math.js +1 -0
  66. package/src/q5-webgpu-canvas.js +8 -7
  67. package/src/q5-webgpu-drawing.js +15 -12
  68. package/src/q5-webgpu-image.js +1 -1
  69. package/src/q5-webgpu-text.js +17 -15
package/q5.js CHANGED
@@ -118,7 +118,7 @@ function Q5(scope, parent, renderer) {
118
118
  };
119
119
  $.loop = () => {
120
120
  $._loop = true;
121
- if (looper == null) $._draw();
121
+ if ($._setupDone && looper == null) $._draw();
122
122
  };
123
123
  $.isLooping = () => $._loop;
124
124
  $.redraw = (n = 1) => {
@@ -309,6 +309,8 @@ function createCanvas(w, h, opt) {
309
309
  }
310
310
  }
311
311
 
312
+ Q5.version = Q5.VERSION = '2.9';
313
+
312
314
  if (typeof document == 'object') {
313
315
  document.addEventListener('DOMContentLoaded', () => {
314
316
  if (!Q5._hasGlobal) new Q5('auto');
@@ -1248,7 +1250,9 @@ Q5.renderers.q2d.image = ($, q) => {
1248
1250
  $.loadImage = function (url, cb, opt) {
1249
1251
  if (url.canvas) return url;
1250
1252
  if (url.slice(-3).toLowerCase() == 'gif') {
1251
- throw new Error(`q5 doesn't support GIFs due to their impact on performance. Use a video or animation instead.`);
1253
+ throw new Error(
1254
+ `q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84`
1255
+ );
1252
1256
  }
1253
1257
  q._preloadCount++;
1254
1258
  let last = [...arguments].at(-1);
@@ -2403,6 +2407,7 @@ Q5.modules.math = ($, q) => {
2403
2407
 
2404
2408
  $.angleMode = (mode) => {
2405
2409
  angleMode = $._angleMode = mode == 0 || mode == 'radians' ? 0 : 1;
2410
+ return !angleMode ? 'radians' : 'degrees';
2406
2411
  };
2407
2412
  let DEGTORAD = ($._DEGTORAD = Math.PI / 180);
2408
2413
  let RADTODEG = ($._RADTODEG = 180 / Math.PI);
@@ -3371,7 +3376,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3371
3376
  $.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
3372
3377
 
3373
3378
  $.resetMatrix = () => {
3374
- // Initialize the transformation matrix as 4x4 identity matrix
3379
+ // initialize the transformation matrix as 4x4 identity matrix
3375
3380
 
3376
3381
  // prettier-ignore
3377
3382
  $._matrix = [
@@ -3395,7 +3400,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3395
3400
 
3396
3401
  $.translate = (x, y, z) => {
3397
3402
  if (!x && !y && !z) return;
3398
- // Update the translation values
3403
+ // update the translation values
3399
3404
  $._matrix[12] += x;
3400
3405
  $._matrix[13] -= y;
3401
3406
  $._matrix[14] += z || 0;
@@ -3494,25 +3499,25 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3494
3499
  else m = args;
3495
3500
 
3496
3501
  if (m.length == 9) {
3497
- // Convert 3x3 matrix to 4x4 matrix
3502
+ // convert 3x3 matrix to 4x4 matrix
3498
3503
  m = [m[0], m[1], 0, m[2], m[3], m[4], 0, m[5], 0, 0, 1, 0, m[6], m[7], 0, m[8]];
3499
3504
  } else if (m.length != 16) {
3500
3505
  throw new Error('Matrix must be a 3x3 or 4x4 array.');
3501
3506
  }
3502
3507
 
3503
- // Overwrite the current transformation matrix
3508
+ // overwrite the current transformation matrix
3504
3509
  $._matrix = m.slice();
3505
3510
  $._matrixDirty = true;
3506
3511
  };
3507
3512
 
3508
- // Function to save the current matrix state if dirty
3513
+ // function to save the current matrix state if dirty
3509
3514
  $._saveMatrix = () => {
3510
3515
  transformStates.push($._matrix.slice());
3511
3516
  $._transformIndex = transformStates.length - 1;
3512
3517
  $._matrixDirty = false;
3513
3518
  };
3514
3519
 
3515
- // Push the current matrix index onto the stack
3520
+ // push the current matrix index onto the stack
3516
3521
  $.pushMatrix = () => {
3517
3522
  if ($._matrixDirty) $._saveMatrix();
3518
3523
  $._transformIndexStack.push($._transformIndex);
@@ -3522,7 +3527,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3522
3527
  if (!$._transformIndexStack.length) {
3523
3528
  return console.warn('Matrix index stack is empty!');
3524
3529
  }
3525
- // Pop the last matrix index and set it as the current matrix index
3530
+ // pop the last matrix index and set it as the current matrix index
3526
3531
  let idx = $._transformIndexStack.pop();
3527
3532
  $._matrix = transformStates[idx].slice();
3528
3533
  $._transformIndex = idx;
@@ -3585,6 +3590,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3585
3590
  'max' // 4
3586
3591
  ];
3587
3592
 
3593
+ // other blend modes are not supported yet
3588
3594
  const blendModes = {
3589
3595
  normal: [2, 3, 0, 2, 3, 0],
3590
3596
  // destination_over: [6, 1, 0, 6, 1, 0],
@@ -4048,19 +4054,22 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4048
4054
  if ($._matrixDirty) $._saveMatrix();
4049
4055
  let ti = $._transformIndex,
4050
4056
  ci = $._stroke,
4051
- sw = $._strokeWeight,
4052
- hsw = sw / 2;
4057
+ sw = $._strokeWeight;
4053
4058
 
4054
4059
  if (sw < 2) {
4055
4060
  let [l, r, t, b] = $._calcBox(x, y, sw, sw, 'corner');
4056
4061
  addRect(l, t, r, t, r, b, l, b, ci, ti);
4057
4062
  } else {
4058
4063
  let n = getArcSegments(sw);
4059
- addEllipse(x, y, hsw, hsw, n, ci, ti);
4064
+ sw /= 2;
4065
+ addEllipse(x, y, sw, sw, n, ci, ti);
4060
4066
  }
4061
4067
  };
4062
4068
 
4063
- // Remove the internal transformations from the line function
4069
+ $.stokeJoin = (x) => {
4070
+ $.log("q5 WebGPU doesn't support changing stroke join style.");
4071
+ };
4072
+
4064
4073
  $.line = (x1, y1, x2, y2) => {
4065
4074
  if ($._matrixDirty) $._saveMatrix();
4066
4075
  let ti = $._transformIndex,
@@ -4068,12 +4077,12 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4068
4077
  sw = $._strokeWeight,
4069
4078
  hsw = sw / 2;
4070
4079
 
4071
- // Calculate the direction vector and length
4080
+ // calculate the direction vector and length
4072
4081
  let dx = x2 - x1,
4073
4082
  dy = y2 - y1,
4074
4083
  length = Math.hypot(dx, dy);
4075
4084
 
4076
- // Calculate the perpendicular vector for line thickness
4085
+ // calculate the perpendicular vector for line thickness
4077
4086
  let px = -(dy / length) * hsw,
4078
4087
  py = (dx / length) * hsw;
4079
4088
 
@@ -4109,10 +4118,10 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4109
4118
 
4110
4119
  $.endShape = (close) => {
4111
4120
  if (curveVertices.length > 0) {
4112
- // Duplicate start and end points if necessary
4121
+ // duplicate start and end points if necessary
4113
4122
  let points = [...curveVertices];
4114
4123
  if (points.length < 4) {
4115
- // Duplicate first and last points
4124
+ // duplicate first and last points
4116
4125
  while (points.length < 4) {
4117
4126
  points.unshift(points[0]);
4118
4127
  points.push(points[points.length - 1]);
@@ -4153,7 +4162,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4153
4162
  throw new Error('A shape must have at least 3 vertices.');
4154
4163
  }
4155
4164
 
4156
- // Close the shape if needed
4165
+ // close the shape if requested
4157
4166
  if (close) {
4158
4167
  let firstIndex = 0;
4159
4168
  let lastIndex = (shapeVertCount - 1) * 4;
@@ -4170,7 +4179,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4170
4179
  }
4171
4180
 
4172
4181
  if ($._doFill) {
4173
- // Triangulate the shape
4182
+ // triangulate the shape
4174
4183
  for (let i = 1; i < shapeVertCount - 1; i++) {
4175
4184
  let v0 = 0;
4176
4185
  let v1 = i * 4;
@@ -4184,7 +4193,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4184
4193
  }
4185
4194
 
4186
4195
  if ($._doStroke) {
4187
- // Draw lines between vertices
4196
+ // draw lines between vertices
4188
4197
  for (let i = 0; i < shapeVertCount - 1; i++) {
4189
4198
  let v1 = i * 4;
4190
4199
  let v2 = (i + 1) * 4;
@@ -4197,7 +4206,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4197
4206
  }
4198
4207
  }
4199
4208
 
4200
- // Reset for the next shape
4209
+ // reset for the next shape
4201
4210
  shapeVertCount = 0;
4202
4211
  sv = [];
4203
4212
  curveVertices = [];
@@ -4412,7 +4421,7 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
4412
4421
 
4413
4422
  tIdx = (tIdx + 1) % MAX_TEXTURES;
4414
4423
 
4415
- // If the texture array is full, destroy the oldest texture
4424
+ // if the texture array is full, destroy the oldest texture
4416
4425
  if ($._textures[tIdx]) {
4417
4426
  $._textures[tIdx].destroy();
4418
4427
  delete $._textures[tIdx];
@@ -4679,8 +4688,9 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4679
4688
  getChar(charCode) {
4680
4689
  return this.chars[charCode] ?? this.defaultChar;
4681
4690
  }
4682
- // Gets the distance in pixels a line should advance for a given character code. If the upcoming
4683
- // character code is given any kerning between the two characters will be taken into account.
4691
+ // Gets the distance in pixels a line should advance for a given
4692
+ // character code. If the upcoming character code is given any
4693
+ // kerning between the two characters will be taken into account.
4684
4694
  getXAdvance(charCode, nextCharCode = -1) {
4685
4695
  let char = this.getChar(charCode);
4686
4696
  if (nextCharCode >= 0) {
@@ -4722,8 +4732,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4722
4732
  });
4723
4733
  Q5.device.queue.copyExternalImageToTexture({ source: img }, { texture }, imgSize);
4724
4734
 
4725
- // to make q5's default font file smaller,
4726
- // the chars and kernings are stored as csv strings
4735
+ // chars and kernings can be stored as csv strings, making the file
4736
+ // size smaller, but they need to be parsed into arrays of objects
4727
4737
  if (typeof atlas.chars == 'string') {
4728
4738
  atlas.chars = $.CSV.parse(atlas.chars, ' ');
4729
4739
  atlas.kernings = $.CSV.parse(atlas.kernings, ' ');
@@ -4849,7 +4859,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4849
4859
  let charCode = nextCharCode;
4850
4860
  nextCharCode = i < text.length - 1 ? text.charCodeAt(i + 1) : -1;
4851
4861
  switch (charCode) {
4852
- case 10: // Newline
4862
+ case 10: // newline
4853
4863
  lineWidths.push(offsetX);
4854
4864
  line++;
4855
4865
  maxWidth = Math.max(maxWidth, offsetX);
@@ -4858,11 +4868,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4858
4868
  break;
4859
4869
  case 13: // CR
4860
4870
  break;
4861
- case 32: // Space
4871
+ case 32: // space
4862
4872
  // advance the offset without actually adding a character
4863
4873
  offsetX += font.getXAdvance(charCode);
4864
4874
  break;
4865
- case 9: // Tab
4875
+ case 9: // tab
4866
4876
  offsetX += font.getXAdvance(charCode) * 2;
4867
4877
  break;
4868
4878
  default:
@@ -4887,7 +4897,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4887
4897
 
4888
4898
  $.text = (str, x, y, w, h) => {
4889
4899
  if (!$._font) {
4890
- // check if online and loading the default font hasn't been attempted yet
4900
+ // check if online and loading the default font
4901
+ // hasn't been attempted yet
4891
4902
  if (navigator.onLine && !initLoadDefaultFont) {
4892
4903
  initLoadDefaultFont = true;
4893
4904
  $.loadFont('https://q5js.org/fonts/YaHei-msdf.json');
@@ -5046,27 +5057,27 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
5046
5057
  $._hooks.preRender.push(() => {
5047
5058
  if (!$._charStack.length) return;
5048
5059
 
5049
- // Calculate total buffer size for text data
5060
+ // calculate total buffer size for text data
5050
5061
  let totalTextSize = 0;
5051
5062
  for (let charsData of $._charStack) {
5052
5063
  totalTextSize += charsData.length * 4;
5053
5064
  }
5054
5065
 
5055
- // Create a single buffer for all char data
5066
+ // create a single buffer for all the char data
5056
5067
  let charBuffer = Q5.device.createBuffer({
5057
5068
  size: totalTextSize,
5058
5069
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
5059
5070
  mappedAtCreation: true
5060
5071
  });
5061
5072
 
5062
- // Copy all text data into the buffer
5073
+ // copy all the text data into the buffer
5063
5074
  new Float32Array(charBuffer.getMappedRange()).set($._charStack.flat());
5064
5075
  charBuffer.unmap();
5065
5076
 
5066
- // Calculate total buffer size for metadata
5077
+ // calculate total buffer size for metadata
5067
5078
  let totalMetadataSize = $._textStack.length * 6 * 4;
5068
5079
 
5069
- // Create a single buffer for all metadata
5080
+ // create a single buffer for all metadata
5070
5081
  let textBuffer = Q5.device.createBuffer({
5071
5082
  label: 'textBuffer',
5072
5083
  size: totalMetadataSize,
@@ -5074,11 +5085,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
5074
5085
  mappedAtCreation: true
5075
5086
  });
5076
5087
 
5077
- // Copy all metadata into the buffer
5088
+ // copy all metadata into the buffer
5078
5089
  new Float32Array(textBuffer.getMappedRange()).set($._textStack.flat());
5079
5090
  textBuffer.unmap();
5080
5091
 
5081
- // Create a single bind group for the text buffer and metadata buffer
5092
+ // create a single bind group for the text buffer and metadata buffer
5082
5093
  $._textBindGroup = Q5.device.createBindGroup({
5083
5094
  label: 'msdf text bind group',
5084
5095
  layout: textBindGroupLayout,