q5 2.9.21 → 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 (77) 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 +158 -54
  62. package/q5.min.js +1 -1
  63. package/src/q5-2d-canvas.js +8 -2
  64. package/src/q5-2d-drawing.js +20 -7
  65. package/src/q5-2d-image.js +4 -1
  66. package/src/q5-2d-text.js +7 -0
  67. package/src/q5-canvas.js +6 -5
  68. package/src/q5-color.js +5 -0
  69. package/src/q5-core.js +3 -1
  70. package/src/q5-input.js +12 -0
  71. package/src/q5-math.js +11 -3
  72. package/src/q5-record.js +2 -0
  73. package/src/q5-vector.js +33 -0
  74. package/src/q5-webgpu-canvas.js +11 -7
  75. package/src/q5-webgpu-drawing.js +15 -12
  76. package/src/q5-webgpu-image.js +1 -1
  77. package/src/q5-webgpu-text.js +22 -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');
@@ -462,7 +464,7 @@ Q5.modules.canvas = ($, q) => {
462
464
  return g;
463
465
  };
464
466
 
465
- $._save = async (data, name, ext) => {
467
+ async function saveFile(data, name, ext) {
466
468
  name = name || 'untitled';
467
469
  ext = ext || 'png';
468
470
  if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
@@ -490,18 +492,19 @@ Q5.modules.canvas = ($, q) => {
490
492
  a.download = name + '.' + ext;
491
493
  a.click();
492
494
  URL.revokeObjectURL(a.href);
493
- };
495
+ }
496
+
494
497
  $.save = (a, b, c) => {
495
498
  if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
496
499
  c = b;
497
500
  b = a;
498
501
  a = $.canvas;
499
502
  }
500
- if (c) return $._save(a, b, c);
503
+ if (c) return saveFile(a, b, c);
501
504
  if (b) {
502
505
  b = b.split('.');
503
- $._save(a, b[0], b.at(-1));
504
- } else $._save(a);
506
+ saveFile(a, b[0], b.at(-1));
507
+ } else saveFile(a);
505
508
  };
506
509
 
507
510
  $._setCanvasSize = (w, h) => {
@@ -716,7 +719,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
716
719
  }
717
720
  $.ctx.fillStyle = $._fill = c.toString();
718
721
  };
719
- $.noFill = () => ($._doFill = false);
722
+
720
723
  $.stroke = function (c) {
721
724
  $._doStroke = $._strokeSet = true;
722
725
  if (Q5.Color) {
@@ -728,13 +731,15 @@ Q5.renderers.q2d.canvas = ($, q) => {
728
731
  }
729
732
  $.ctx.strokeStyle = $._stroke = c.toString();
730
733
  };
734
+
731
735
  $.strokeWeight = (n) => {
732
736
  if (!n) $._doStroke = false;
733
737
  if ($._da) n *= $._da;
734
738
  $.ctx.lineWidth = $._strokeWeight = n || 0.0001;
735
739
  };
736
- $.noStroke = () => ($._doStroke = false);
737
740
 
741
+ $.noFill = () => ($._doFill = false);
742
+ $.noStroke = () => ($._doStroke = false);
738
743
  $.opacity = (a) => ($.ctx.globalAlpha = a);
739
744
 
740
745
  // DRAWING MATRIX
@@ -746,10 +751,12 @@ Q5.renderers.q2d.canvas = ($, q) => {
746
751
  }
747
752
  $.ctx.translate(x, y);
748
753
  };
754
+
749
755
  $.rotate = (r) => {
750
756
  if ($._angleMode) r = $.radians(r);
751
757
  $.ctx.rotate(r);
752
758
  };
759
+
753
760
  $.scale = (x, y) => {
754
761
  if (x.x) {
755
762
  y = x.y;
@@ -758,9 +765,11 @@ Q5.renderers.q2d.canvas = ($, q) => {
758
765
  y ??= x;
759
766
  $.ctx.scale(x, y);
760
767
  };
768
+
761
769
  $.applyMatrix = (a, b, c, d, e, f) => $.ctx.transform(a, b, c, d, e, f);
762
770
  $.shearX = (ang) => $.ctx.transform(1, 0, $.tan(ang), 1, 0, 0);
763
771
  $.shearY = (ang) => $.ctx.transform(1, $.tan(ang), 0, 1, 0, 0);
772
+
764
773
  $.resetMatrix = () => {
765
774
  if ($.ctx) {
766
775
  $.ctx.resetTransform();
@@ -852,12 +861,7 @@ Q5.renderers.q2d.drawing = ($) => {
852
861
 
853
862
  $.line = (x0, y0, x1, y1) => {
854
863
  if ($._doStroke) {
855
- if ($._da) {
856
- x0 *= $._da;
857
- y0 *= $._da;
858
- x1 *= $._da;
859
- y1 *= $._da;
860
- }
864
+ $._da && ((x0 *= $._da), (y0 *= $._da), (x1 *= $._da), (y1 *= $._da));
861
865
  $.ctx.beginPath();
862
866
  $.ctx.moveTo(x0, y0);
863
867
  $.ctx.lineTo(x1, y1);
@@ -897,6 +901,7 @@ Q5.renderers.q2d.drawing = ($) => {
897
901
  $.ctx.stroke();
898
902
  }
899
903
  }
904
+
900
905
  $.arc = (x, y, w, h, start, stop, mode) => {
901
906
  if (start == stop) return $.ellipse(x, y, w, h);
902
907
 
@@ -906,7 +911,6 @@ Q5.renderers.q2d.drawing = ($) => {
906
911
  w *= $._da;
907
912
  h *= $._da;
908
913
  }
909
-
910
914
  mode ??= $.PIE_OPEN;
911
915
 
912
916
  if ($._ellipseMode == $.CENTER) {
@@ -925,6 +929,7 @@ Q5.renderers.q2d.drawing = ($) => {
925
929
  $.ctx.ellipse(x, y, w / 2, h / 2, 0, 0, $.TAU);
926
930
  ink();
927
931
  }
932
+
928
933
  $.ellipse = (x, y, w, h) => {
929
934
  h ??= w;
930
935
  if ($._da) {
@@ -943,6 +948,7 @@ Q5.renderers.q2d.drawing = ($) => {
943
948
  ellipse((x + w) / 2, (y + h) / 2, w - x, h - y);
944
949
  }
945
950
  };
951
+
946
952
  $.circle = (x, y, d) => {
947
953
  if ($._ellipseMode == $.CENTER) {
948
954
  if ($._da) {
@@ -984,6 +990,7 @@ Q5.renderers.q2d.drawing = ($) => {
984
990
  $.ctx.rect(x, y, w, h);
985
991
  ink();
986
992
  }
993
+
987
994
  function roundedRect(x, y, w, h, tl, tr, br, bl) {
988
995
  if (tl === undefined) {
989
996
  return rect(x, y, w, h);
@@ -1016,6 +1023,7 @@ Q5.renderers.q2d.drawing = ($) => {
1016
1023
  roundedRect(x, y, w - x, h - y, tl, tr, br, bl);
1017
1024
  }
1018
1025
  };
1026
+
1019
1027
  $.square = (x, y, s, tl, tr, br, bl) => {
1020
1028
  return $.rect(x, y, s, s, tl, tr, br, bl);
1021
1029
  };
@@ -1025,15 +1033,18 @@ Q5.renderers.q2d.drawing = ($) => {
1025
1033
  $.ctx.beginPath();
1026
1034
  firstVertex = true;
1027
1035
  };
1036
+
1028
1037
  $.beginContour = () => {
1029
1038
  $.ctx.closePath();
1030
1039
  curveBuff.length = 0;
1031
1040
  firstVertex = true;
1032
1041
  };
1042
+
1033
1043
  $.endContour = () => {
1034
1044
  curveBuff.length = 0;
1035
1045
  firstVertex = true;
1036
1046
  };
1047
+
1037
1048
  $.vertex = (x, y) => {
1038
1049
  if ($._da) {
1039
1050
  x *= $._da;
@@ -1047,6 +1058,7 @@ Q5.renderers.q2d.drawing = ($) => {
1047
1058
  }
1048
1059
  firstVertex = false;
1049
1060
  };
1061
+
1050
1062
  $.bezierVertex = (cp1x, cp1y, cp2x, cp2y, x, y) => {
1051
1063
  if ($._da) {
1052
1064
  cp1x *= $._da;
@@ -1059,6 +1071,7 @@ Q5.renderers.q2d.drawing = ($) => {
1059
1071
  curveBuff.length = 0;
1060
1072
  $.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1061
1073
  };
1074
+
1062
1075
  $.quadraticVertex = (cp1x, cp1y, x, y) => {
1063
1076
  if ($._da) {
1064
1077
  cp1x *= $._da;
@@ -1069,12 +1082,14 @@ Q5.renderers.q2d.drawing = ($) => {
1069
1082
  curveBuff.length = 0;
1070
1083
  $.ctx.quadraticCurveTo(cp1x, cp1y, x, y);
1071
1084
  };
1085
+
1072
1086
  $.bezier = (x1, y1, x2, y2, x3, y3, x4, y4) => {
1073
1087
  $.beginShape();
1074
1088
  $.vertex(x1, y1);
1075
1089
  $.bezierVertex(x2, y2, x3, y3, x4, y4);
1076
1090
  $.endShape();
1077
1091
  };
1092
+
1078
1093
  $.triangle = (x1, y1, x2, y2, x3, y3) => {
1079
1094
  $.beginShape();
1080
1095
  $.vertex(x1, y1);
@@ -1082,6 +1097,7 @@ Q5.renderers.q2d.drawing = ($) => {
1082
1097
  $.vertex(x3, y3);
1083
1098
  $.endShape($.CLOSE);
1084
1099
  };
1100
+
1085
1101
  $.quad = (x1, y1, x2, y2, x3, y3, x4, y4) => {
1086
1102
  $.beginShape();
1087
1103
  $.vertex(x1, y1);
@@ -1090,6 +1106,7 @@ Q5.renderers.q2d.drawing = ($) => {
1090
1106
  $.vertex(x4, y4);
1091
1107
  $.endShape($.CLOSE);
1092
1108
  };
1109
+
1093
1110
  $.endShape = (close) => {
1094
1111
  curveBuff.length = 0;
1095
1112
  if (close) $.ctx.closePath();
@@ -1120,6 +1137,7 @@ Q5.renderers.q2d.drawing = ($) => {
1120
1137
  }
1121
1138
  $.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2[0], p2[1]);
1122
1139
  };
1140
+
1123
1141
  $.curve = (x1, y1, x2, y2, x3, y3, x4, y4) => {
1124
1142
  $.beginShape();
1125
1143
  $.curveVertex(x1, y1);
@@ -1128,6 +1146,7 @@ Q5.renderers.q2d.drawing = ($) => {
1128
1146
  $.curveVertex(x4, y4);
1129
1147
  $.endShape();
1130
1148
  };
1149
+
1131
1150
  $.curvePoint = (a, b, c, d, t) => {
1132
1151
  const t3 = t * t * t,
1133
1152
  t2 = t * t,
@@ -1137,6 +1156,7 @@ Q5.renderers.q2d.drawing = ($) => {
1137
1156
  f4 = 0.5 * t3 - 0.5 * t2;
1138
1157
  return a * f1 + b * f2 + c * f3 + d * f4;
1139
1158
  };
1159
+
1140
1160
  $.bezierPoint = (a, b, c, d, t) => {
1141
1161
  const adjustedT = 1 - t;
1142
1162
  return (
@@ -1146,6 +1166,7 @@ Q5.renderers.q2d.drawing = ($) => {
1146
1166
  Math.pow(t, 3) * d
1147
1167
  );
1148
1168
  };
1169
+
1149
1170
  $.curveTangent = (a, b, c, d, t) => {
1150
1171
  const t2 = t * t,
1151
1172
  f1 = (-3 * t2) / 2 + 2 * t - 0.5,
@@ -1154,6 +1175,7 @@ Q5.renderers.q2d.drawing = ($) => {
1154
1175
  f4 = (3 * t2) / 2 - t;
1155
1176
  return a * f1 + b * f2 + c * f3 + d * f4;
1156
1177
  };
1178
+
1157
1179
  $.bezierTangent = (a, b, c, d, t) => {
1158
1180
  const adjustedT = 1 - t;
1159
1181
  return (
@@ -1228,7 +1250,9 @@ Q5.renderers.q2d.image = ($, q) => {
1228
1250
  $.loadImage = function (url, cb, opt) {
1229
1251
  if (url.canvas) return url;
1230
1252
  if (url.slice(-3).toLowerCase() == 'gif') {
1231
- 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
+ );
1232
1256
  }
1233
1257
  q._preloadCount++;
1234
1258
  let last = [...arguments].at(-1);
@@ -1271,6 +1295,7 @@ Q5.renderers.q2d.image = ($, q) => {
1271
1295
  };
1272
1296
 
1273
1297
  $.imageMode = (mode) => ($._imageMode = mode);
1298
+
1274
1299
  $.image = (img, dx, dy, dw, dh, sx = 0, sy = 0, sw, sh) => {
1275
1300
  if (!img) return;
1276
1301
  let drawable = img?.canvas || img;
@@ -1512,6 +1537,7 @@ Q5.renderers.q2d.text = ($, q) => {
1512
1537
  fontMod = true;
1513
1538
  styleHash = -1;
1514
1539
  };
1540
+
1515
1541
  $.textSize = (x) => {
1516
1542
  if (x == undefined || x == $._textSize) return $._textSize;
1517
1543
  if ($._da) x *= $._da;
@@ -1523,12 +1549,14 @@ Q5.renderers.q2d.text = ($, q) => {
1523
1549
  leadDiff = leading - x;
1524
1550
  }
1525
1551
  };
1552
+
1526
1553
  $.textStyle = (x) => {
1527
1554
  if (!x || x == emphasis) return emphasis;
1528
1555
  emphasis = x;
1529
1556
  fontMod = true;
1530
1557
  styleHash = -1;
1531
1558
  };
1559
+
1532
1560
  $.textLeading = (x) => {
1533
1561
  leadingSet = true;
1534
1562
  if (x == undefined || x == leading) return leading;
@@ -1537,6 +1565,7 @@ Q5.renderers.q2d.text = ($, q) => {
1537
1565
  leadDiff = x - $._textSize;
1538
1566
  styleHash = -1;
1539
1567
  };
1568
+
1540
1569
  $.textAlign = (horiz, vert) => {
1541
1570
  $.ctx.textAlign = $._textAlign = horiz;
1542
1571
  if (vert) {
@@ -1566,6 +1595,7 @@ Q5.renderers.q2d.text = ($, q) => {
1566
1595
  if (enable !== undefined) useCache = enable;
1567
1596
  return useCache;
1568
1597
  };
1598
+
1569
1599
  $.createTextImage = (str, w, h) => {
1570
1600
  genTextImage = true;
1571
1601
  img = $.text(str, 0, 0, w, h);
@@ -1574,6 +1604,7 @@ Q5.renderers.q2d.text = ($, q) => {
1574
1604
  };
1575
1605
 
1576
1606
  let lines = [];
1607
+
1577
1608
  $.text = (str, x, y, w, h) => {
1578
1609
  if (str === undefined || (!$._doFill && !$._doStroke)) return;
1579
1610
  str = str.toString();
@@ -1699,6 +1730,7 @@ Q5.renderers.q2d.text = ($, q) => {
1699
1730
  $.textImage(img, x, y);
1700
1731
  }
1701
1732
  };
1733
+
1702
1734
  $.textImage = (img, x, y) => {
1703
1735
  if (typeof img == 'string') img = $.createTextImage(img);
1704
1736
 
@@ -1942,6 +1974,7 @@ Q5.Color = class {
1942
1974
  this._q5Color = true;
1943
1975
  }
1944
1976
  };
1977
+
1945
1978
  Q5.ColorOKLCH = class extends Q5.Color {
1946
1979
  constructor(l, c, h, a) {
1947
1980
  super();
@@ -1954,6 +1987,7 @@ Q5.ColorOKLCH = class extends Q5.Color {
1954
1987
  return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
1955
1988
  }
1956
1989
  };
1990
+
1957
1991
  Q5.ColorRGBA = class extends Q5.Color {
1958
1992
  constructor(r, g, b, a) {
1959
1993
  super();
@@ -1969,11 +2003,13 @@ Q5.ColorRGBA = class extends Q5.Color {
1969
2003
  return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
1970
2004
  }
1971
2005
  };
2006
+
1972
2007
  Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
1973
2008
  toString() {
1974
2009
  return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
1975
2010
  }
1976
2011
  };
2012
+
1977
2013
  // legacy 8-bit (0-255) integer color format
1978
2014
  Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
1979
2015
  constructor(r, g, b, a) {
@@ -1998,6 +2034,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
1998
2034
  return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
1999
2035
  }
2000
2036
  };
2037
+
2001
2038
  // p3 10-bit color in integer color format, for backwards compatibility
2002
2039
  Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
2003
2040
  constructor(r, g, b, a) {
@@ -2206,6 +2243,7 @@ Q5.modules.input = ($, q) => {
2206
2243
  q.moveX = e.movementX;
2207
2244
  q.moveY = e.movementY;
2208
2245
  };
2246
+
2209
2247
  $._onmousedown = (e) => {
2210
2248
  $._startAudio();
2211
2249
  $._updateMouse(e);
@@ -2213,22 +2251,26 @@ Q5.modules.input = ($, q) => {
2213
2251
  q.mouseButton = mouseBtns[e.button];
2214
2252
  $.mousePressed(e);
2215
2253
  };
2254
+
2216
2255
  $._onmousemove = (e) => {
2217
2256
  $._updateMouse(e);
2218
2257
  if ($.mouseIsPressed) $.mouseDragged(e);
2219
2258
  else $.mouseMoved(e);
2220
2259
  };
2260
+
2221
2261
  $._onmouseup = (e) => {
2222
2262
  $._updateMouse(e);
2223
2263
  q.mouseIsPressed = false;
2224
2264
  $.mouseReleased(e);
2225
2265
  };
2266
+
2226
2267
  $._onclick = (e) => {
2227
2268
  $._updateMouse(e);
2228
2269
  q.mouseIsPressed = true;
2229
2270
  $.mouseClicked(e);
2230
2271
  q.mouseIsPressed = false;
2231
2272
  };
2273
+
2232
2274
  $._onwheel = (e) => {
2233
2275
  $._updateMouse(e);
2234
2276
  e.delta = e.deltaY;
@@ -2246,9 +2288,11 @@ Q5.modules.input = ($, q) => {
2246
2288
  }
2247
2289
  $.canvas.style.cursor = name + pfx;
2248
2290
  };
2291
+
2249
2292
  $.noCursor = () => {
2250
2293
  $.canvas.style.cursor = 'none';
2251
2294
  };
2295
+
2252
2296
  if (window) {
2253
2297
  $.requestPointerLock = document.body?.requestPointerLock;
2254
2298
  $.exitPointerLock = document.exitPointerLock;
@@ -2264,6 +2308,7 @@ Q5.modules.input = ($, q) => {
2264
2308
  $.keyPressed(e);
2265
2309
  if (e.key.length == 1) $.keyTyped(e);
2266
2310
  };
2311
+
2267
2312
  $._onkeyup = (e) => {
2268
2313
  q.keyIsPressed = false;
2269
2314
  q.key = e.key;
@@ -2271,6 +2316,7 @@ Q5.modules.input = ($, q) => {
2271
2316
  keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
2272
2317
  $.keyReleased(e);
2273
2318
  };
2319
+
2274
2320
  $.keyIsDown = (v) => !!keysHeld[typeof v == 'string' ? v.toLowerCase() : v];
2275
2321
 
2276
2322
  function getTouchInfo(touch) {
@@ -2283,6 +2329,7 @@ Q5.modules.input = ($, q) => {
2283
2329
  id: touch.identifier
2284
2330
  };
2285
2331
  }
2332
+
2286
2333
  $._ontouchstart = (e) => {
2287
2334
  $._startAudio();
2288
2335
  q.touches = [...e.touches].map(getTouchInfo);
@@ -2295,6 +2342,7 @@ Q5.modules.input = ($, q) => {
2295
2342
  }
2296
2343
  if (!$.touchStarted(e)) e.preventDefault();
2297
2344
  };
2345
+
2298
2346
  $._ontouchmove = (e) => {
2299
2347
  q.touches = [...e.touches].map(getTouchInfo);
2300
2348
  if (!$._isTouchAware) {
@@ -2304,6 +2352,7 @@ Q5.modules.input = ($, q) => {
2304
2352
  }
2305
2353
  if (!$.touchMoved(e)) e.preventDefault();
2306
2354
  };
2355
+
2307
2356
  $._ontouchend = (e) => {
2308
2357
  q.touches = [...e.touches].map(getTouchInfo);
2309
2358
  if (!$._isTouchAware && !$.touches.length) {
@@ -2358,6 +2407,7 @@ Q5.modules.math = ($, q) => {
2358
2407
 
2359
2408
  $.angleMode = (mode) => {
2360
2409
  angleMode = $._angleMode = mode == 0 || mode == 'radians' ? 0 : 1;
2410
+ return !angleMode ? 'radians' : 'degrees';
2361
2411
  };
2362
2412
  let DEGTORAD = ($._DEGTORAD = Math.PI / 180);
2363
2413
  let RADTODEG = ($._RADTODEG = 180 / Math.PI);
@@ -2375,13 +2425,15 @@ Q5.modules.math = ($, q) => {
2375
2425
  return Math.min(Math.max(val, ostop), ostart);
2376
2426
  }
2377
2427
  };
2378
- $.lerp = (a, b, t) => a * (1 - t) + b * t;
2379
- $.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
2428
+
2380
2429
  $.dist = function () {
2381
2430
  let a = arguments;
2382
2431
  if (a.length == 4) return Math.hypot(a[0] - a[2], a[1] - a[3]);
2383
2432
  else return Math.hypot(a[0] - a[3], a[1] - a[4], a[2] - a[5]);
2384
2433
  };
2434
+
2435
+ $.lerp = (a, b, t) => a * (1 - t) + b * t;
2436
+ $.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
2385
2437
  $.norm = (value, start, stop) => $.map(value, start, stop, 0, 1);
2386
2438
  $.sq = (x) => x * x;
2387
2439
  $.fract = (x) => x - Math.floor(x);
@@ -2402,7 +2454,6 @@ Q5.modules.math = ($, q) => {
2402
2454
  let a = Math.atan(x);
2403
2455
  return !angleMode ? a : a * RADTODEG;
2404
2456
  };
2405
-
2406
2457
  $.atan2 = (y, x) => {
2407
2458
  let a = Math.atan2(y, x);
2408
2459
  return !angleMode ? a : a * RADTODEG;
@@ -2426,6 +2477,7 @@ Q5.modules.math = ($, q) => {
2426
2477
  }
2427
2478
  };
2428
2479
  }
2480
+
2429
2481
  function shr3() {
2430
2482
  let jsr, seed;
2431
2483
  let m = 4294967295;
@@ -2444,6 +2496,7 @@ Q5.modules.math = ($, q) => {
2444
2496
  }
2445
2497
  };
2446
2498
  }
2499
+
2447
2500
  let rng1 = shr3();
2448
2501
  rng1.setSeed();
2449
2502
 
@@ -2460,6 +2513,7 @@ Q5.modules.math = ($, q) => {
2460
2513
  return a[Math.trunc(a.length * rng1.rand())];
2461
2514
  }
2462
2515
  };
2516
+
2463
2517
  $.randomGenerator = (method) => {
2464
2518
  if (method == $.LCG) rng1 = lcg();
2465
2519
  else if (method == $.SHR3) rng1 = shr3();
@@ -2615,13 +2669,16 @@ Q5.modules.math = ($, q) => {
2615
2669
  q.Noise = Q5[mode[0].toUpperCase() + mode.slice(1) + 'Noise'];
2616
2670
  _noise = null;
2617
2671
  };
2672
+
2618
2673
  $.noiseSeed = (seed) => {
2619
2674
  _noise = new $.Noise(seed);
2620
2675
  };
2676
+
2621
2677
  $.noise = (x = 0, y = 0, z = 0) => {
2622
2678
  _noise ??= new $.Noise();
2623
2679
  return _noise.noise(x, y, z);
2624
2680
  };
2681
+
2625
2682
  $.noiseDetail = (lod, falloff) => {
2626
2683
  _noise ??= new $.Noise();
2627
2684
  if (lod > 0) _noise.octaves = lod;
@@ -2857,15 +2914,18 @@ Q5.Vector = class {
2857
2914
  this._cn = null;
2858
2915
  this._cnsq = null;
2859
2916
  }
2917
+
2860
2918
  set(x, y, z) {
2861
2919
  this.x = x?.x || x || 0;
2862
2920
  this.y = x?.y || y || 0;
2863
2921
  this.z = x?.z || z || 0;
2864
2922
  return this;
2865
2923
  }
2924
+
2866
2925
  copy() {
2867
2926
  return new Q5.Vector(this.x, this.y, this.z);
2868
2927
  }
2928
+
2869
2929
  _arg2v(x, y, z) {
2870
2930
  if (x?.x !== undefined) return x;
2871
2931
  if (y !== undefined) {
@@ -2873,10 +2933,12 @@ Q5.Vector = class {
2873
2933
  }
2874
2934
  return { x: x, y: x, z: x };
2875
2935
  }
2936
+
2876
2937
  _calcNorm() {
2877
2938
  this._cnsq = this.x * this.x + this.y * this.y + this.z * this.z;
2878
2939
  this._cn = Math.sqrt(this._cnsq);
2879
2940
  }
2941
+
2880
2942
  add() {
2881
2943
  let u = this._arg2v(...arguments);
2882
2944
  this.x += u.x;
@@ -2884,6 +2946,7 @@ Q5.Vector = class {
2884
2946
  this.z += u.z;
2885
2947
  return this;
2886
2948
  }
2949
+
2887
2950
  rem() {
2888
2951
  let u = this._arg2v(...arguments);
2889
2952
  this.x %= u.x;
@@ -2891,6 +2954,7 @@ Q5.Vector = class {
2891
2954
  this.z %= u.z;
2892
2955
  return this;
2893
2956
  }
2957
+
2894
2958
  sub() {
2895
2959
  let u = this._arg2v(...arguments);
2896
2960
  this.x -= u.x;
@@ -2898,6 +2962,7 @@ Q5.Vector = class {
2898
2962
  this.z -= u.z;
2899
2963
  return this;
2900
2964
  }
2965
+
2901
2966
  mult() {
2902
2967
  let u = this._arg2v(...arguments);
2903
2968
  this.x *= u.x;
@@ -2905,6 +2970,7 @@ Q5.Vector = class {
2905
2970
  this.z *= u.z;
2906
2971
  return this;
2907
2972
  }
2973
+
2908
2974
  div() {
2909
2975
  let u = this._arg2v(...arguments);
2910
2976
  if (u.x) this.x /= u.x;
@@ -2915,18 +2981,22 @@ Q5.Vector = class {
2915
2981
  else this.z = 0;
2916
2982
  return this;
2917
2983
  }
2984
+
2918
2985
  mag() {
2919
2986
  this._calcNorm();
2920
2987
  return this._cn;
2921
2988
  }
2989
+
2922
2990
  magSq() {
2923
2991
  this._calcNorm();
2924
2992
  return this._cnsq;
2925
2993
  }
2994
+
2926
2995
  dot() {
2927
2996
  let u = this._arg2v(...arguments);
2928
2997
  return this.x * u.x + this.y * u.y + this.z * u.z;
2929
2998
  }
2999
+
2930
3000
  dist() {
2931
3001
  let u = this._arg2v(...arguments);
2932
3002
  let x = this.x - u.x;
@@ -2934,6 +3004,7 @@ Q5.Vector = class {
2934
3004
  let z = this.z - u.z;
2935
3005
  return Math.sqrt(x * x + y * y + z * z);
2936
3006
  }
3007
+
2937
3008
  cross() {
2938
3009
  let u = this._arg2v(...arguments);
2939
3010
  let x = this.y * u.z - this.z * u.y;
@@ -2944,6 +3015,7 @@ Q5.Vector = class {
2944
3015
  this.z = z;
2945
3016
  return this;
2946
3017
  }
3018
+
2947
3019
  normalize() {
2948
3020
  this._calcNorm();
2949
3021
  let n = this._cn;
@@ -2956,6 +3028,7 @@ Q5.Vector = class {
2956
3028
  this._cnsq = 1;
2957
3029
  return this;
2958
3030
  }
3031
+
2959
3032
  limit(m) {
2960
3033
  this._calcNorm();
2961
3034
  let n = this._cn;
@@ -2969,6 +3042,7 @@ Q5.Vector = class {
2969
3042
  }
2970
3043
  return this;
2971
3044
  }
3045
+
2972
3046
  setMag(m) {
2973
3047
  this._calcNorm();
2974
3048
  let n = this._cn;
@@ -2980,15 +3054,18 @@ Q5.Vector = class {
2980
3054
  this._cnsq = m * m;
2981
3055
  return this;
2982
3056
  }
3057
+
2983
3058
  heading() {
2984
3059
  return this._$.atan2(this.y, this.x);
2985
3060
  }
3061
+
2986
3062
  setHeading(ang) {
2987
3063
  let mag = this.mag();
2988
3064
  this.x = mag * this._$.cos(ang);
2989
3065
  this.y = mag * this._$.sin(ang);
2990
3066
  return this;
2991
3067
  }
3068
+
2992
3069
  rotate(ang) {
2993
3070
  let costh = this._$.cos(ang);
2994
3071
  let sinth = this._$.sin(ang);
@@ -2998,12 +3075,14 @@ Q5.Vector = class {
2998
3075
  this.y = vy;
2999
3076
  return this;
3000
3077
  }
3078
+
3001
3079
  angleBetween() {
3002
3080
  let u = this._arg2v(...arguments);
3003
3081
  let o = Q5.Vector.cross(this, u);
3004
3082
  let ang = this._$.atan2(o.mag(), this.dot(u));
3005
3083
  return ang * Math.sign(o.z || 1);
3006
3084
  }
3085
+
3007
3086
  lerp() {
3008
3087
  let args = [...arguments];
3009
3088
  let amt = args.at(-1);
@@ -3014,6 +3093,7 @@ Q5.Vector = class {
3014
3093
  this.z += (u.z - this.z) * amt;
3015
3094
  return this;
3016
3095
  }
3096
+
3017
3097
  slerp() {
3018
3098
  let args = [...arguments];
3019
3099
  let amt = args.at(-1);
@@ -3052,17 +3132,21 @@ Q5.Vector = class {
3052
3132
  this.z = this.z * cosMultiplier + ey.z * sinMultiplier;
3053
3133
  return this;
3054
3134
  }
3135
+
3055
3136
  reflect(n) {
3056
3137
  n.normalize();
3057
3138
  return this.sub(n.mult(2 * this.dot(n)));
3058
3139
  }
3140
+
3059
3141
  array() {
3060
3142
  return [this.x, this.y, this.z];
3061
3143
  }
3144
+
3062
3145
  equals(u, epsilon) {
3063
3146
  epsilon ??= Number.EPSILON || 0;
3064
3147
  return Math.abs(u.x - this.x) < epsilon && Math.abs(u.y - this.y) < epsilon && Math.abs(u.z - this.z) < epsilon;
3065
3148
  }
3149
+
3066
3150
  fromAngle(th, l) {
3067
3151
  if (l === undefined) l = 1;
3068
3152
  this._cn = l;
@@ -3072,6 +3156,7 @@ Q5.Vector = class {
3072
3156
  this.z = 0;
3073
3157
  return this;
3074
3158
  }
3159
+
3075
3160
  fromAngles(th, ph, l) {
3076
3161
  if (l === undefined) l = 1;
3077
3162
  this._cn = l;
@@ -3085,18 +3170,22 @@ Q5.Vector = class {
3085
3170
  this.z = l * sinth * cosph;
3086
3171
  return this;
3087
3172
  }
3173
+
3088
3174
  random2D() {
3089
3175
  this._cn = this._cnsq = 1;
3090
3176
  return this.fromAngle(Math.random() * Math.PI * 2);
3091
3177
  }
3178
+
3092
3179
  random3D() {
3093
3180
  this._cn = this._cnsq = 1;
3094
3181
  return this.fromAngles(Math.random() * Math.PI * 2, Math.random() * Math.PI * 2);
3095
3182
  }
3183
+
3096
3184
  toString() {
3097
3185
  return `[${this.x}, ${this.y}, ${this.z}]`;
3098
3186
  }
3099
3187
  };
3188
+
3100
3189
  Q5.Vector.add = (v, u) => v.copy().add(u);
3101
3190
  Q5.Vector.cross = (v, u) => v.copy().cross(u);
3102
3191
  Q5.Vector.dist = (v, u) => Math.hypot(v.x - u.x, v.y - u.y, v.z - u.z);
@@ -3113,6 +3202,7 @@ Q5.Vector.mult = (v, u) => v.copy().mult(u);
3113
3202
  Q5.Vector.normalize = (v) => v.copy().normalize();
3114
3203
  Q5.Vector.rem = (v, u) => v.copy().rem(u);
3115
3204
  Q5.Vector.sub = (v, u) => v.copy().sub(u);
3205
+
3116
3206
  for (let k of ['fromAngle', 'fromAngles', 'random2D', 'random3D']) {
3117
3207
  Q5.Vector[k] = (u, v, t) => new Q5.Vector()[k](u, v, t);
3118
3208
  }
@@ -3286,7 +3376,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3286
3376
  $.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
3287
3377
 
3288
3378
  $.resetMatrix = () => {
3289
- // Initialize the transformation matrix as 4x4 identity matrix
3379
+ // initialize the transformation matrix as 4x4 identity matrix
3290
3380
 
3291
3381
  // prettier-ignore
3292
3382
  $._matrix = [
@@ -3310,7 +3400,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3310
3400
 
3311
3401
  $.translate = (x, y, z) => {
3312
3402
  if (!x && !y && !z) return;
3313
- // Update the translation values
3403
+ // update the translation values
3314
3404
  $._matrix[12] += x;
3315
3405
  $._matrix[13] -= y;
3316
3406
  $._matrix[14] += z || 0;
@@ -3409,34 +3499,35 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3409
3499
  else m = args;
3410
3500
 
3411
3501
  if (m.length == 9) {
3412
- // Convert 3x3 matrix to 4x4 matrix
3502
+ // convert 3x3 matrix to 4x4 matrix
3413
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]];
3414
3504
  } else if (m.length != 16) {
3415
3505
  throw new Error('Matrix must be a 3x3 or 4x4 array.');
3416
3506
  }
3417
3507
 
3418
- // Overwrite the current transformation matrix
3508
+ // overwrite the current transformation matrix
3419
3509
  $._matrix = m.slice();
3420
3510
  $._matrixDirty = true;
3421
3511
  };
3422
3512
 
3423
- // Function to save the current matrix state if dirty
3513
+ // function to save the current matrix state if dirty
3424
3514
  $._saveMatrix = () => {
3425
3515
  transformStates.push($._matrix.slice());
3426
3516
  $._transformIndex = transformStates.length - 1;
3427
3517
  $._matrixDirty = false;
3428
3518
  };
3429
3519
 
3430
- // Push the current matrix index onto the stack
3520
+ // push the current matrix index onto the stack
3431
3521
  $.pushMatrix = () => {
3432
3522
  if ($._matrixDirty) $._saveMatrix();
3433
3523
  $._transformIndexStack.push($._transformIndex);
3434
3524
  };
3525
+
3435
3526
  $.popMatrix = () => {
3436
3527
  if (!$._transformIndexStack.length) {
3437
3528
  return console.warn('Matrix index stack is empty!');
3438
3529
  }
3439
- // 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
3440
3531
  let idx = $._transformIndexStack.pop();
3441
3532
  $._matrix = transformStates[idx].slice();
3442
3533
  $._transformIndex = idx;
@@ -3447,6 +3538,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3447
3538
  $.pushMatrix();
3448
3539
  $.pushStyles();
3449
3540
  };
3541
+
3450
3542
  $.pop = () => {
3451
3543
  $.popMatrix();
3452
3544
  $.popStyles();
@@ -3498,6 +3590,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3498
3590
  'max' // 4
3499
3591
  ];
3500
3592
 
3593
+ // other blend modes are not supported yet
3501
3594
  const blendModes = {
3502
3595
  normal: [2, 3, 0, 2, 3, 0],
3503
3596
  // destination_over: [6, 1, 0, 6, 1, 0],
@@ -3528,6 +3621,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3528
3621
  }
3529
3622
 
3530
3623
  $._blendMode = 'normal';
3624
+
3531
3625
  $.blendMode = (mode) => {
3532
3626
  if (mode == $._blendMode) return;
3533
3627
  if (mode == 'source-over') mode = 'normal';
@@ -3960,19 +4054,22 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
3960
4054
  if ($._matrixDirty) $._saveMatrix();
3961
4055
  let ti = $._transformIndex,
3962
4056
  ci = $._stroke,
3963
- sw = $._strokeWeight,
3964
- hsw = sw / 2;
4057
+ sw = $._strokeWeight;
3965
4058
 
3966
4059
  if (sw < 2) {
3967
4060
  let [l, r, t, b] = $._calcBox(x, y, sw, sw, 'corner');
3968
4061
  addRect(l, t, r, t, r, b, l, b, ci, ti);
3969
4062
  } else {
3970
4063
  let n = getArcSegments(sw);
3971
- addEllipse(x, y, hsw, hsw, n, ci, ti);
4064
+ sw /= 2;
4065
+ addEllipse(x, y, sw, sw, n, ci, ti);
3972
4066
  }
3973
4067
  };
3974
4068
 
3975
- // Remove the internal transformations from the line function
4069
+ $.stokeJoin = (x) => {
4070
+ $.log("q5 WebGPU doesn't support changing stroke join style.");
4071
+ };
4072
+
3976
4073
  $.line = (x1, y1, x2, y2) => {
3977
4074
  if ($._matrixDirty) $._saveMatrix();
3978
4075
  let ti = $._transformIndex,
@@ -3980,12 +4077,12 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
3980
4077
  sw = $._strokeWeight,
3981
4078
  hsw = sw / 2;
3982
4079
 
3983
- // Calculate the direction vector and length
4080
+ // calculate the direction vector and length
3984
4081
  let dx = x2 - x1,
3985
4082
  dy = y2 - y1,
3986
4083
  length = Math.hypot(dx, dy);
3987
4084
 
3988
- // Calculate the perpendicular vector for line thickness
4085
+ // calculate the perpendicular vector for line thickness
3989
4086
  let px = -(dy / length) * hsw,
3990
4087
  py = (dx / length) * hsw;
3991
4088
 
@@ -4021,10 +4118,10 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4021
4118
 
4022
4119
  $.endShape = (close) => {
4023
4120
  if (curveVertices.length > 0) {
4024
- // Duplicate start and end points if necessary
4121
+ // duplicate start and end points if necessary
4025
4122
  let points = [...curveVertices];
4026
4123
  if (points.length < 4) {
4027
- // Duplicate first and last points
4124
+ // duplicate first and last points
4028
4125
  while (points.length < 4) {
4029
4126
  points.unshift(points[0]);
4030
4127
  points.push(points[points.length - 1]);
@@ -4065,7 +4162,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4065
4162
  throw new Error('A shape must have at least 3 vertices.');
4066
4163
  }
4067
4164
 
4068
- // Close the shape if needed
4165
+ // close the shape if requested
4069
4166
  if (close) {
4070
4167
  let firstIndex = 0;
4071
4168
  let lastIndex = (shapeVertCount - 1) * 4;
@@ -4082,7 +4179,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4082
4179
  }
4083
4180
 
4084
4181
  if ($._doFill) {
4085
- // Triangulate the shape
4182
+ // triangulate the shape
4086
4183
  for (let i = 1; i < shapeVertCount - 1; i++) {
4087
4184
  let v0 = 0;
4088
4185
  let v1 = i * 4;
@@ -4096,7 +4193,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4096
4193
  }
4097
4194
 
4098
4195
  if ($._doStroke) {
4099
- // Draw lines between vertices
4196
+ // draw lines between vertices
4100
4197
  for (let i = 0; i < shapeVertCount - 1; i++) {
4101
4198
  let v1 = i * 4;
4102
4199
  let v2 = (i + 1) * 4;
@@ -4109,7 +4206,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4109
4206
  }
4110
4207
  }
4111
4208
 
4112
- // Reset for the next shape
4209
+ // reset for the next shape
4113
4210
  shapeVertCount = 0;
4114
4211
  sv = [];
4115
4212
  curveVertices = [];
@@ -4324,7 +4421,7 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
4324
4421
 
4325
4422
  tIdx = (tIdx + 1) % MAX_TEXTURES;
4326
4423
 
4327
- // If the texture array is full, destroy the oldest texture
4424
+ // if the texture array is full, destroy the oldest texture
4328
4425
  if ($._textures[tIdx]) {
4329
4426
  $._textures[tIdx].destroy();
4330
4427
  delete $._textures[tIdx];
@@ -4537,6 +4634,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4537
4634
  mipmapFilter: 'linear',
4538
4635
  maxAnisotropy: 16
4539
4636
  });
4637
+
4540
4638
  let fontBindGroupLayout = Q5.device.createBindGroupLayout({
4541
4639
  label: 'MSDF font group layout',
4542
4640
  entries: [
@@ -4574,6 +4672,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4574
4672
  primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' },
4575
4673
  multisample: { count: 4 }
4576
4674
  };
4675
+
4577
4676
  $._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
4578
4677
 
4579
4678
  class MsdfFont {
@@ -4589,8 +4688,9 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4589
4688
  getChar(charCode) {
4590
4689
  return this.chars[charCode] ?? this.defaultChar;
4591
4690
  }
4592
- // Gets the distance in pixels a line should advance for a given character code. If the upcoming
4593
- // 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.
4594
4694
  getXAdvance(charCode, nextCharCode = -1) {
4595
4695
  let char = this.getChar(charCode);
4596
4696
  if (nextCharCode >= 0) {
@@ -4632,8 +4732,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4632
4732
  });
4633
4733
  Q5.device.queue.copyExternalImageToTexture({ source: img }, { texture }, imgSize);
4634
4734
 
4635
- // to make q5's default font file smaller,
4636
- // 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
4637
4737
  if (typeof atlas.chars == 'string') {
4638
4738
  atlas.chars = $.CSV.parse(atlas.chars, ' ');
4639
4739
  atlas.kernings = $.CSV.parse(atlas.kernings, ' ');
@@ -4722,6 +4822,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4722
4822
  $.textFont = (fontName) => {
4723
4823
  $._font = fonts[fontName];
4724
4824
  };
4825
+
4725
4826
  $.textSize = (size) => {
4726
4827
  $._textSize = size;
4727
4828
  if (!leadingSet) {
@@ -4729,12 +4830,14 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4729
4830
  leadDiff = leading - size;
4730
4831
  }
4731
4832
  };
4833
+
4732
4834
  $.textLeading = (lineHeight) => {
4733
4835
  $._font.lineHeight = leading = lineHeight;
4734
4836
  leadDiff = leading - $._textSize;
4735
4837
  leadPercent = leading / $._textSize;
4736
4838
  leadingSet = true;
4737
4839
  };
4840
+
4738
4841
  $.textAlign = (horiz, vert) => {
4739
4842
  $._textAlign = horiz;
4740
4843
  if (vert) $._textBaseline = vert;
@@ -4756,7 +4859,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4756
4859
  let charCode = nextCharCode;
4757
4860
  nextCharCode = i < text.length - 1 ? text.charCodeAt(i + 1) : -1;
4758
4861
  switch (charCode) {
4759
- case 10: // Newline
4862
+ case 10: // newline
4760
4863
  lineWidths.push(offsetX);
4761
4864
  line++;
4762
4865
  maxWidth = Math.max(maxWidth, offsetX);
@@ -4765,11 +4868,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4765
4868
  break;
4766
4869
  case 13: // CR
4767
4870
  break;
4768
- case 32: // Space
4871
+ case 32: // space
4769
4872
  // advance the offset without actually adding a character
4770
4873
  offsetX += font.getXAdvance(charCode);
4771
4874
  break;
4772
- case 9: // Tab
4875
+ case 9: // tab
4773
4876
  offsetX += font.getXAdvance(charCode) * 2;
4774
4877
  break;
4775
4878
  default:
@@ -4794,7 +4897,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4794
4897
 
4795
4898
  $.text = (str, x, y, w, h) => {
4796
4899
  if (!$._font) {
4797
- // 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
4798
4902
  if (navigator.onLine && !initLoadDefaultFont) {
4799
4903
  initLoadDefaultFont = true;
4800
4904
  $.loadFont('https://q5js.org/fonts/YaHei-msdf.json');
@@ -4953,27 +5057,27 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4953
5057
  $._hooks.preRender.push(() => {
4954
5058
  if (!$._charStack.length) return;
4955
5059
 
4956
- // Calculate total buffer size for text data
5060
+ // calculate total buffer size for text data
4957
5061
  let totalTextSize = 0;
4958
5062
  for (let charsData of $._charStack) {
4959
5063
  totalTextSize += charsData.length * 4;
4960
5064
  }
4961
5065
 
4962
- // Create a single buffer for all char data
5066
+ // create a single buffer for all the char data
4963
5067
  let charBuffer = Q5.device.createBuffer({
4964
5068
  size: totalTextSize,
4965
5069
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
4966
5070
  mappedAtCreation: true
4967
5071
  });
4968
5072
 
4969
- // Copy all text data into the buffer
5073
+ // copy all the text data into the buffer
4970
5074
  new Float32Array(charBuffer.getMappedRange()).set($._charStack.flat());
4971
5075
  charBuffer.unmap();
4972
5076
 
4973
- // Calculate total buffer size for metadata
5077
+ // calculate total buffer size for metadata
4974
5078
  let totalMetadataSize = $._textStack.length * 6 * 4;
4975
5079
 
4976
- // Create a single buffer for all metadata
5080
+ // create a single buffer for all metadata
4977
5081
  let textBuffer = Q5.device.createBuffer({
4978
5082
  label: 'textBuffer',
4979
5083
  size: totalMetadataSize,
@@ -4981,11 +5085,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4981
5085
  mappedAtCreation: true
4982
5086
  });
4983
5087
 
4984
- // Copy all metadata into the buffer
5088
+ // copy all metadata into the buffer
4985
5089
  new Float32Array(textBuffer.getMappedRange()).set($._textStack.flat());
4986
5090
  textBuffer.unmap();
4987
5091
 
4988
- // 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
4989
5093
  $._textBindGroup = Q5.device.createBindGroup({
4990
5094
  label: 'msdf text bind group',
4991
5095
  layout: textBindGroupLayout,