q5 2.0.4 → 2.0.12

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # <img src="q5js_logo.webp" height="64"> <img src="q5js_brand.webp" height="64">
2
2
 
3
- The sequel to p5.js is here!
3
+ The unsanctioned sequel to p5.js is here!
4
4
 
5
5
  **q5.js** implements all of [p5][]'s 2D drawing, math, and user input functionality.
6
6
 
@@ -282,10 +282,16 @@ An increase in performance of even a few frames per second can make a significan
282
282
 
283
283
  I was also interested in working on q5 because for a lot of p5.js users, the library itself is a black box. Even as an expert JS programmer and someone who teaches CS for a living, I still find myself scratching my head when I look at the p5.js source code. p5 was initially released 10 years ago and bad design choices were made due to JS limitations at the time. It's also become an absolutely massive library, with literally over 100,000 lines of code and documentation!
284
284
 
285
- I think it'd be better if the canvas mode, webgl mode, Friendly Error System, and accessibility features of p5 were offered in separate files. Yet, the powers that be at the Processing Foundation have made it clear that they don't want to do that. So q5 is a good alternative that trims out the fat.
286
-
287
285
  Thanks in large part to @LingDong-'s design, q5 is well organized, concise, and utilizes many modern JS features! I think even without inline documentation, the source code is easier for experienced JS programmers to comprehend.
288
286
 
287
+ I also started working on q5 because unfortunately I had a bad experience with The Processing Foundation. Simple bug fixes I contributed to p5.js all took over 5 months to be released. That's unacceptable given how well funded TPF is. I began to see p5play solely relying on p5.js as a liability. So being able to provide q5 as an alternative became a priority for me.
288
+
289
+ I think the problem is that management takes exorbitant salaries, 76% of the [annual budget](https://processingfoundation.report/), yet many of them still work [other full time jobs](https://www.linkedin.com/in/edsaber/). They seem to expect that just because p5.js is open source that volunteers will do most of the dev work. 🕵️
290
+
291
+ When criticized, TPF staff play the victim, silence dissent, and badmouth former contributors, regardless of how much time and effort they've donated to TPF projects. This behavior is inexcusable. Its driving away the people who made Processing and p5 great. 🚪
292
+
293
+ In October 2023, The Processing Foundation's co-founder, Ben Fry, resigned and publicly criticized management for [squandering millions of dollars in donations](https://x.com/ben_fry/status/1709400641456501020). I agree with Ben and I hope that TPF will hire full time developers to work on p5.js in the future. The summer 2024 pro5 grants are a great step in the right direction.
294
+
289
295
  ## More exclusive features
290
296
 
291
297
  Features added by @quinton-ashley:
@@ -305,9 +311,14 @@ Features added by @LingDong-:
305
311
  - `curveAlpha()`: manipulate the `α` parameter of Catmull-Rom curves.
306
312
  - `relRotationX`, `relRotationY` and `relRotationZ`: Similar to `rotationX/Y/Z`, but are relative to the orientation of the mobile device.
307
313
 
308
- ## Limitations
314
+ ## Porting from p5.js
309
315
 
310
- - `color` function only accepts numeric input, hex, and simple named colors. It doesn't parse strings like `color('hsl(160, 100%, 50%)')`. q5 supports oklch which is a superior color format so use it instead. The `fill`, `stroke`, and `background` functions can accept any css color string though.
316
+ - `createCanvas` must be run before any rendering functions are called. It can be run in `preload`. If it's not run before the draw loop starts, then q5 will run `createCanvas(100, 100)` automatically.
317
+ - `colorMode` supports 'rgb', 'srgb', and 'oklch'. Color modes like hsv are outdated, OKLCH is superior.
318
+ - `color` function only accepts numeric input, hex, and common named colors. It doesn't parse strings like `color('hsl(160, 100%, 50%)')`.
319
+ - `fill`, `stroke`, and `background` can accept any CSS color string.
320
+ - `colorMode` function only accepts "rgb", "srgb", or "oklch" because other formats that p5 still supports like hsv are obsolete.
321
+ - `noise` function's default noise algorithm is perlin noise. p5's default noise is called "blocky" noise in q5 and using it requires loading the src/q5-noisier.js module.
311
322
 
312
323
  ## Size Comparison
313
324
 
@@ -360,25 +371,15 @@ Higher FPS (frames per second) is better.
360
371
 
361
372
  <sub>\* Only for browsers that support CanvasRenderingContext2D.filter ([75% of all](https://caniuse.com/#feat=mdn-api_canvasrenderingcontext2d_filter) as of Aug 2020, including Chrome, Firefox and Edge). For those that don't, performance is similar to p5.js, as identical implementations are usually used as fallbacks.</sub>
362
373
 
363
- ## Contributor Code of Conduct
364
-
365
- We aim to make contributing to the q5 project more approachable for non-experts by using modern JavaScript without any complicated build tools or frameworks.
366
-
367
- All contributors are required to check their ego at the door and be open to feedback. Critique of code is not a critique of the person who wrote it. We're all here to learn and work with others to collectively write the best code possible.
368
-
369
- Code is a language art that can be subjectively judged by its effectiveness at communicating its functionality to humans. Code can also be objectively measured by its performance. Since JavaScript is served over a network, size is a factor as well. Therefore, the q5 team strives to balance code readability with brevity and performance.
370
-
371
- Check out the [q5 planning board](https://github.com/orgs/q5js/projects/1/views/1).
372
-
373
- ## Organization
374
+ ## Contributing
374
375
 
375
- If the q5 project is successful, all contributing developers will be paid for their work. The project will be run as a [worker co-op](https://en.wikipedia.org/wiki/Worker_cooperative).
376
+ See the [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [CONTRIBUTING.md](CONTRIBUTING.md) files for more information.
376
377
 
377
378
  ## Licensing
378
379
 
379
380
  q5.js was created by the q5 team and is licensed under the LGPLv3. q5 is not affiliated with The Processing Foundation.
380
381
 
381
- @LingDong- created the original q5xjs library which is MIT licensed.
382
+ @LingDong- created the original q5xjs library which is Unlicense licensed.
382
383
 
383
384
  p5.js is licensed under the LGPLv2, the two small sections of p5' code directly copied into q5 are credited below. The rest of q5 is a new implementation of part of the p5 API. APIs are not copyrightable in the United States, as decided by the Supreme Court in the Google v Oracle case.
384
385
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "2.0.4",
4
- "description": "The sequel to p5.js that's smaller and faster",
3
+ "version": "2.0.12",
4
+ "description": "A sequel to p5.js that's smaller and faster",
5
5
  "author": "quinton-ashley",
6
6
  "contributors": [
7
7
  "Tezumie",
package/q5.js CHANGED
@@ -81,7 +81,6 @@ function Q5(scope, parent) {
81
81
  p.frameCount++;
82
82
  let pre = performance.now();
83
83
  for (let m of Q5.prototype._methods.pre) m.call($);
84
- firstVertex = true;
85
84
  if ($.ctx) $.ctx.save();
86
85
  $.draw();
87
86
  for (let m of Q5.prototype._methods.post) m.call($);
@@ -207,7 +206,7 @@ function Q5(scope, parent) {
207
206
  else if ($._isGlobal) {
208
207
  $[k] = () => {
209
208
  try {
210
- t[k]();
209
+ return t[k]();
211
210
  } catch (e) {
212
211
  if ($._aiErrorAssistance) $._aiErrorAssistance(e);
213
212
  else console.error(e);
@@ -264,7 +263,7 @@ Q5.prototype.registerPreloadMethod = (n, fn) => (Q5.prototype[n] = fn[n]);
264
263
 
265
264
  if (Q5._nodejs) global.p5 ??= global.Q5 = Q5;
266
265
  else if (typeof window == 'object') window.p5 ??= window.Q5 = Q5;
267
- else window = 0;
266
+ else global.window = 0;
268
267
 
269
268
  if (typeof document == 'object') {
270
269
  document.addEventListener('DOMContentLoaded', () => {
@@ -535,6 +534,7 @@ Q5.modules.q2d_canvas = ($, p) => {
535
534
  let g = new Q5('graphics');
536
535
  opt ??= {};
537
536
  opt.alpha ??= true;
537
+ opt.colorSpace ??= $.canvas.colorSpace;
538
538
  g._createCanvas.call($, w, h, opt);
539
539
  return g;
540
540
  };
@@ -551,7 +551,6 @@ Q5.modules.q2d_canvas = ($, p) => {
551
551
 
552
552
  Q5.canvasOptions = {
553
553
  alpha: false,
554
- desynchronized: false,
555
554
  colorSpace: 'display-p3'
556
555
  };
557
556
 
@@ -630,7 +629,7 @@ Q5.modules.q2d_drawing = ($) => {
630
629
  $._strokeSet = true;
631
630
  if (Q5.Color) {
632
631
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
633
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
632
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
634
633
  if (c.a <= 0) return ($._doStroke = false);
635
634
  }
636
635
  $.ctx.strokeStyle = c.toString();
@@ -641,7 +640,7 @@ Q5.modules.q2d_drawing = ($) => {
641
640
  $._fillSet = true;
642
641
  if (Q5.Color) {
643
642
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
644
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
643
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
645
644
  if (c.a <= 0) return ($._doFill = false);
646
645
  }
647
646
  $.ctx.fillStyle = c.toString();
@@ -668,7 +667,7 @@ Q5.modules.q2d_drawing = ($) => {
668
667
  $.ctx.resetTransform();
669
668
  if (Q5.Color) {
670
669
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
671
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
670
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
672
671
  }
673
672
  $.ctx.fillStyle = c.toString();
674
673
  $.ctx.fillRect(0, 0, $.canvas.width, $.canvas.height);
@@ -690,21 +689,22 @@ Q5.modules.q2d_drawing = ($) => {
690
689
  }
691
690
  };
692
691
 
693
- function normAng(x) {
694
- let full = $._angleMode == $.DEGREES ? 360 : $.TAU;
695
- x = x % full;
696
- if (x < 0) x += full;
697
- return x;
698
- }
699
-
700
- function arc(x, y, w, h, start, stop, mode, detail) {
692
+ function arc(x, y, w, h, lo, hi, mode, detail) {
701
693
  if (!$._doFill && !$._doStroke) return;
702
- let lo = normAng(start);
703
- let hi = normAng(stop);
704
- if (lo > hi) [lo, hi] = [hi, lo];
694
+ let d = $._angleMode == 'degrees';
695
+ let full = d ? 360 : $.TAU;
696
+ lo %= full;
697
+ hi %= full;
698
+ if (lo < 0) lo += full;
699
+ if (hi < 0) hi += full;
705
700
  if (lo == 0 && hi == 0) return;
701
+ if (lo > hi) [lo, hi] = [hi, lo];
706
702
  $.ctx.beginPath();
707
703
  if (w == h) {
704
+ if (d) {
705
+ lo = $.radians(lo);
706
+ hi = $.radians(hi);
707
+ }
708
708
  $.ctx.arc(x, y, w / 2, lo, hi);
709
709
  } else {
710
710
  for (let i = 0; i < detail + 1; i++) {
@@ -1071,12 +1071,15 @@ Q5.modules.q2d_drawing = ($) => {
1071
1071
  };
1072
1072
 
1073
1073
  $.inStroke = (x, y) => {
1074
- const pd = pixelDensity();
1074
+ const pd = $._pixelDensity;
1075
1075
  return $.ctx.isPointInStroke(x * pd, y * pd);
1076
1076
  };
1077
1077
  };
1078
1078
  Q5.modules.q2d_image = ($, p) => {
1079
1079
  $.createImage = (w, h, opt) => {
1080
+ opt ??= {};
1081
+ opt.alpha ??= true;
1082
+ opt.colorSpace ??= $.canvas.colorSpace || Q5.canvasOptions.colorSpace;
1080
1083
  return new Q5.Image(w, h, opt);
1081
1084
  };
1082
1085
 
@@ -1398,22 +1401,26 @@ Q5.modules.q2d_image = ($, p) => {
1398
1401
  $.loadImage = function (url, cb, opt) {
1399
1402
  if (url.canvas) return url;
1400
1403
  if (url.slice(-3).toLowerCase() == 'gif') {
1401
- throw `In q5, GIFs are not supported due to their impact on performance. Use a video or p5play animation instead.`;
1404
+ throw new Error(`q5 doesn't support GIFs due to their impact on performance. Use a video or animation instead.`);
1402
1405
  }
1403
1406
  p._preloadCount++;
1404
1407
  let last = [...arguments].at(-1);
1405
- opt = typeof last == 'object' ? last : true;
1406
- let g = $.createImage(1, 1, opt.alpha);
1407
- let c = g.ctx;
1408
+ opt = typeof last == 'object' ? last : null;
1409
+
1410
+ let g = $.createImage(1, 1, opt);
1411
+
1412
+ function loaded(img) {
1413
+ let c = g.ctx;
1414
+ g.width = c.canvas.width = img.naturalWidth || img.width;
1415
+ g.height = c.canvas.height = img.naturalHeight || img.height;
1416
+ c.drawImage(img, 0, 0);
1417
+ p._preloadCount--;
1418
+ if (cb) cb(g);
1419
+ }
1420
+
1408
1421
  if (Q5._nodejs && global.CairoCanvas) {
1409
- CairoCanvas.loadImage(url)
1410
- .then((img) => {
1411
- g.width = c.canvas.width = img.width;
1412
- g.height = c.canvas.height = img.height;
1413
- c.drawImage(img, 0, 0);
1414
- p._preloadCount--;
1415
- if (cb) cb(g);
1416
- })
1422
+ global.CairoCanvas.loadImage(url)
1423
+ .then(loaded)
1417
1424
  .catch((e) => {
1418
1425
  p._preloadCount--;
1419
1426
  throw e;
@@ -1423,13 +1430,7 @@ Q5.modules.q2d_image = ($, p) => {
1423
1430
  img.src = url;
1424
1431
  img.crossOrigin = 'Anonymous';
1425
1432
  img._pixelDensity = 1;
1426
- img.onload = () => {
1427
- g.width = c.canvas.width = img.naturalWidth;
1428
- g.height = c.canvas.height = img.naturalHeight;
1429
- c.drawImage(img, 0, 0);
1430
- p._preloadCount--;
1431
- if (cb) cb(g);
1432
- };
1433
+ img.onload = () => loaded(img);
1433
1434
  img.onerror = (e) => {
1434
1435
  p._preloadCount--;
1435
1436
  throw e;
@@ -1453,8 +1454,7 @@ class _Q5Image {
1453
1454
  Q5.modules[m]($, $);
1454
1455
  }
1455
1456
  delete this.createCanvas;
1456
- opt ??= {};
1457
- opt.alpha ??= true;
1457
+
1458
1458
  this._createCanvas(w, h, '2d', opt);
1459
1459
  this._loop = false;
1460
1460
  }
@@ -1673,9 +1673,8 @@ Q5.modules.q2d_text = ($, p) => {
1673
1673
 
1674
1674
  $.loadFont = (url, cb) => {
1675
1675
  p._preloadCount++;
1676
- let sp = url.split('/');
1677
- let name = sp[sp.length - 1].split('.')[0].replace(' ', '');
1678
- let f = new FontFace(name, 'url(' + url + ')');
1676
+ let name = url.split('/').pop().split('.')[0].replace(' ', '');
1677
+ let f = new FontFace(name, `url(${url})`);
1679
1678
  document.fonts.add(f);
1680
1679
  f.load().then(() => {
1681
1680
  p._preloadCount--;
@@ -1795,7 +1794,6 @@ Q5.modules.q2d_text = ($, p) => {
1795
1794
  }
1796
1795
  if (!$._doFill && !$._doStroke) return;
1797
1796
  let c, ti, tg, k, cX, cY, _ascent, _descent;
1798
- let pd = 1;
1799
1797
  let t = $.ctx.getTransform();
1800
1798
  let useCache = $._genTextImage || ($._textCache && (t.b != 0 || t.c != 0));
1801
1799
  if (!useCache) {
@@ -1811,7 +1809,6 @@ Q5.modules.q2d_text = ($, p) => {
1811
1809
  }
1812
1810
  tg = $.createGraphics.call($, 1, 1);
1813
1811
  c = tg.ctx;
1814
- pd = $._pixelDensity;
1815
1812
  }
1816
1813
  c.font = `${$._textStyle} ${$._textSize}px ${$._textFont}`;
1817
1814
  let lines = str.split('\n');
@@ -1877,7 +1874,7 @@ Q5.modules.ai = ($) => {
1877
1874
  let askAI = e.message?.includes('Ask AI ✨');
1878
1875
  if (!askAI) console.error(e);
1879
1876
  if (Q5.disableFriendlyErrors) return;
1880
- if (askAI || !Q5.errorTolerant) noLoop();
1877
+ if (askAI || !Q5.errorTolerant) $.noLoop();
1881
1878
  let stackLines = e.stack?.split('\n');
1882
1879
  if (!e.stack || stackLines.length <= 1) return;
1883
1880
 
@@ -1952,7 +1949,7 @@ Q5.modules.color = ($, p) => {
1952
1949
  }
1953
1950
  };
1954
1951
 
1955
- $._basicColors = {
1952
+ $._namedColors = {
1956
1953
  aqua: [0, 255, 255],
1957
1954
  black: [0, 0, 0],
1958
1955
  blue: [0, 0, 255],
@@ -1993,14 +1990,28 @@ Q5.modules.color = ($, p) => {
1993
1990
  if (args.length == 1) {
1994
1991
  if (typeof c0 == 'string') {
1995
1992
  if (c0[0] == '#') {
1996
- return new C(
1997
- parseInt(c0.slice(1, 3), 16),
1998
- parseInt(c0.slice(3, 5), 16),
1999
- parseInt(c0.slice(5, 7), 16),
2000
- c0.length != 9 ? null : parseInt(c0.slice(7, 9), 16)
1993
+ if (c0.length <= 5) {
1994
+ return new C(
1995
+ parseInt(c0[1] + c0[1], 16),
1996
+ parseInt(c0[2] + c0[2], 16),
1997
+ parseInt(c0[3] + c0[3], 16),
1998
+ c0.length == 4 ? null : parseInt(c0[4] + c0[4], 16)
1999
+ );
2000
+ } else {
2001
+ return new C(
2002
+ parseInt(c0.slice(1, 3), 16),
2003
+ parseInt(c0.slice(3, 5), 16),
2004
+ parseInt(c0.slice(5, 7), 16),
2005
+ c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16)
2006
+ );
2007
+ }
2008
+ } else if ($._namedColors[c0]) return new C(...$._namedColors[c0]);
2009
+ else {
2010
+ console.error(
2011
+ "q5 can't parse color: " + c0 + '\nOnly numeric input, hex, and common named colors are supported.'
2001
2012
  );
2002
- } else if ($._basicColors[c0]) return new C(...$._basicColors[c0]);
2003
- else return new C(0, 0, 0);
2013
+ return new C(0, 0, 0);
2014
+ }
2004
2015
  } else if (Array.isArray(c0)) return new C(...c0);
2005
2016
  }
2006
2017
  if ($._colorMode == 'rgb') {
@@ -2318,24 +2329,22 @@ Q5.modules.input = ($, p) => {
2318
2329
 
2319
2330
  $._onkeydown = (e) => {
2320
2331
  if (e.repeat) return;
2321
- $._startAudio;
2332
+ $._startAudio();
2322
2333
  p.keyIsPressed = true;
2323
2334
  p.key = e.key;
2324
2335
  p.keyCode = e.keyCode;
2325
- keysHeld[$.keyCode] = keysHeld[$.key] = true;
2336
+ keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = true;
2326
2337
  $.keyPressed(e);
2327
- if (e.key.length == 1) {
2328
- $.keyTyped(e);
2329
- }
2338
+ if (e.key.length == 1) $.keyTyped(e);
2330
2339
  };
2331
2340
  $._onkeyup = (e) => {
2332
2341
  p.keyIsPressed = false;
2333
2342
  p.key = e.key;
2334
2343
  p.keyCode = e.keyCode;
2335
- keysHeld[$.keyCode] = keysHeld[$.key] = false;
2344
+ keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
2336
2345
  $.keyReleased(e);
2337
2346
  };
2338
- $.keyIsDown = (x) => !!keysHeld[x];
2347
+ $.keyIsDown = (v) => !!keysHeld[typeof v == 'string' ? v.toLowerCase() : v];
2339
2348
 
2340
2349
  function getTouchInfo(touch) {
2341
2350
  const rect = $.canvas.getBoundingClientRect();
@@ -2692,9 +2701,7 @@ Q5.modules.math = ($, p) => {
2692
2701
  };
2693
2702
  };
2694
2703
 
2695
- Q5.Noise = class {
2696
- constructor() {}
2697
- };
2704
+ Q5.Noise = class {};
2698
2705
 
2699
2706
  Q5.PerlinNoise = class extends Q5.Noise {
2700
2707
  constructor(seed) {
@@ -3025,7 +3032,7 @@ Q5.Vector = class {
3025
3032
  lerp() {
3026
3033
  let args = [...arguments];
3027
3034
  let u = this._arg2v(...args.slice(0, -1));
3028
- let amt = args[args.length - 1];
3035
+ let amt = args.at(-1);
3029
3036
  this.x += (u.x - this.x) * amt;
3030
3037
  this.y += (u.y - this.y) * amt;
3031
3038
  this.z += (u.z - this.z) * amt;
package/q5.min.js CHANGED
@@ -5,4 +5,4 @@
5
5
  * @license LGPL-3.0
6
6
  * @class Q5
7
7
  */
8
- function Q5(e,t){let a,o=this;if(o._q5=!0,o._scope=e,o._parent=t,o._preloadCount=0,e??="global","auto"==e){if(!window.setup&&!window.draw)return;e="global"}"global"==e&&(Q5._hasGlobal=o._isGlobal=!0,a=Q5._nodejs?global:window);let n=new Proxy(o,{set:(e,t,n)=>(o[t]=n,o._isGlobal&&(a[t]=n),!0)});o.canvas=o.ctx=o.drawingContext=null,o.pixels=[];let r=null;o.frameCount=0,o.deltaTime=16,o._targetFrameRate=0,o._targetFrameDuration=16.666666666666668,o._frameRate=o._fps=60,o._loop=!0;let i=0;function s(e){let t=e||performance.now();if(o._lastFrameTime??=t-o._targetFrameDuration,o._shouldResize&&(o.windowResized(),o._shouldResize=!1),o._loop)r=l(s);else if(o.frameCount&&!o._redraw)return;if(r&&o.frameCount){if(t-o._lastFrameTime<o._targetFrameDuration-1)return}n.deltaTime=t-o._lastFrameTime,o._frameRate=1e3/o.deltaTime,n.frameCount++;let a=performance.now();for(let e of Q5.prototype._methods.pre)e.call(o);firstVertex=!0,o.ctx&&o.ctx.save(),o.draw();for(let e of Q5.prototype._methods.post)e.call(o);o.ctx&&(o.ctx.restore(),o.resetMatrix()),n.pmouseX=o.mouseX,n.pmouseY=o.mouseY,o._lastFrameTime=t;let i=performance.now();o._fps=Math.round(1e3/(i-a))}o.millis=()=>performance.now()-i,o.noCanvas=()=>{o.canvas?.remove&&o.canvas.remove(),o.canvas=0,n.ctx=n.drawingContext=0},window&&(o.windowWidth=window.innerWidth,o.windowHeight=window.innerHeight,o.deviceOrientation=window.screen?.orientation?.type),o._incrementPreload=()=>n._preloadCount++,o._decrementPreload=()=>n._preloadCount--,o.noLoop=()=>{o._loop=!1,r=null},o.loop=()=>{o._loop=!0,null==r&&s()},o.redraw=(e=1)=>{o._redraw=!0;for(let t=0;t<e;t++)s();o._redraw=!1},o.remove=()=>{o.noLoop(),o.canvas.remove()},o.frameRate=e=>(e&&(o._targetFrameRate=e,o._targetFrameDuration=1e3/e),o._frameRate),o.getTargetFrameRate=()=>o._targetFrameRate,o.getFPS=()=>o._fps,o.Element=function(e){this.elt=e},o._elements=[],o.TWO_PI=o.TAU=2*Math.PI,o.log=o.print=console.log,o.describe=()=>{};for(let e in Q5.modules)Q5.modules[e](o,n);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(o[e]=Q5[e]);"global"==e&&(Object.assign(Q5,o),delete Q5.Q5);for(let e of Q5.prototype._methods.init)e.call(o);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof o[e]&&(o[e]=t.bind(o));if("global"==e){let e=Object.getOwnPropertyNames(o);for(let t of e)"_"!=t[0]&&(a[t]=o[t])}if("function"==typeof e&&e(o),"graphics"==e)return;Q5._instanceCount++;let l=window.requestAnimationFrame||function(e){const t=o._lastFrameTime+o._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},c=a||o;o._isTouchAware=c.touchStarted||c.touchMoved||c.mouseReleased;let d=c.preload,h=["setup","draw","preload","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized"];for(let e of h)c[e]?o._isGlobal&&(o[e]=()=>{try{c[e]()}catch(e){o._aiErrorAssistance?o._aiErrorAssistance(e):console.error(e)}}):o[e]=()=>{};async function u(){if(o._startDone=!0,o._preloadCount>0)return l(u);i=performance.now(),await o.setup(),o.frameCount||(null===o.ctx&&o.createCanvas(100,100),o._setupDone=!0,o.ctx&&o.resetMatrix(),l(s))}(o.setup||o.draw)&&(o._startDone=!1,arguments.length&&"namespace"!=e||d?(o.preload(),u()):(c.preload=o.preload=()=>{o._startDone||u()},setTimeout(o.preload,32)))}Q5.modules={},Q5._nodejs="object"==typeof process,Q5._instanceCount=0,Q5._friendlyError=(e,t)=>{throw Error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.prototype._methods={init:[],pre:[],post:[],remove:[]},Q5.prototype.registerMethod=(e,t)=>Q5.prototype._methods[e].push(t),Q5.prototype.registerPreloadMethod=(e,t)=>Q5.prototype[e]=t[e],Q5._nodejs?global.p5??=global.Q5=Q5:"object"==typeof window?window.p5??=window.Q5=Q5:window=0,"object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||new Q5("auto")})),Q5.modules.q2d_canvas=(e,t)=>{e._OffscreenCanvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._nodejs?Q5._createNodeJSCanvas&&(t.canvas=Q5._createNodeJSCanvas(100,100)):"image"!=e._scope&&"graphics"!=e._scope||(t.canvas=new e._OffscreenCanvas(100,100)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas());let a=e.canvas;if(a.width=e.width=100,a.height=e.height=100,a&&"graphics"!=e._scope&&"image"!=e._scope){e._setupDone=!1;let r=e._parent;function o(){r??=document.getElementsByTagName("main")[0],r||(r=document.createElement("main"),document.body.append(r)),a.parent(r)}r&&"string"==typeof r&&(r=document.getElementById(r)),a.parent=t=>{function o(){e.frameCount>1&&(e._shouldResize=!0,e._adjustDisplay())}"string"==typeof t&&(t=document.getElementById(t)),t.append(a),"function"==typeof ResizeObserver?(e._ro&&e._ro.disconnect(),e._ro=new ResizeObserver(o),e._ro.observe(r)):e.frameCount||window.addEventListener("resize",o)},document.body?o():document.addEventListener("DOMContentLoaded",o)}function n(o,n){o??=window.innerWidth,n??=window.innerHeight;let r,i=function(){let t={};for(let a in e.ctx)"function"!=typeof e.ctx[a]&&(t[a]=e.ctx[a]);return delete t.canvas,t}();if(e.frameCount){r=new e._OffscreenCanvas(a.width,a.height),r.w=a.w,r.h=a.h,r.getContext("2d").drawImage(a,0,0)}a.width=Math.ceil(o*e._pixelDensity),a.height=Math.ceil(n*e._pixelDensity),a.w=o,a.h=n,a.hw=o/2,a.hh=n/2;for(let t in i)e.ctx[t]=i[t];e.ctx.scale(e._pixelDensity,e._pixelDensity),e.frameCount&&e.ctx.drawImage(r,0,0,r.w,r.h),e._da?e.flexibleCanvas(e._dau):(t.width=o,t.height=n),0!=e.frameCount&&e._adjustDisplay()}e._adjustDisplay=()=>{a.style&&(a.style.width=a.w+"px",a.style.height=a.h+"px")},e.createCanvas=function(o,n,r,i){if("webgl"==r)throw Error("webgl renderer is not supported in q5, use '2d'");"object"==typeof r&&(i=r),t.width=a.width=a.w=o||window.innerWidth,t.height=a.height=a.h=n||window.innerHeight,a.hw=o/2,a.hh=n/2,a.renderer="2d";let s=Object.assign({},Q5.canvasOptions);if(i&&Object.assign(s,i),t.ctx=t.drawingContext=a.getContext("2d",s),Object.assign(a,s),"rgb"==e._colorMode&&e.colorMode("rgb"),"image"!=e._scope&&(e._defaultStyle(),e._da=0),e.ctx.save(),"image"!=e._scope){let t=e.displayDensity();"graphics"==e._scope?t=this._pixelDensity:window.IntersectionObserver&&new IntersectionObserver((e=>{a.visible=e[0].isIntersecting})).observe(a),e.pixelDensity(Math.ceil(t))}else this._pixelDensity=1;return e.displayMode?e.displayMode():e._adjustDisplay(),a},e._createCanvas=e.createCanvas,"image"!=e._scope&&(e._defaultStyle=()=>{e.ctx.fillStyle="white",e.ctx.strokeStyle="black",e.ctx.lineCap="round",e.ctx.lineJoin="miter",e.ctx.textAlign="left"},e.resizeCanvas=(e,t)=>{e==a.w&&t==a.h||n(e,t)},e._pixelDensity=1,e.displayDensity=()=>window.devicePixelRatio,e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,n(a.w,a.h),t):e._pixelDensity,"image"!=e._scope&&(e.fullscreen=e=>{if(void 0===e)return document.fullscreenElement;e?document.body.requestFullscreen():document.body.exitFullscreen()},e.flexibleCanvas=(o=400)=>{o?(e._da=a.width/(o*e._pixelDensity),t.width=e._dau=o,t.height=a.h/a.w*o):e._da=0},e.translate=(t,a)=>{e._da&&(t*=e._da,a*=e._da),e.ctx.translate(t,a)},e.rotate=t=>{"degrees"==e._angleMode&&(t=e.radians(t)),e.ctx.rotate(t)},e.scale=(t,a)=>{a??=t,e.ctx.scale(t,a)},e.opacity=t=>e.ctx.globalAlpha=t,e.applyMatrix=(t,a,o,n,r,i)=>e.ctx.transform(t,a,o,n,r,i),e.shearX=t=>e.ctx.transform(1,0,e.tan(t),1,0,0),e.shearY=t=>e.ctx.transform(1,e.tan(t),0,1,0,0),e.resetMatrix=()=>{e.ctx.resetTransform(),e.ctx.scale(e._pixelDensity,e._pixelDensity)},e._styleNames=["_doStroke","_doFill","_strokeSet","_fillSet","_tint","_imageMode","_rectMode","_ellipseMode","_textFont","_textLeading","_leadingSet","_textSize","_textAlign","_textBaseline","_textStyle","_textWrap"],e._styles=[],e.push=e.pushMatrix=()=>{e.ctx.save();let t={};for(let a of e._styleNames)t[a]=e[a];e._styles.push(t)},e.pop=e.popMatrix=()=>{e.ctx.restore();let t=e._styles.pop();for(let a of e._styleNames)e[a]=t[a]},e.createCapture=e=>{var t=document.createElement("video");return t.playsinline="playsinline",t.autoplay="autoplay",navigator.mediaDevices.getUserMedia(e).then((e=>{t.srcObject=e})),t.style.position="absolute",t.style.opacity=1e-5,t.style.zIndex=-1e3,document.body.append(t),t},e.createGraphics=function(t,a,o){let n=new Q5("graphics");return o??={},o.alpha??=!0,n._createCanvas.call(e,t,a,o),n},window&&"graphics"!=e._scope&&window.addEventListener("resize",(()=>{e._shouldResize=!0,t.windowWidth=window.innerWidth,t.windowHeight=window.innerHeight,t.deviceOrientation=window.screen?.orientation?.type}))))},Q5.canvasOptions={alpha:!1,desynchronized:!1,colorSpace:"display-p3"},window.matchMedia&&matchMedia("(dynamic-range: high) and (color-gamut: p3)").matches?Q5.supportsHDR=!0:Q5.canvasOptions.colorSpace="srgb",Q5.modules.q2d_drawing=e=>{e.CHORD=0,e.PIE=1,e.OPEN=2,e.RADIUS="radius",e.CORNER="corner",e.CORNERS="corners",e.ROUND="round",e.SQUARE="butt",e.PROJECT="square",e.MITER="miter",e.BEVEL="bevel",e.CLOSE=1,e.CENTER="center",e.LEFT="left",e.RIGHT="right",e.TOP="top",e.BOTTOM="bottom",e.LANDSCAPE="landscape",e.PORTRAIT="portrait",e.BLEND="source-over",e.REMOVE="destination-out",e.ADD="lighter",e.DARKEST="darken",e.LIGHTEST="lighten",e.DIFFERENCE="difference",e.SUBTRACT="subtract",e.EXCLUSION="exclusion",e.MULTIPLY="multiply",e.SCREEN="screen",e.REPLACE="copy",e.OVERLAY="overlay",e.HARD_LIGHT="hard-light",e.SOFT_LIGHT="soft-light",e.DODGE="color-dodge",e.BURN="color-burn",e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=e.CENTER,e._rectMode=e.CORNER,e._curveDetail=20,e._curveAlpha=0;let t=!0,a=[];function o(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}function n(t){let a=e._angleMode==e.DEGREES?360:e.TAU;return(t%=a)<0&&(t+=a),t}function r(t,a,r,i,s,l,c,d){if(!e._doFill&&!e._doStroke)return;let h=n(s),u=n(l);if(h>u&&([h,u]=[u,h]),0!=h||0!=u){if(e.ctx.beginPath(),r==i)e.ctx.arc(t,a,r/2,h,u);else{for(let o=0;o<d+1;o++){let n=o/d,s=e.lerp(h,u,n),l=e.cos(s)*r/2,c=e.sin(s)*i/2;e.ctx[o?"lineTo":"moveTo"](t+l,a+c)}c==e.CHORD?e.ctx.closePath():c==e.PIE&&(e.ctx.lineTo(t,a),e.ctx.closePath())}o()}}function i(t,a,n,r){(e._doFill||e._doStroke)&&(e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.ellipse(t,a,n/2,r/2,0,0,e.TAU),o())}function s(t,a,n,r,i,l,c,d){if(!e._doFill&&!e._doStroke)return;if(void 0===i)return function(t,a,n,r){e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.rect(t,a,n,r),o()}(t,a,n,r);if(void 0===l)return s(t,a,n,r,i,i,i,i);e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da,i*=e._da,l*=e._da,d*=e._da,c*=e._da);const h=Math.min(Math.abs(r),Math.abs(n))/2;i=Math.min(h,i),l=Math.min(h,l),d=Math.min(h,d),c=Math.min(h,c),e.ctx.beginPath(),e.ctx.moveTo(t+i,a),e.ctx.arcTo(t+n,a,t+n,a+r,l),e.ctx.arcTo(t+n,a+r,t,a+r,c),e.ctx.arcTo(t,a+r,t,a,d),e.ctx.arcTo(t,a,t+n,a,i),e.ctx.closePath(),o()}function l(){a=[]}e.strokeWeight=t=>{t||(e._doStroke=!1),e._da&&(t*=e._da),e.ctx.lineWidth=t||1e-4},e.stroke=function(t){if(e._doStroke=!0,e._strokeSet=!0,Q5.Color&&(t._q5Color||"string"==typeof t?e._basicColors[t]&&(t=e.color(...e._basicColors[t])):t=e.color(...arguments),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=t.toString()},e.noStroke=()=>e._doStroke=!1,e.fill=function(t){if(e._doFill=!0,e._fillSet=!0,Q5.Color&&(t._q5Color||"string"==typeof t?e._basicColors[t]&&(t=e.color(...e._basicColors[t])):t=e.color(...arguments),t.a<=0))return e._doFill=!1;e.ctx.fillStyle=t.toString()},e.noFill=()=>e._doFill=!1,e.blendMode=t=>e.ctx.globalCompositeOperation=t,e.strokeCap=t=>e.ctx.lineCap=t,e.strokeJoin=t=>e.ctx.lineJoin=t,e.ellipseMode=t=>e._ellipseMode=t,e.rectMode=t=>e._rectMode=t,e.curveDetail=t=>e._curveDetail=t,e.curveAlpha=t=>e._curveAlpha=t,e.curveTightness=t=>e._curveAlpha=t,e.clear=()=>{e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height)},e.background=function(t){if(t.canvas)return e.image(t,0,0,e.width,e.height);e.ctx.save(),e.ctx.resetTransform(),Q5.Color&&(t._q5Color||"string"==typeof t?e._basicColors[t]&&(t=e.color(...e._basicColors[t])):t=e.color(...arguments)),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e.line=(t,a,o,n)=>{e._doStroke&&(e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,a),e.ctx.lineTo(o,n),e.ctx.stroke())},e.arc=(t,a,o,n,i,s,l,c=25)=>{if(i==s)return e.ellipse(t,a,o,n);l??=e.PIE,e._ellipseMode==e.CENTER?r(t,a,o,n,i,s,l,c):e._ellipseMode==e.RADIUS?r(t,a,2*o,2*n,i,s,l,c):e._ellipseMode==e.CORNER?r(t+o/2,a+n/2,o,n,i,s,l,c):e._ellipseMode==e.CORNERS&&r((t+o)/2,(a+n)/2,o-t,n-a,i,s,l,c)},e.ellipse=(t,a,o,n)=>{n??=o,e._ellipseMode==e.CENTER?i(t,a,o,n):e._ellipseMode==e.RADIUS?i(t,a,2*o,2*n):e._ellipseMode==e.CORNER?i(t+o/2,a+n/2,o,n):e._ellipseMode==e.CORNERS&&i((t+o)/2,(a+n)/2,o-t,n-a)},e.circle=(t,a,n)=>{e._ellipseMode==e.CENTER?(e._da&&(t*=e._da,a*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.arc(t,a,n/2,0,e.TAU),o()):e.ellipse(t,a,n,n)},e.point=(t,a)=>{t.x&&(a=t.y,t=t.x),e._da&&(t*=e._da,a*=e._da),e.ctx.save(),e.ctx.beginPath(),e.ctx.arc(t,a,e.ctx.lineWidth/2,0,e.TAU),e.ctx.fillStyle=e.ctx.strokeStyle,e.ctx.fill(),e.ctx.restore()},e.rect=(t,a,o,n=o,r,i,l,c)=>{e._rectMode==e.CENTER?s(t-o/2,a-n/2,o,n,r,i,l,c):e._rectMode==e.RADIUS?s(t-o,a-n,2*o,2*n,r,i,l,c):e._rectMode==e.CORNER?s(t,a,o,n,r,i,l,c):e._rectMode==e.CORNERS&&s(t,a,o-t,n-a,r,i,l,c)},e.square=(t,a,o,n,r,i,s)=>e.rect(t,a,o,o,n,r,i,s),e.beginShape=()=>{l(),e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),l(),t=!0},e.endContour=()=>{l(),t=!0},e.vertex=(a,o)=>{e._da&&(a*=e._da,o*=e._da),l(),t?e.ctx.moveTo(a,o):e.ctx.lineTo(a,o),t=!1},e.bezierVertex=(t,a,o,n,r,i)=>{e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da,r*=e._da,i*=e._da),l(),e.ctx.bezierCurveTo(t,a,o,n,r,i)},e.quadraticVertex=(t,a,o,n)=>{e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da),l(),e.ctx.quadraticCurveTo(t,a,o,n)},e.bezier=(t,a,o,n,r,i,s,l)=>{e.beginShape(),e.vertex(t,a),e.bezierVertex(o,n,r,i,s,l),e.endShape()},e.triangle=(t,a,o,n,r,i)=>{e.beginShape(),e.vertex(t,a),e.vertex(o,n),e.vertex(r,i),e.endShape(e.CLOSE)},e.quad=(t,a,o,n,r,i,s,l)=>{e.beginShape(),e.vertex(t,a),e.vertex(o,n),e.vertex(r,i),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{l(),t&&e.ctx.closePath(),o()},e.curveVertex=(o,n)=>{if(e._da&&(o*=e._da,n*=e._da),a.push([o,n]),a.length<4)return;let r=function(e,t,a,o,n,r,i,s,l,c){function d(e,t,a,o,n,r){let i=Math.pow(o-t,2)+Math.pow(n-a,2);return Math.pow(i,.5*r)+e}let h=[],u=d(0,e,t,a,o,c),_=d(u,a,o,n,r,c),g=d(_,n,r,i,s,c);for(let c=0;c<l;c++){let d=u+c/(l-1)*(_-u),p=[(u-d)/(u-0),(d-0)/(u-0),(_-d)/(_-u),(d-u)/(_-u),(g-d)/(g-_),(d-_)/(g-_),(_-d)/(_-0),(d-0)/(_-0),(g-d)/(g-u),(d-u)/(g-u)];for(let e=0;e<p.length;e+=2)isNaN(p[e])&&(p[e]=1,p[e+1]=0),isFinite(p[e])||(p[e]>0?(p[e]=1,p[e+1]=0):(p[e]=0,p[e+1]=1));let x=e*p[0]+a*p[1],m=t*p[0]+o*p[1],f=a*p[2]+n*p[3],v=o*p[2]+r*p[3],y=n*p[4]+i*p[5],w=r*p[4]+s*p[5],M=x*p[6]+f*p[7],C=m*p[6]+v*p[7],S=f*p[8]+y*p[9],b=v*p[8]+w*p[9],R=M*p[2]+S*p[3],E=C*p[2]+b*p[3];h.push([R,E])}return h}(...a.at(-4),...a.at(-3),...a.at(-2),...a.at(-1),e._curveDetail,e._curveAlpha);for(let a=0;a<r.length;a++)t?e.ctx.moveTo(...r[a]):e.ctx.lineTo(...r[a]),t=!1},e.curve=(t,a,o,n,r,i,s,l)=>{e.beginShape(),e.curveVertex(t,a),e.curveVertex(o,n),e.curveVertex(r,i),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,a,o,n)=>{const r=n*n*n,i=n*n;return e*(-.5*r+i-.5*n)+t*(1.5*r-2.5*i+1)+a*(-1.5*r+2*i+.5*n)+o*(.5*r-.5*i)},e.bezierPoint=(e,t,a,o,n)=>{const r=1-n;return Math.pow(r,3)*e+3*Math.pow(r,2)*n*t+3*r*Math.pow(n,2)*a+Math.pow(n,3)*o},e.curveTangent=(e,t,a,o,n)=>{const r=n*n;return e*(-3*r/2+2*n-.5)+t*(9*r/2-5*n)+a*(-9*r/2+4*n+.5)+o*(3*r/2-n)},e.bezierTangent=(e,t,a,o,n)=>{const r=1-n;return 3*o*Math.pow(n,2)-3*a*Math.pow(n,2)+6*a*r*n-6*t*r*n+3*t*Math.pow(r,2)-3*e*Math.pow(r,2)},e.erase=function(t=255,a=255){e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgba(0, 0, 0, ${t/255})`,e.ctx.strokeStyle=`rgba(0, 0, 0, ${a/255})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,a)=>{const o=e._pixelDensity;return e.ctx.isPointInPath(t*o,a*o)},e.inStroke=(t,a)=>{const o=pixelDensity();return e.ctx.isPointInStroke(t*o,a*o)}},Q5.modules.q2d_image=(e,t)=>{e.createImage=(e,t,a)=>new Q5.Image(e,t,a),e._tint=null;let a=null,o=null,n=null;function r(t,a){a??=t||e.canvas.height,t??=e.canvas.width,null==o&&(o=new e._OffscreenCanvas(t,a).getContext("2d",{colorSpace:e.canvas.colorSpace})),o.canvas.width==t&&o.canvas.height==a||(o.canvas.width=t,o.canvas.height=a)}function i(t){o.clearRect(0,0,o.canvas.width,o.canvas.height),o.filter=t,o.drawImage(e.canvas,0,0),e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()}e._softFilter=()=>{throw"Load q5-2d-soft-filters.js to use software filters."},e.filter=(t,a)=>{if(!e.ctx.filter)return e._softFilter(t,a);if(r(),"string"==typeof t)i(t);else if(t==Q5.THRESHOLD){a??=.5,a=Math.max(a,1e-5),i(`saturate(0%) brightness(${Math.floor(.5/a*100)}%) contrast(1000000%)`)}else t==Q5.GRAY?i("saturate(0%)"):t==Q5.OPAQUE?(o.fillStyle="black",o.fillRect(0,0,o.canvas.width,o.canvas.height),o.drawImage(e.canvas,0,0),e.ctx.save(),e.ctx.resetTransform(),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()):t==Q5.INVERT?i("invert(100%)"):t==Q5.BLUR?i(`blur(${Math.ceil(a*e._pixelDensity/1)||1}px)`):e._softFilter(t,a)},e.resize=(a,n)=>{r(),o.drawImage(e.canvas,0,0),t.width=a,t.height=n,e.canvas.width=a*e._pixelDensity,e.canvas.height=n*e._pixelDensity,e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.drawImage(o.canvas,0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e.trim=()=>{let t=e._pixelDensity||1,a=e.ctx.getImageData(0,0,e.width*t,e.height*t).data,o=e.width,n=0,r=e.height,i=0;for(let s=0;s<e.height*t;s++)for(let l=0;l<e.width*t;l++){0!==a[4*(s*e.width*t+l)+3]&&(l<o&&(o=l),l>n&&(n=l),s<r&&(r=s),s>i&&(i=s))}return r=Math.floor(r/t),i=Math.floor(i/t),o=Math.floor(o/t),n=Math.floor(n/t),e.get(o,r,n-o+1,i-r+1)},e.mask=t=>{e.ctx.save(),e.ctx.resetTransform();let a=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="destination-in",e.ctx.drawImage(t.canvas,0,0),e.ctx.globalCompositeOperation=a,e.ctx.restore()},e._save=async(e,t,a)=>{if(t=t||"untitled","jpg"==(a=a||"png")||"png"==a||"webp"==a)if(e instanceof OffscreenCanvas){const t=await e.convertToBlob({type:"image/"+a});e=await new Promise((e=>{const a=new FileReader;a.onloadend=()=>e(a.result),a.readAsDataURL(t)}))}else e=e.toDataURL("image/"+a);else{let t="text/plain";"json"==a&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),e=new Blob([e],{type:t}),e=URL.createObjectURL(e)}let o=document.createElement("a");o.href=e,o.download=t+"."+a,document.body.append(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(o.href)},e.save=(t,a,o)=>{if((!t||"string"==typeof t&&(!a||!o&&a.length<5))&&(o=a,a=t,t=e.canvas),o)return e._save(t,a,o);a?(a=a.split("."),e._save(t,a[0],a.at(-1))):e._save(t)},e.get=(t,a,o,n)=>{let r=e._pixelDensity||1;if(void 0!==t&&void 0===o){let o=e.ctx.getImageData(t*r,a*r,1,1).data;return new e.Color(o[0],o[1],o[2],o[3]/255)}t=(t||0)*r,a=(a||0)*r;let i=o=o||e.width,s=n=n||e.height;o*=r,n*=r;let l=e.createImage(o,n),c=e.ctx.getImageData(t,a,o,n);return l.ctx.putImageData(c,0,0),l._pixelDensity=r,l.width=i,l.height=s,l},e.set=(t,a,o)=>{if(o.canvas){let n=e._tint;return e._tint=null,e.image(o,t,a),void(e._tint=n)}e.pixels.length||e.loadPixels();let n=e._pixelDensity||1;for(let r=0;r<n;r++)for(let i=0;i<n;i++){let s=4*((a*n+r)*e.canvas.width+t*n+i);e.pixels[s]=o.r??o.l,e.pixels[s+1]=o.g??o.c,e.pixels[s+2]=o.b??o.h,e.pixels[s+3]=o.a}},e.loadPixels=()=>{a=e.ctx.getImageData(0,0,e.canvas.width,e.canvas.height),t.pixels=a.data},e.updatePixels=()=>{null!=a&&e.ctx.putImageData(a,0,0)},e._tinted=function(t){let a=t.a;t.a=255,r(),o.clearRect(0,0,o.canvas.width,o.canvas.height),o.fillStyle=t.toString(),o.fillRect(0,0,o.canvas.width,o.canvas.height),o.globalCompositeOperation="multiply",o.drawImage(e.ctx.canvas,0,0),o.globalCompositeOperation="source-over",e.ctx.save(),e.ctx.resetTransform();let n=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="source-in",e.ctx.drawImage(o.canvas,0,0),e.ctx.globalCompositeOperation=n,e.ctx.restore(),o.globalAlpha=a/255,o.clearRect(0,0,o.canvas.width,o.canvas.height),o.drawImage(e.ctx.canvas,0,0),o.globalAlpha=1,e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.ctx.canvas.width,e.ctx.canvas.height),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,"image"!=e._scope&&(e.saveCanvas=e.canvas.save=e.save,e.tint=function(t){e._tint=t._q5Color?t:e.color(...arguments)},e.noTint=()=>e._tint=null,e.imageMode=t=>e._imageMode=t,e.image=(t,a,o,r,i,s=0,l=0,c,d)=>{e._da&&(a*=e._da,o*=e._da,r*=e._da,i*=e._da,s*=e._da,l*=e._da,c*=e._da,d*=e._da);let h=t.canvas||t;var u,_;Q5._createNodeJSCanvas&&(h=h.context.canvas),t.canvas&&null!=e._tint&&(u=t.canvas.width,_=t.canvas.height,_??=u||e.canvas.height,u??=e.canvas.width,null==n&&(n=new e._OffscreenCanvas(u,_).getContext("2d",{colorSpace:e.canvas.colorSpace})),n.canvas.width==u&&n.canvas.height==_||(n.canvas.width=u,n.canvas.height=_),n.drawImage(t.canvas,0,0),t._tinted(e._tint)),r??=t.width||t.videoWidth,i??=t.height||t.videoHeight,"center"==e._imageMode&&(a-=.5*r,o-=.5*i);let g=t._pixelDensity||1;c?c*=g:c=h.width||h.videoWidth,d?d*=g:d=h.height||h.videoHeight,e.ctx.drawImage(h,s*g,l*g,c,d,a,o,r,i),function(){if(!t._q5||!e._tint)return;let a=t.ctx;a.save(),a.resetTransform(),a.clearRect(0,0,a.canvas.width,a.canvas.height),a.drawImage(n.canvas,0,0),a.restore()}()},e.loadImage=function(a,o,n){if(a.canvas)return a;if("gif"==a.slice(-3).toLowerCase())throw"In q5, GIFs are not supported due to their impact on performance. Use a video or p5play animation instead.";t._preloadCount++;let r=[...arguments].at(-1);n="object"!=typeof r||r;let i=e.createImage(1,1,n.alpha),s=i.ctx;if(Q5._nodejs&&global.CairoCanvas)CairoCanvas.loadImage(a).then((e=>{i.width=s.canvas.width=e.width,i.height=s.canvas.height=e.height,s.drawImage(e,0,0),t._preloadCount--,o&&o(i)})).catch((e=>{throw t._preloadCount--,e}));else{let e=new window.Image;e.src=a,e.crossOrigin="Anonymous",e._pixelDensity=1,e.onload=()=>{i.width=s.canvas.width=e.naturalWidth,i.height=s.canvas.height=e.naturalHeight,s.drawImage(e,0,0),t._preloadCount--,o&&o(i)},e.onerror=e=>{throw t._preloadCount--,e}}return i})},Q5.imageModules=["q2d_canvas","q2d_image"];class _Q5Image{constructor(e,t,a){let o=this;o._scope="image",o.canvas=o.ctx=o.drawingContext=null,o.pixels=[];for(let e of Q5.imageModules)Q5.modules[e](o,o);delete this.createCanvas,a??={},a.alpha??=!0,this._createCanvas(e,t,"2d",a),this._loop=!1}get w(){return this.width}get h(){return this.height}}Q5.Image??=_Q5Image,Q5.THRESHOLD=1,Q5.GRAY=2,Q5.OPAQUE=3,Q5.INVERT=4,Q5.POSTERIZE=5,Q5.DILATE=6,Q5.ERODE=7,Q5.BLUR=8,Q5.modules.q2d_soft_filters=e=>{let t=null;function a(){let a=e.canvas.width*e.canvas.height*4;t&&a==t.length||(t=new Uint8ClampedArray(a))}e._softFilter=(o,n)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let a=0;a<e.length;a+=4){const o=.2126*e[a]+.7152*e[a+1]+.0722*e[a+2];e[a]=e[a+1]=e[a+2]=o>=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t<e.length;t+=4){const a=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];e[t]=e[t+1]=e[t+2]=a}},e._filters[Q5.OPAQUE]=e=>{for(let t=0;t<e.length;t+=4)e[t+3]=255},e._filters[Q5.INVERT]=e=>{for(let t=0;t<e.length;t+=4)e[t]=255-e[t],e[t+1]=255-e[t+1],e[t+2]=255-e[t+2]},e._filters[Q5.POSTERIZE]=(e,t=4)=>{let a=t-1;for(let o=0;o<e.length;o+=4)e[o]=255*(e[o]*t>>8)/a,e[o+1]=255*(e[o+1]*t>>8)/a,e[o+2]=255*(e[o+2]*t>>8)/a},e._filters[Q5.DILATE]=o=>{a(),t.set(o);let[n,r]=[e.canvas.width,e.canvas.height];for(let e=0;e<r;e++)for(let a=0;a<n;a++){let i=4*Math.max(a-1,0),s=4*Math.min(a+1,n-1),l=4*Math.max(e-1,0)*n,c=4*Math.min(e+1,r-1)*n,d=4*e*n,h=4*a;for(let e=0;e<4;e++){let a=e+l,n=e+c,r=e+d;o[d+h+e]=Math.max(t[a+h],t[r+i],t[r+h],t[r+s],t[n+h])}}},e._filters[Q5.ERODE]=o=>{a(),t.set(o);let[n,r]=[e.canvas.width,e.canvas.height];for(let e=0;e<r;e++)for(let a=0;a<n;a++){let i=4*Math.max(a-1,0),s=4*Math.min(a+1,n-1),l=4*Math.max(e-1,0)*n,c=4*Math.min(e+1,r-1)*n,d=4*e*n,h=4*a;for(let e=0;e<4;e++){let a=e+l,n=e+c,r=e+d;o[d+h+e]=Math.min(t[a+h],t[r+i],t[r+h],t[r+s],t[n+h])}}},e._filters[Q5.BLUR]=(o,n)=>{n=n||1,n=Math.floor(n*e._pixelDensity),a(),t.set(o);let r=2*n+1,i=function(e){let t=new Float32Array(e),a=.3*n+.8,o=a*a*2;for(let n=0;n<e;n++){let r=n-e/2,i=Math.exp(-r*r/o)/(2.5066282746*a);t[n]=i}return t}(r),[s,l]=[e.canvas.width,e.canvas.height];for(let e=0;e<l;e++)for(let a=0;a<s;a++){let l=0,c=0,d=0,h=0;for(let o=0;o<r;o++){let r=4*(e*s+Math.min(Math.max(a-n+o,0),s-1));l+=t[r]*i[o],c+=t[r+1]*i[o],d+=t[r+2]*i[o],h+=t[r+3]*i[o]}let u=4*(e*s+a);o[u]=l,o[u+1]=c,o[u+2]=d,o[u+3]=h}t.set(o);for(let e=0;e<l;e++)for(let a=0;a<s;a++){let c=0,d=0,h=0,u=0;for(let o=0;o<r;o++){let r=4*(Math.min(Math.max(e-n+o,0),l-1)*s+a);c+=t[r]*i[o],d+=t[r+1]*i[o],h+=t[r+2]*i[o],u+=t[r+3]*i[o]}let _=4*(e*s+a);o[_]=c,o[_+1]=d,o[_+2]=h,o[_+3]=u}});let r=e.ctx.getImageData(0,0,e.canvas.width,e.canvas.height);e._filters[o](r.data,n),e.ctx.putImageData(r,0,0)}},Q5.modules.q2d_text=(e,t)=>{e.NORMAL="normal",e.ITALIC="italic",e.BOLD="bold",e.BOLDITALIC="italic bold",e.CENTER="center",e.LEFT="left",e.RIGHT="right",e.TOP="top",e.BOTTOM="bottom",e.BASELINE="alphabetic",e._textFont="sans-serif",e._textSize=12,e._textLeading=15,e._textLeadDiff=3,e._textStyle="normal",e.loadFont=(e,a)=>{t._preloadCount++;let o=e.split("/"),n=o[o.length-1].split(".")[0].replace(" ",""),r=new FontFace(n,"url("+e+")");return document.fonts.add(r),r.load().then((()=>{t._preloadCount--,a&&a(n)})),n},e.textFont=t=>e._textFont=t,e.textSize=t=>{if(void 0===t)return e._textSize;e._da&&(t*=e._da),e._textSize=t,e._leadingSet||(e._textLeading=1.25*t,e._textLeadDiff=e._textLeading-t)},e.textLeading=t=>{if(void 0===t)return e._textLeading;e._da&&(t*=e._da),e._textLeading=t,e._textLeadDiff=t-e._textSize,e._leadingSet=!0},e.textStyle=t=>e._textStyle=t,e.textAlign=(t,a)=>{e.ctx.textAlign=t,a&&(e.ctx.textBaseline=a==e.CENTER?"middle":a)},e.textWidth=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).width),e.textAscent=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).actualBoundingBoxDescent),e._textCache=!!Q5.Image,e._TimedCache=class extends Map{constructor(){super(),this.maxSize=500}set(e,t){t.lastAccessed=Date.now(),super.set(e,t),this.size>this.maxSize&&this.gc()}get(e){const t=super.get(e);return t&&(t.lastAccessed=Date.now()),t}gc(){let e,t=1/0,a=0;for(const[o,n]of this.entries())n.lastAccessed<t&&(t=n.lastAccessed,e=a),a++;a=e;for(const t of this.keys()){if(0==a){e=t;break}a--}this.delete(e)}},e._tic=new e._TimedCache,e.textCache=(t,a)=>(a&&(e._tic.maxSize=a),void 0!==t&&(e._textCache=t),e._textCache),e._genTextImageKey=(t,a,o)=>t.slice(0,200)+e._textStyle+e._textSize+e._textFont+(e._doFill?e.ctx.fillStyle:"")+"_"+(e._doStroke&&e._strokeSet?e.ctx.lineWidth+e.ctx.strokeStyle+"_":"")+(a||"")+(o?"x"+o:""),e.createTextImage=(t,a,o)=>{let n=e._textCache;e._textCache=!0,e._genTextImage=!0,e.text(t,0,0,a,o),e._genTextImage=!1;let r=e._genTextImageKey(t,a,o);return e._textCache=n,e._tic.get(r)},e.text=(t,a,o,n,r)=>{if(void 0===t)return;if(t=t.toString(),e._da&&(a*=e._da,o*=e._da),!e._doFill&&!e._doStroke)return;let i,s,l,c,d,h,u,_,g=1,p=e.ctx.getTransform(),x=e._genTextImage||e._textCache&&(0!=p.b||0!=p.c);if(x){if(c=e._genTextImageKey(t,n,r),s=e._tic.get(c),s&&!e._genTextImage)return void e.textImage(s,a,o);l=e.createGraphics.call(e,1,1),i=l.ctx,g=e._pixelDensity}else i=e.ctx,d=a,h=o;i.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`;let m=t.split("\n");if(x){d=0,h=e._textLeading*m.length;let a=i.measureText(" ");u=a.fontBoundingBoxAscent,_=a.fontBoundingBoxDescent,r??=h+_,l.resizeCanvas(Math.ceil(i.measureText(t).width),Math.ceil(r)),i.fillStyle=e.ctx.fillStyle,i.strokeStyle=e.ctx.strokeStyle,i.lineWidth=e.ctx.lineWidth}let f=i.fillStyle;e._fillSet||(i.fillStyle="black");for(let t=0;t<m.length&&(e._doStroke&&e._strokeSet&&i.strokeText(m[t],d,h),e._doFill&&i.fillText(m[t],d,h),h+=e._textLeading,!(h>r));t++);e._fillSet||(i.fillStyle=f),x&&(s=l.get(),s._ascent=u,s._descent=_,e._tic.set(c,s),e._genTextImage||e.textImage(s,a,o))},e.textImage=(t,a,o)=>{let n=e._imageMode;e._imageMode="corner","center"==e.ctx.textAlign?a-=.5*t.width:"right"==e.ctx.textAlign&&(a-=t.width),"alphabetic"==e.ctx.textBaseline&&(o-=e._textLeading),"middle"==e.ctx.textBaseline?o-=t._descent+.5*t._ascent+e._textLeadDiff:"bottom"==e.ctx.textBaseline?o-=t._ascent+t._descent+e._textLeadDiff:"top"==e.ctx.textBaseline&&(o-=t._descent+e._textLeadDiff),e.image(t,a,o),e._imageMode=n},e.nf=(e,t,a)=>{let o=e<0,n=(e=Math.abs(e)).toFixed(a).split(".");n[0]=n[0].padStart(t,"0");let r=n.join(".");return o&&(r="-"+r),r}},Q5.modules.ai=e=>{e.askAI=(e="")=>{throw Error("Ask AI ✨ "+e)},e._aiErrorAssistance=async e=>{let t=e.message?.includes("Ask AI ✨");if(t||console.error(e),Q5.disableFriendlyErrors)return;!t&&Q5.errorTolerant||noLoop();let a=e.stack?.split("\n");if(!e.stack||a.length<=1)return;let o=1,n="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(o=0,n="@");a[o].indexOf("q5.js:")>=0;)o++;let r=a[o].split(n).at(-1);r=r.split(":");let i=parseInt(r.at(-2));t&&i++;let s=r.slice(0,-2).join(":"),l=s.split("/").at(-1);try{let a=(await(await fetch(s)).text()).split("\n"),o=a[i-1].trim(),n="",r=1;for(;n.length<1600&&(i-r>=0&&(n=a[i-r].trim()+"\n"+n),i+r<a.length);)n+=a[i+r].trim()+"\n",r++;let c="https://chatgpt.com/?q=q5.js+"+(t&&e.message.length>10?e.message.slice(10):"Whats+wrong+with+this+line%3F+short+answer")+(t?"":"%0A%0A"+encodeURIComponent(e.name+": "+e.message))+"%0A%0ALine%3A+"+encodeURIComponent(o)+"%0A%0AExcerpt+for+context%3A%0A%0A"+encodeURIComponent(n);t||console.log("Error in "+l+" on line "+i+":\n\n"+o),console.warn("Ask AI ✨ "+c),t&&window.open(c,"_blank")}catch(e){}}},Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e._colorMode="rgb",Q5.supportsHDR?e.Color=Q5.ColorRGBA_P3:e.Color=Q5.ColorRGBA,e.colorMode=a=>{e._colorMode=a,"oklch"==a?t.Color=Q5.ColorOKLCH:"rgb"==a?"srgb"==e.canvas.colorSpace?t.Color=Q5.ColorRGBA:t.Color=Q5.ColorRGBA_P3:"srgb"==a&&(t.Color=Q5.ColorRGBA,e._colorMode="rgb")},e._basicColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],crimson:[220,20,60],cyan:[0,255,255],darkviolet:[148,0,211],gold:[255,215,0],green:[0,128,0],gray:[128,128,128],grey:[128,128,128],hotpink:[255,105,180],indigo:[75,0,130],khaki:[240,230,140],lightgreen:[144,238,144],lime:[0,255,0],magenta:[255,0,255],navy:[0,0,128],orange:[255,165,0],olive:[128,128,0],peachpuff:[255,218,185],pink:[255,192,203],purple:[128,0,128],red:[255,0,0],skyblue:[135,206,235],tan:[210,180,140],turquoise:[64,224,208],transparent:[0,0,0,0],white:[255,255,255],violet:[238,130,238],yellow:[255,255,0]},e.color=function(t,a,o,n){let r=e.Color;if(t._q5Color)return new r(...t.levels);let i=arguments;if(1==i.length){if("string"==typeof t)return"#"==t[0]?new r(parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16),9!=t.length?null:parseInt(t.slice(7,9),16)):e._basicColors[t]?new r(...e._basicColors[t]):new r(0,0,0);if(Array.isArray(t))return new r(...t)}if("rgb"==e._colorMode){if(1==i.length)return new r(t,t,t);if(2==i.length)return new r(t,t,t,a);if(3==i.length)return new r(t,a,o);if(4==i.length)return new r(t,a,o,n)}},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=e=>100*(.2126*e.r+.7152*e.g+.0722*e.b)/255,e.lerpColor=(t,a,o)=>{if("rgb"==e._colorMode)return new e.Color(e.constrain(e.lerp(t.r,a.r,o),0,255),e.constrain(e.lerp(t.g,a.g,o),0,255),e.constrain(e.lerp(t.b,a.b,o),0,255),e.constrain(e.lerp(t.a,a.a,o),0,255));{let n=a.h-t.h;n>180&&(n-=360),n<-180&&(n+=360);let r=t.h+o*n;return r<0&&(r+=360),r>360&&(r-=360),new e.Color(e.constrain(e.lerp(t.l,a.l,o),0,100),e.constrain(e.lerp(t.c,a.c,o),0,100),r,e.constrain(e.lerp(t.a,a.a,o),0,255))}}},Q5.Color=class{constructor(){this._q5Color=!0}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,a,o){super(),this.l=e,this.c=t,this.h=a,this.a=o??1}toString(){return`color(oklch ${this.l} ${this.c} ${this.h} / ${this.a})`}},Q5.ColorRGBA=class extends Q5.Color{constructor(e,t,a,o){super(),this.r=e,this.g=t,this.b=a,this.a=o??255}setRed(e){this.r=e}setGreen(e){this.g=e}setBlue(e){this.b=e}setAlpha(e){this.a=e}get levels(){return[this.r,this.g,this.b,this.a]}toString(){return`rgb(${this.r} ${this.g} ${this.b} / ${this.a/255})`}},Q5.ColorRGBA_P3=class extends Q5.ColorRGBA{constructor(e,t,a,o){super(e,t,a,o),this._edited=!0}get r(){return this._r}set r(e){this._r=e,this._edited=!0}get g(){return this._g}set g(e){this._g=e,this._edited=!0}get b(){return this._b}set b(e){this._b=e,this._edited=!0}get a(){return this._a}set a(e){this._a=e,this._edited=!0}toString(){if(this._edited){let e=(this._r/255).toFixed(3),t=(this._g/255).toFixed(3),a=(this._b/255).toFixed(3),o=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${a} / ${o})`,this._edited=!1}return this._css}},Q5.modules.display=e=>{if(!e.canvas||"graphics"==e._scope)return;let t=e.canvas;0!=Q5._instanceCount||Q5._nodejs||document.head.insertAdjacentHTML("beforeend","<style>\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\n.q5Canvas {\n\toutline: none;\n\t-webkit-touch-callout: none;\n\t-webkit-text-size-adjust: none;\n\t-webkit-user-select: none;\n\toverscroll-behavior: none;\n}\n.q5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.q5-centered,\n.q5-maxed,\n.q5-fullscreen {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.q5-centered,\nmain.q5-maxed,\n.q5-fullscreen {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>"),e._adjustDisplay=()=>{let a=t.style,o=t.parentElement;a&&o&&t.displayMode&&("pixelated"==t.renderQuality&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),"normal"==t.displayMode?(o.classList.remove("q5-centered","q5-maxed","q5-fullscreen"),a.width=t.w*t.displayScale+"px",a.height=t.h*t.displayScale+"px"):(o.classList.add("q5-"+t.displayMode),o=o.getBoundingClientRect(),t.w/t.h>o.width/o.height?("centered"==t.displayMode?(a.width=t.w*t.displayScale+"px",a.maxWidth="100%"):a.width="100%",a.height="auto",a.maxHeight=""):(a.width="auto",a.maxWidth="","centered"==t.displayMode?(a.height=t.h*t.displayScale+"px",a.maxHeight="100%"):a.height="100%")))},e.displayMode=(a="normal",o="default",n=1)=>{"string"==typeof n&&(n=parseFloat(n.slice(1))),Object.assign(t,{displayMode:a,renderQuality:o,displayScale:n}),e._adjustDisplay()}},Q5.modules.input=(e,t)=>{if("graphics"==e._scope)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.mouseButton=null,e.keyIsPressed=!1,e.mouseIsPressed=!1,e.key=null,e.keyCode=null,e.UP_ARROW=38,e.DOWN_ARROW=40,e.LEFT_ARROW=37,e.RIGHT_ARROW=39,e.SHIFT=16,e.TAB=9,e.BACKSPACE=8,e.ENTER=e.RETURN=13,e.ALT=e.OPTION=18,e.CONTROL=17,e.DELETE=46,e.ESCAPE=27,e.ARROW="default",e.CROSS="crosshair",e.HAND="pointer",e.MOVE="move",e.TEXT="text";let a={},o=[e.LEFT,e.CENTER,e.RIGHT],n=e.canvas;function r(t){const a=e.canvas.getBoundingClientRect(),o=e.canvas.scrollWidth/e.width||1,n=e.canvas.scrollHeight/e.height||1;return{x:(t.clientX-a.left)/o,y:(t.clientY-a.top)/n,id:t.identifier}}if(e._startAudio=()=>{e.getAudioContext&&"suspended"==e.getAudioContext()?.state&&e.userStartAudio()},e._updateMouse=a=>{if(a.changedTouches)return;let o=e.canvas.getBoundingClientRect(),n=e.canvas.scrollWidth/e.width||1,r=e.canvas.scrollHeight/e.height||1;t.mouseX=(a.clientX-o.left)/n,t.mouseY=(a.clientY-o.top)/r},e._onmousedown=a=>{e._startAudio(),e._updateMouse(a),t.mouseIsPressed=!0,t.mouseButton=o[a.button],e.mousePressed(a)},e._onmousemove=t=>{e._updateMouse(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t)},e._onmouseup=a=>{e._updateMouse(a),t.mouseIsPressed=!1,e.mouseReleased(a)},e._onclick=a=>{e._updateMouse(a),t.mouseIsPressed=!0,e.mouseClicked(a),t.mouseIsPressed=!1},n.addEventListener("mousedown",(t=>e._onmousedown(t))),n.addEventListener("mouseup",(t=>e._onmouseup(t))),n.addEventListener("click",(t=>e._onclick(t))),e.cursor=(t,a,o)=>{let n="";t.includes(".")&&(t=`url("${t}")`,n=", auto"),void 0!==a&&(t+=" "+a+" "+o),e.canvas.style.cursor=t+n},e.noCursor=()=>{e.canvas.style.cursor="none"},e.requestPointerLock=document.body?.requestPointerLock,e.exitPointerLock=document.exitPointerLock,e._onkeydown=o=>{o.repeat||(e._startAudio,t.keyIsPressed=!0,t.key=o.key,t.keyCode=o.keyCode,a[e.keyCode]=a[e.key]=!0,e.keyPressed(o),1==o.key.length&&e.keyTyped(o))},e._onkeyup=o=>{t.keyIsPressed=!1,t.key=o.key,t.keyCode=o.keyCode,a[e.keyCode]=a[e.key]=!1,e.keyReleased(o)},e.keyIsDown=e=>!!a[e],e._ontouchstart=a=>{e._startAudio(),t.touches=[...a.touches].map(r),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,t.mouseIsPressed=!0,t.mouseButton=e.LEFT,e.mousePressed(a)||a.preventDefault()),e.touchStarted(a)||a.preventDefault()},e._ontouchmove=a=>{t.touches=[...a.touches].map(r),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,e.mouseDragged(a)||a.preventDefault()),e.touchMoved(a)||a.preventDefault()},e._ontouchend=a=>{t.touches=[...a.touches].map(r),e._isTouchAware||e.touches.length||(t.mouseIsPressed=!1,e.mouseReleased(a)||a.preventDefault()),e.touchEnded(a)||a.preventDefault()},n.addEventListener("touchstart",(t=>e._ontouchstart(t))),n.addEventListener("touchmove",(t=>e._ontouchmove(t))),n.addEventListener("touchcancel",(t=>e._ontouchend(t))),n.addEventListener("touchend",(t=>e._ontouchend(t))),window){let t=window.addEventListener;t("mousemove",(t=>e._onmousemove(t)),!1),t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1)}},Q5.modules.math=(e,t)=>{function a(){let e,t,a=4294967295;return{setSeed(o){e=t=(o??Math.random()*a)>>>0},getSeed:()=>t,rand:()=>(e^=e<<17,e^=e>>13,e^=e<<5,(e>>>0)/a)}}e.DEGREES="degrees",e.RADIANS="radians",e.PI=Math.PI,e.HALF_PI=Math.PI/2,e.QUARTER_PI=Math.PI/4,e.abs=Math.abs,e.ceil=Math.ceil,e.exp=Math.exp,e.floor=Math.floor,e.loge=Math.log,e.mag=Math.hypot,e.max=Math.max,e.min=Math.min,e.round=Math.round,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2,e.angleMode=t=>e._angleMode=t,e._DEGTORAD=Math.PI/180,e._RADTODEG=180/Math.PI,e.degrees=t=>t*e._RADTODEG,e.radians=t=>t*e._DEGTORAD,e.map=(e,t,a,o,n,r)=>{let i=o+1*(e-t)/(a-t)*(n-o);return r?o<n?Math.min(Math.max(i,o),n):Math.min(Math.max(i,n),o):i},e.lerp=(e,t,a)=>e*(1-a)+t*a,e.constrain=(e,t,a)=>Math.min(Math.max(e,t),a),e.dist=function(){let e=arguments;return 4==e.length?Math.hypot(e[0]-e[2],e[1]-e[3]):Math.hypot(e[0]-e[3],e[1]-e[4],e[2]-e[5])},e.norm=(t,a,o)=>e.map(t,a,o,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.sin(t)),e.cos=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.cos(t)),e.tan=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.tan(t)),e.asin=t=>{let a=Math.asin(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.acos=t=>{let a=Math.acos(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.atan=t=>{let a=Math.atan(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.atan2=(t,a)=>{let o=Math.atan2(t,a);return"degrees"==e._angleMode&&(o=e.degrees(o)),o};let o=a();o.setSeed(),e.randomSeed=e=>o.setSeed(e),e.random=(e,t)=>void 0===e?o.rand():"number"==typeof e?void 0!==t?o.rand()*(t-e)+e:o.rand()*e:e[Math.trunc(e.length*o.rand())],e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,a;return{setSeed(o){a=t=(o??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(a=(1664525*a+1013904223)%e,a/e)}}():t==e.SHR3&&(o=a()),o.setSeed()};var n=new function(){var e,t,a,n=new Array(128),r=new Array(256),i=new Array(128),s=new Array(128),l=new Array(256),c=new Array(256),d=()=>4294967296*o.rand()-2147483648,h=()=>.5+2.328306e-10*(d()|0),u=()=>{for(var t,o,r,l,c=3.44262;;){if(t=a*i[e],0==e){do{r=h(),l=h(),t=.2904764*-Math.log(r),o=-Math.log(l)}while(o+o<t*t);return a>0?c+t:-c-t}if(s[e]+h()*(s[e-1]-s[e])<Math.exp(-.5*t*t))return t;if(a=d(),e=127&a,Math.abs(a)<n[e])return a*i[e]}},_=()=>{for(var a;;){if(0==e)return 7.69711-Math.log(h());if(a=t*l[e],c[e]+h()*(c[e-1]-c[e])<Math.exp(-a))return a;if((t=d())<r[e=255&t])return t*l[e]}};this.SHR3=d,this.UNI=h,this.RNOR=()=>(a=d(),e=127&a,Math.abs(a)<n[e]?a*i[e]:u()),this.REXP=()=>(t=d()>>>0)<n[e=255&t]?t*l[e]:_(),this.zigset=()=>{var e,t,a=2147483648,o=4294967296,d=3.442619855899,h=d,u=.00991256303526217,_=7.697117470131487,g=_,p=.003949659822581572;for(e=u/Math.exp(-.5*d*d),n[0]=Math.floor(d/e*a),n[1]=0,i[0]=e/a,i[127]=d/a,s[0]=1,s[127]=Math.exp(-.5*d*d),t=126;t>=1;t--)d=Math.sqrt(-2*Math.log(u/d+Math.exp(-.5*d*d))),n[t+1]=Math.floor(d/h*a),h=d,s[t]=Math.exp(-.5*d*d),i[t]=d/a;for(e=p/Math.exp(-_),r[0]=Math.floor(_/e*o),r[1]=0,l[0]=e/o,l[255]=_/o,c[0]=1,c[255]=Math.exp(-_),t=254;t>=1;t--)_=-Math.log(p/_+Math.exp(-_)),r[t+1]=Math.floor(_/g*o),g=_,c[t]=Math.exp(-_),l[t]=_/o}};let r;n.hasInit=!1,e.randomGaussian=(e,t)=>(n.hasInit||(n.zigset(),n.hasInit=!0),n.RNOR()*t+e),e.randomExponential=()=>(n.hasInit||(n.zigset(),n.hasInit=!0),n.REXP()),e.PERLIN="perlin",e.SIMPLEX="simplex",e.BLOCKY="blocky",e.Noise=Q5.PerlinNoise,e.noiseMode=e=>{t.Noise=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],r=null},e.noiseSeed=t=>{r=new e.Noise(t)},e.noise=(t=0,a=0,o=0)=>(r??=new e.Noise,r.noise(t,a,o)),e.noiseDetail=(t,a)=>{r??=new e.Noise,t>0&&(r.octaves=t),a>0&&(r.falloff=a)}},Q5.Noise=class{constructor(){}},Q5.PerlinNoise=class extends Q5.Noise{constructor(e){super(),this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.octaves=1,this.falloff=.5,this.p=null==e?Array.from({length:256},(()=>Math.floor(256*Math.random()))):this.seedPermutation(e),this.p=this.p.concat(this.p)}seedPermutation(e){let t,a,o=[];for(let e=0;e<256;e++)o[e]=e;for(let n=255;n>0;n--)t=(e=16807*e%2147483647)%(n+1),a=o[n],o[n]=o[t],o[t]=a;return o}dot(e,t,a,o){return e[0]*t+e[1]*a+e[2]*o}mix(e,t,a){return(1-a)*e+a*t}fade(e){return e*e*e*(e*(6*e-15)+10)}noise(e,t,a){let o=this,n=0,r=1,i=1,s=0;for(let l=0;l<o.octaves;l++){const l=255&Math.floor(e*r),c=255&Math.floor(t*r),d=255&Math.floor(a*r),h=e*r-Math.floor(e*r),u=t*r-Math.floor(t*r),_=a*r-Math.floor(a*r),g=o.fade(h),p=o.fade(u),x=o.fade(_),m=o.p[l]+c,f=o.p[m]+d,v=o.p[m+1]+d,y=o.p[l+1]+c,w=o.p[y]+d,M=o.p[y+1]+d,C=o.mix(o.dot(o.grad3[o.p[f]%12],h,u,_),o.dot(o.grad3[o.p[w]%12],h-1,u,_),g),S=o.mix(o.dot(o.grad3[o.p[v]%12],h,u-1,_),o.dot(o.grad3[o.p[M]%12],h-1,u-1,_),g),b=o.mix(o.dot(o.grad3[o.p[f+1]%12],h,u,_-1),o.dot(o.grad3[o.p[w+1]%12],h-1,u,_-1),g),R=o.mix(o.dot(o.grad3[o.p[v+1]%12],h,u-1,_-1),o.dot(o.grad3[o.p[M+1]%12],h-1,u-1,_-1),g),E=o.mix(C,S,p),I=o.mix(b,R,p);n+=o.mix(E,I,x)*i,s+=i,i*=o.falloff,r*=2}return(n/s+1)/2}},Q5.modules.sound=(e,t)=>{e.loadSound=(a,o)=>{t._preloadCount++,e.aud??=new window.AudioContext;let n=new Audio(a);return n.addEventListener("canplaythrough",(()=>{t._preloadCount--,o&&o(n)})),n.load(),n.setVolume=e=>n.volume=e,n.setLoop=e=>n.loop=e,n.panner=e.aud.createStereoPanner(),n.source=e.aud.createMediaElementSource(n),n.source.connect(n.panner),n.panner.connect(e.aud.destination),Object.defineProperty(n,"pan",{get:()=>n.panner.pan.value,set:e=>n.panner.pan.value=e}),n.setPan=e=>n.pan=e,n},e.getAudioContext=()=>e.aud,e.userStartAudio=()=>e.aud.resume()},Q5.modules.util=(e,t)=>{e._loadFile=(e,a,o)=>{t._preloadCount++;let n={};return fetch(e).then((e=>"json"==o?e.json():"text"==o?e.text():void 0)).then((e=>{t._preloadCount--,Object.assign(n,e),a&&a(e)})),n},e.loadStrings=(t,a)=>e._loadFile(t,a,"text"),e.loadJSON=(t,a)=>e._loadFile(t,a,"json"),"object"==typeof localStorage&&(e.storeItem=localStorage.setItem,e.getItem=localStorage.getItem,e.removeItem=localStorage.removeItem,e.clearStorage=localStorage.clear),e.year=()=>(new Date).getFullYear(),e.day=()=>(new Date).getDay(),e.hour=()=>(new Date).getHours(),e.minute=()=>(new Date).getMinutes(),e.second=()=>(new Date).getSeconds()},Q5.modules.vector=e=>{e.createVector=(t,a,o)=>new Q5.Vector(t,a,o,e)},Q5.Vector=class{constructor(e,t,a,o){this.x=e||0,this.y=t||0,this.z=a||0,this._$=o||window,this._cn=null,this._cnsq=null}set(e,t,a){this.x=e||0,this.y=t||0,this.z=a||0}copy(){return new Q5.Vector(this.x,this.y,this.z)}_arg2v(e,t,a){return void 0!==e.x?e:void 0!==t?{x:e,y:t,z:a||0}:{x:e,y:e,z:e}}_calcNorm(){this._cnsq=this.x*this.x+this.y*this.y+this.z*this.z,this._cn=Math.sqrt(this._cnsq)}add(){let e=this._arg2v(...arguments);return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}rem(){let e=this._arg2v(...arguments);return this.x%=e.x,this.y%=e.y,this.z%=e.z,this}sub(){let e=this._arg2v(...arguments);return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}mult(){let e=this._arg2v(...arguments);return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}div(){let e=this._arg2v(...arguments);return e.x?this.x/=e.x:this.x=0,e.y?this.y/=e.y:this.y=0,e.z?this.z/=e.z:this.z=0,this}mag(){return this._calcNorm(),this._cn}magSq(){return this._calcNorm(),this._cnsq}dot(){let e=this._arg2v(...arguments);return this.x*e.x+this.y*e.y+this.z*e.z}dist(){let e=this._arg2v(...arguments),t=this.x-e.x,a=this.y-e.y,o=this.z-e.z;return Math.sqrt(t*t+a*a+o*o)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,a=this.z*e.x-this.x*e.z,o=this.x*e.y-this.y*e.x;return this.x=t,this.y=a,this.z=o,this}normalize(){this._calcNorm();let e=this._cn;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._cn=1,this._cnsq=1,this}limit(e){this._calcNorm();let t=this._cn;if(t>e){let a=e/t;this.x*=a,this.y*=a,this.z*=a,this._cn=e,this._cnsq=e*e}return this}setMag(e){this._calcNorm();let t=e/this._cn;return this.x*=t,this.y*=t,this.z*=t,this._cn=e,this._cnsq=e*e,this}heading(){return this._$.atan2(this.y,this.x)}rotate(e){let t=this._$.cos(e),a=this._$.sin(e),o=this.x*t-this.y*a,n=this.x*a+this.y*t;return this.x=o,this.y=n,this}angleBetween(){let e=this._arg2v(...arguments),t=Q5.Vector.cross(this,e);return this._$.atan2(t.mag(),this.dot(e))*Math.sign(t.z||1)}lerp(){let e=[...arguments],t=this._arg2v(...e.slice(0,-1)),a=e[e.length-1];return this.x+=(t.x-this.x)*a,this.y+=(t.y-this.y)*a,this.z+=(t.z-this.z)*a,this}reflect(e){return e.normalize(),this.sub(e.mult(2*this.dot(e)))}array(){return[this.x,this.y,this.z]}equals(e,t){return t??=Number.EPSILON||0,Math.abs(e.x-this.x)<t&&Math.abs(e.y-this.y)<t&&Math.abs(e.z-this.z)<t}fromAngle(e,t){return void 0===t&&(t=1),this._cn=t,this._cnsq=t*t,this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this.z=0,this}fromAngles(e,t,a){void 0===a&&(a=1),this._cn=a,this._cnsq=a*a;const o=this._$.cos(t),n=this._$.sin(t),r=this._$.cos(e),i=this._$.sin(e);return this.x=a*i*n,this.y=-a*r,this.z=a*i*o,this}random2D(){return this._cn=this._cnsq=1,this.fromAngle(Math.random()*Math.PI*2)}random3D(){return this._cn=this._cnsq=1,this.fromAngles(Math.random()*Math.PI*2,Math.random()*Math.PI*2)}toString(){return`[${this.x}, ${this.y}, ${this.z}]`}},Q5.Vector.add=(e,t)=>e.copy().add(t),Q5.Vector.cross=(e,t)=>e.copy().cross(t),Q5.Vector.dist=(e,t)=>Math.hypot(e.x-t.x,e.y-t.y,e.z-t.z),Q5.Vector.div=(e,t)=>e.copy().div(t),Q5.Vector.dot=(e,t)=>e.copy().dot(t),Q5.Vector.equals=(e,t,a)=>e.equals(t,a),Q5.Vector.lerp=(e,t,a)=>e.copy().lerp(t,a),Q5.Vector.limit=(e,t)=>e.copy().limit(t),Q5.Vector.heading=e=>this._$.atan2(e.y,e.x),Q5.Vector.magSq=e=>e.x*e.x+e.y*e.y+e.z*e.z,Q5.Vector.mag=e=>Math.sqrt(Q5.Vector.magSq(e)),Q5.Vector.mult=(e,t)=>e.copy().mult(t),Q5.Vector.normalize=e=>e.copy().normalize(),Q5.Vector.rem=(e,t)=>e.copy().rem(t),Q5.Vector.sub=(e,t)=>e.copy().sub(t);for(let e of["fromAngle","fromAngles","random2D","random3D"])Q5.Vector[e]=(t,a,o)=>(new Q5.Vector)[e](t,a,o);
8
+ function Q5(e,t){let a,o=this;if(o._q5=!0,o._scope=e,o._parent=t,o._preloadCount=0,e??="global","auto"==e){if(!window.setup&&!window.draw)return;e="global"}"global"==e&&(Q5._hasGlobal=o._isGlobal=!0,a=Q5._nodejs?global:window);let n=new Proxy(o,{set:(e,t,n)=>(o[t]=n,o._isGlobal&&(a[t]=n),!0)});o.canvas=o.ctx=o.drawingContext=null,o.pixels=[];let r=null;o.frameCount=0,o.deltaTime=16,o._targetFrameRate=0,o._targetFrameDuration=16.666666666666668,o._frameRate=o._fps=60,o._loop=!0;let s=0;function i(e){let t=e||performance.now();if(o._lastFrameTime??=t-o._targetFrameDuration,o._shouldResize&&(o.windowResized(),o._shouldResize=!1),o._loop)r=l(i);else if(o.frameCount&&!o._redraw)return;if(r&&o.frameCount){if(t-o._lastFrameTime<o._targetFrameDuration-1)return}n.deltaTime=t-o._lastFrameTime,o._frameRate=1e3/o.deltaTime,n.frameCount++;let a=performance.now();for(let e of Q5.prototype._methods.pre)e.call(o);o.ctx&&o.ctx.save(),o.draw();for(let e of Q5.prototype._methods.post)e.call(o);o.ctx&&(o.ctx.restore(),o.resetMatrix()),n.pmouseX=o.mouseX,n.pmouseY=o.mouseY,o._lastFrameTime=t;let s=performance.now();o._fps=Math.round(1e3/(s-a))}o.millis=()=>performance.now()-s,o.noCanvas=()=>{o.canvas?.remove&&o.canvas.remove(),o.canvas=0,n.ctx=n.drawingContext=0},window&&(o.windowWidth=window.innerWidth,o.windowHeight=window.innerHeight,o.deviceOrientation=window.screen?.orientation?.type),o._incrementPreload=()=>n._preloadCount++,o._decrementPreload=()=>n._preloadCount--,o.noLoop=()=>{o._loop=!1,r=null},o.loop=()=>{o._loop=!0,null==r&&i()},o.redraw=(e=1)=>{o._redraw=!0;for(let t=0;t<e;t++)i();o._redraw=!1},o.remove=()=>{o.noLoop(),o.canvas.remove()},o.frameRate=e=>(e&&(o._targetFrameRate=e,o._targetFrameDuration=1e3/e),o._frameRate),o.getTargetFrameRate=()=>o._targetFrameRate,o.getFPS=()=>o._fps,o.Element=function(e){this.elt=e},o._elements=[],o.TWO_PI=o.TAU=2*Math.PI,o.log=o.print=console.log,o.describe=()=>{};for(let e in Q5.modules)Q5.modules[e](o,n);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(o[e]=Q5[e]);"global"==e&&(Object.assign(Q5,o),delete Q5.Q5);for(let e of Q5.prototype._methods.init)e.call(o);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof o[e]&&(o[e]=t.bind(o));if("global"==e){let e=Object.getOwnPropertyNames(o);for(let t of e)"_"!=t[0]&&(a[t]=o[t])}if("function"==typeof e&&e(o),"graphics"==e)return;Q5._instanceCount++;let l=window.requestAnimationFrame||function(e){const t=o._lastFrameTime+o._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},c=a||o;o._isTouchAware=c.touchStarted||c.touchMoved||c.mouseReleased;let d=c.preload,h=["setup","draw","preload","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized"];for(let e of h)c[e]?o._isGlobal&&(o[e]=()=>{try{return c[e]()}catch(e){o._aiErrorAssistance?o._aiErrorAssistance(e):console.error(e)}}):o[e]=()=>{};async function u(){if(o._startDone=!0,o._preloadCount>0)return l(u);s=performance.now(),await o.setup(),o.frameCount||(null===o.ctx&&o.createCanvas(100,100),o._setupDone=!0,o.ctx&&o.resetMatrix(),l(i))}(o.setup||o.draw)&&(o._startDone=!1,arguments.length&&"namespace"!=e||d?(o.preload(),u()):(c.preload=o.preload=()=>{o._startDone||u()},setTimeout(o.preload,32)))}Q5.modules={},Q5._nodejs="object"==typeof process,Q5._instanceCount=0,Q5._friendlyError=(e,t)=>{throw Error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.prototype._methods={init:[],pre:[],post:[],remove:[]},Q5.prototype.registerMethod=(e,t)=>Q5.prototype._methods[e].push(t),Q5.prototype.registerPreloadMethod=(e,t)=>Q5.prototype[e]=t[e],Q5._nodejs?global.p5??=global.Q5=Q5:"object"==typeof window?window.p5??=window.Q5=Q5:global.window=0,"object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||new Q5("auto")})),Q5.modules.q2d_canvas=(e,t)=>{e._OffscreenCanvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._nodejs?Q5._createNodeJSCanvas&&(t.canvas=Q5._createNodeJSCanvas(100,100)):"image"!=e._scope&&"graphics"!=e._scope||(t.canvas=new e._OffscreenCanvas(100,100)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas());let a=e.canvas;if(a.width=e.width=100,a.height=e.height=100,a&&"graphics"!=e._scope&&"image"!=e._scope){e._setupDone=!1;let r=e._parent;function o(){r??=document.getElementsByTagName("main")[0],r||(r=document.createElement("main"),document.body.append(r)),a.parent(r)}r&&"string"==typeof r&&(r=document.getElementById(r)),a.parent=t=>{function o(){e.frameCount>1&&(e._shouldResize=!0,e._adjustDisplay())}"string"==typeof t&&(t=document.getElementById(t)),t.append(a),"function"==typeof ResizeObserver?(e._ro&&e._ro.disconnect(),e._ro=new ResizeObserver(o),e._ro.observe(r)):e.frameCount||window.addEventListener("resize",o)},document.body?o():document.addEventListener("DOMContentLoaded",o)}function n(o,n){o??=window.innerWidth,n??=window.innerHeight;let r,s=function(){let t={};for(let a in e.ctx)"function"!=typeof e.ctx[a]&&(t[a]=e.ctx[a]);return delete t.canvas,t}();if(e.frameCount){r=new e._OffscreenCanvas(a.width,a.height),r.w=a.w,r.h=a.h,r.getContext("2d").drawImage(a,0,0)}a.width=Math.ceil(o*e._pixelDensity),a.height=Math.ceil(n*e._pixelDensity),a.w=o,a.h=n,a.hw=o/2,a.hh=n/2;for(let t in s)e.ctx[t]=s[t];e.ctx.scale(e._pixelDensity,e._pixelDensity),e.frameCount&&e.ctx.drawImage(r,0,0,r.w,r.h),e._da?e.flexibleCanvas(e._dau):(t.width=o,t.height=n),0!=e.frameCount&&e._adjustDisplay()}e._adjustDisplay=()=>{a.style&&(a.style.width=a.w+"px",a.style.height=a.h+"px")},e.createCanvas=function(o,n,r,s){if("webgl"==r)throw Error("webgl renderer is not supported in q5, use '2d'");"object"==typeof r&&(s=r),t.width=a.width=a.w=o||window.innerWidth,t.height=a.height=a.h=n||window.innerHeight,a.hw=o/2,a.hh=n/2,a.renderer="2d";let i=Object.assign({},Q5.canvasOptions);if(s&&Object.assign(i,s),t.ctx=t.drawingContext=a.getContext("2d",i),Object.assign(a,i),"rgb"==e._colorMode&&e.colorMode("rgb"),"image"!=e._scope&&(e._defaultStyle(),e._da=0),e.ctx.save(),"image"!=e._scope){let t=e.displayDensity();"graphics"==e._scope?t=this._pixelDensity:window.IntersectionObserver&&new IntersectionObserver((e=>{a.visible=e[0].isIntersecting})).observe(a),e.pixelDensity(Math.ceil(t))}else this._pixelDensity=1;return e.displayMode?e.displayMode():e._adjustDisplay(),a},e._createCanvas=e.createCanvas,"image"!=e._scope&&(e._defaultStyle=()=>{e.ctx.fillStyle="white",e.ctx.strokeStyle="black",e.ctx.lineCap="round",e.ctx.lineJoin="miter",e.ctx.textAlign="left"},e.resizeCanvas=(e,t)=>{e==a.w&&t==a.h||n(e,t)},e._pixelDensity=1,e.displayDensity=()=>window.devicePixelRatio,e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,n(a.w,a.h),t):e._pixelDensity,"image"!=e._scope&&(e.fullscreen=e=>{if(void 0===e)return document.fullscreenElement;e?document.body.requestFullscreen():document.body.exitFullscreen()},e.flexibleCanvas=(o=400)=>{o?(e._da=a.width/(o*e._pixelDensity),t.width=e._dau=o,t.height=a.h/a.w*o):e._da=0},e.translate=(t,a)=>{e._da&&(t*=e._da,a*=e._da),e.ctx.translate(t,a)},e.rotate=t=>{"degrees"==e._angleMode&&(t=e.radians(t)),e.ctx.rotate(t)},e.scale=(t,a)=>{a??=t,e.ctx.scale(t,a)},e.opacity=t=>e.ctx.globalAlpha=t,e.applyMatrix=(t,a,o,n,r,s)=>e.ctx.transform(t,a,o,n,r,s),e.shearX=t=>e.ctx.transform(1,0,e.tan(t),1,0,0),e.shearY=t=>e.ctx.transform(1,e.tan(t),0,1,0,0),e.resetMatrix=()=>{e.ctx.resetTransform(),e.ctx.scale(e._pixelDensity,e._pixelDensity)},e._styleNames=["_doStroke","_doFill","_strokeSet","_fillSet","_tint","_imageMode","_rectMode","_ellipseMode","_textFont","_textLeading","_leadingSet","_textSize","_textAlign","_textBaseline","_textStyle","_textWrap"],e._styles=[],e.push=e.pushMatrix=()=>{e.ctx.save();let t={};for(let a of e._styleNames)t[a]=e[a];e._styles.push(t)},e.pop=e.popMatrix=()=>{e.ctx.restore();let t=e._styles.pop();for(let a of e._styleNames)e[a]=t[a]},e.createCapture=e=>{var t=document.createElement("video");return t.playsinline="playsinline",t.autoplay="autoplay",navigator.mediaDevices.getUserMedia(e).then((e=>{t.srcObject=e})),t.style.position="absolute",t.style.opacity=1e-5,t.style.zIndex=-1e3,document.body.append(t),t},e.createGraphics=function(t,a,o){let n=new Q5("graphics");return o??={},o.alpha??=!0,o.colorSpace??=e.canvas.colorSpace,n._createCanvas.call(e,t,a,o),n},window&&"graphics"!=e._scope&&window.addEventListener("resize",(()=>{e._shouldResize=!0,t.windowWidth=window.innerWidth,t.windowHeight=window.innerHeight,t.deviceOrientation=window.screen?.orientation?.type}))))},Q5.canvasOptions={alpha:!1,colorSpace:"display-p3"},window.matchMedia&&matchMedia("(dynamic-range: high) and (color-gamut: p3)").matches?Q5.supportsHDR=!0:Q5.canvasOptions.colorSpace="srgb",Q5.modules.q2d_drawing=e=>{e.CHORD=0,e.PIE=1,e.OPEN=2,e.RADIUS="radius",e.CORNER="corner",e.CORNERS="corners",e.ROUND="round",e.SQUARE="butt",e.PROJECT="square",e.MITER="miter",e.BEVEL="bevel",e.CLOSE=1,e.CENTER="center",e.LEFT="left",e.RIGHT="right",e.TOP="top",e.BOTTOM="bottom",e.LANDSCAPE="landscape",e.PORTRAIT="portrait",e.BLEND="source-over",e.REMOVE="destination-out",e.ADD="lighter",e.DARKEST="darken",e.LIGHTEST="lighten",e.DIFFERENCE="difference",e.SUBTRACT="subtract",e.EXCLUSION="exclusion",e.MULTIPLY="multiply",e.SCREEN="screen",e.REPLACE="copy",e.OVERLAY="overlay",e.HARD_LIGHT="hard-light",e.SOFT_LIGHT="soft-light",e.DODGE="color-dodge",e.BURN="color-burn",e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=e.CENTER,e._rectMode=e.CORNER,e._curveDetail=20,e._curveAlpha=0;let t=!0,a=[];function o(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}function n(t,a,n,r,s,i,l,c){if(!e._doFill&&!e._doStroke)return;let d="degrees"==e._angleMode,h=d?360:e.TAU;if((s%=h)<0&&(s+=h),(i%=h)<0&&(i+=h),0!=s||0!=i){if(s>i&&([s,i]=[i,s]),e.ctx.beginPath(),n==r)d&&(s=e.radians(s),i=e.radians(i)),e.ctx.arc(t,a,n/2,s,i);else{for(let o=0;o<c+1;o++){let l=o/c,d=e.lerp(s,i,l),h=e.cos(d)*n/2,u=e.sin(d)*r/2;e.ctx[o?"lineTo":"moveTo"](t+h,a+u)}l==e.CHORD?e.ctx.closePath():l==e.PIE&&(e.ctx.lineTo(t,a),e.ctx.closePath())}o()}}function r(t,a,n,r){(e._doFill||e._doStroke)&&(e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.ellipse(t,a,n/2,r/2,0,0,e.TAU),o())}function s(t,a,n,r,i,l,c,d){if(!e._doFill&&!e._doStroke)return;if(void 0===i)return function(t,a,n,r){e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.rect(t,a,n,r),o()}(t,a,n,r);if(void 0===l)return s(t,a,n,r,i,i,i,i);e._da&&(t*=e._da,a*=e._da,n*=e._da,r*=e._da,i*=e._da,l*=e._da,d*=e._da,c*=e._da);const h=Math.min(Math.abs(r),Math.abs(n))/2;i=Math.min(h,i),l=Math.min(h,l),d=Math.min(h,d),c=Math.min(h,c),e.ctx.beginPath(),e.ctx.moveTo(t+i,a),e.ctx.arcTo(t+n,a,t+n,a+r,l),e.ctx.arcTo(t+n,a+r,t,a+r,c),e.ctx.arcTo(t,a+r,t,a,d),e.ctx.arcTo(t,a,t+n,a,i),e.ctx.closePath(),o()}function i(){a=[]}e.strokeWeight=t=>{t||(e._doStroke=!1),e._da&&(t*=e._da),e.ctx.lineWidth=t||1e-4},e.stroke=function(t){if(e._doStroke=!0,e._strokeSet=!0,Q5.Color&&(t._q5Color||"string"==typeof t?e._namedColors[t]&&(t=e.color(...e._namedColors[t])):t=e.color(...arguments),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=t.toString()},e.noStroke=()=>e._doStroke=!1,e.fill=function(t){if(e._doFill=!0,e._fillSet=!0,Q5.Color&&(t._q5Color||"string"==typeof t?e._namedColors[t]&&(t=e.color(...e._namedColors[t])):t=e.color(...arguments),t.a<=0))return e._doFill=!1;e.ctx.fillStyle=t.toString()},e.noFill=()=>e._doFill=!1,e.blendMode=t=>e.ctx.globalCompositeOperation=t,e.strokeCap=t=>e.ctx.lineCap=t,e.strokeJoin=t=>e.ctx.lineJoin=t,e.ellipseMode=t=>e._ellipseMode=t,e.rectMode=t=>e._rectMode=t,e.curveDetail=t=>e._curveDetail=t,e.curveAlpha=t=>e._curveAlpha=t,e.curveTightness=t=>e._curveAlpha=t,e.clear=()=>{e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height)},e.background=function(t){if(t.canvas)return e.image(t,0,0,e.width,e.height);e.ctx.save(),e.ctx.resetTransform(),Q5.Color&&(t._q5Color||"string"==typeof t?e._namedColors[t]&&(t=e.color(...e._namedColors[t])):t=e.color(...arguments)),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e.line=(t,a,o,n)=>{e._doStroke&&(e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,a),e.ctx.lineTo(o,n),e.ctx.stroke())},e.arc=(t,a,o,r,s,i,l,c=25)=>{if(s==i)return e.ellipse(t,a,o,r);l??=e.PIE,e._ellipseMode==e.CENTER?n(t,a,o,r,s,i,l,c):e._ellipseMode==e.RADIUS?n(t,a,2*o,2*r,s,i,l,c):e._ellipseMode==e.CORNER?n(t+o/2,a+r/2,o,r,s,i,l,c):e._ellipseMode==e.CORNERS&&n((t+o)/2,(a+r)/2,o-t,r-a,s,i,l,c)},e.ellipse=(t,a,o,n)=>{n??=o,e._ellipseMode==e.CENTER?r(t,a,o,n):e._ellipseMode==e.RADIUS?r(t,a,2*o,2*n):e._ellipseMode==e.CORNER?r(t+o/2,a+n/2,o,n):e._ellipseMode==e.CORNERS&&r((t+o)/2,(a+n)/2,o-t,n-a)},e.circle=(t,a,n)=>{e._ellipseMode==e.CENTER?(e._da&&(t*=e._da,a*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.arc(t,a,n/2,0,e.TAU),o()):e.ellipse(t,a,n,n)},e.point=(t,a)=>{t.x&&(a=t.y,t=t.x),e._da&&(t*=e._da,a*=e._da),e.ctx.save(),e.ctx.beginPath(),e.ctx.arc(t,a,e.ctx.lineWidth/2,0,e.TAU),e.ctx.fillStyle=e.ctx.strokeStyle,e.ctx.fill(),e.ctx.restore()},e.rect=(t,a,o,n=o,r,i,l,c)=>{e._rectMode==e.CENTER?s(t-o/2,a-n/2,o,n,r,i,l,c):e._rectMode==e.RADIUS?s(t-o,a-n,2*o,2*n,r,i,l,c):e._rectMode==e.CORNER?s(t,a,o,n,r,i,l,c):e._rectMode==e.CORNERS&&s(t,a,o-t,n-a,r,i,l,c)},e.square=(t,a,o,n,r,s,i)=>e.rect(t,a,o,o,n,r,s,i),e.beginShape=()=>{i(),e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),i(),t=!0},e.endContour=()=>{i(),t=!0},e.vertex=(a,o)=>{e._da&&(a*=e._da,o*=e._da),i(),t?e.ctx.moveTo(a,o):e.ctx.lineTo(a,o),t=!1},e.bezierVertex=(t,a,o,n,r,s)=>{e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da,r*=e._da,s*=e._da),i(),e.ctx.bezierCurveTo(t,a,o,n,r,s)},e.quadraticVertex=(t,a,o,n)=>{e._da&&(t*=e._da,a*=e._da,o*=e._da,n*=e._da),i(),e.ctx.quadraticCurveTo(t,a,o,n)},e.bezier=(t,a,o,n,r,s,i,l)=>{e.beginShape(),e.vertex(t,a),e.bezierVertex(o,n,r,s,i,l),e.endShape()},e.triangle=(t,a,o,n,r,s)=>{e.beginShape(),e.vertex(t,a),e.vertex(o,n),e.vertex(r,s),e.endShape(e.CLOSE)},e.quad=(t,a,o,n,r,s,i,l)=>{e.beginShape(),e.vertex(t,a),e.vertex(o,n),e.vertex(r,s),e.vertex(i,l),e.endShape(e.CLOSE)},e.endShape=t=>{i(),t&&e.ctx.closePath(),o()},e.curveVertex=(o,n)=>{if(e._da&&(o*=e._da,n*=e._da),a.push([o,n]),a.length<4)return;let r=function(e,t,a,o,n,r,s,i,l,c){function d(e,t,a,o,n,r){let s=Math.pow(o-t,2)+Math.pow(n-a,2);return Math.pow(s,.5*r)+e}let h=[],u=d(0,e,t,a,o,c),_=d(u,a,o,n,r,c),p=d(_,n,r,s,i,c);for(let c=0;c<l;c++){let d=u+c/(l-1)*(_-u),g=[(u-d)/(u-0),(d-0)/(u-0),(_-d)/(_-u),(d-u)/(_-u),(p-d)/(p-_),(d-_)/(p-_),(_-d)/(_-0),(d-0)/(_-0),(p-d)/(p-u),(d-u)/(p-u)];for(let e=0;e<g.length;e+=2)isNaN(g[e])&&(g[e]=1,g[e+1]=0),isFinite(g[e])||(g[e]>0?(g[e]=1,g[e+1]=0):(g[e]=0,g[e+1]=1));let x=e*g[0]+a*g[1],m=t*g[0]+o*g[1],f=a*g[2]+n*g[3],v=o*g[2]+r*g[3],y=n*g[4]+s*g[5],w=r*g[4]+i*g[5],M=x*g[6]+f*g[7],C=m*g[6]+v*g[7],S=f*g[8]+y*g[9],b=v*g[8]+w*g[9],R=M*g[2]+S*g[3],E=C*g[2]+b*g[3];h.push([R,E])}return h}(...a.at(-4),...a.at(-3),...a.at(-2),...a.at(-1),e._curveDetail,e._curveAlpha);for(let a=0;a<r.length;a++)t?e.ctx.moveTo(...r[a]):e.ctx.lineTo(...r[a]),t=!1},e.curve=(t,a,o,n,r,s,i,l)=>{e.beginShape(),e.curveVertex(t,a),e.curveVertex(o,n),e.curveVertex(r,s),e.curveVertex(i,l),e.endShape()},e.curvePoint=(e,t,a,o,n)=>{const r=n*n*n,s=n*n;return e*(-.5*r+s-.5*n)+t*(1.5*r-2.5*s+1)+a*(-1.5*r+2*s+.5*n)+o*(.5*r-.5*s)},e.bezierPoint=(e,t,a,o,n)=>{const r=1-n;return Math.pow(r,3)*e+3*Math.pow(r,2)*n*t+3*r*Math.pow(n,2)*a+Math.pow(n,3)*o},e.curveTangent=(e,t,a,o,n)=>{const r=n*n;return e*(-3*r/2+2*n-.5)+t*(9*r/2-5*n)+a*(-9*r/2+4*n+.5)+o*(3*r/2-n)},e.bezierTangent=(e,t,a,o,n)=>{const r=1-n;return 3*o*Math.pow(n,2)-3*a*Math.pow(n,2)+6*a*r*n-6*t*r*n+3*t*Math.pow(r,2)-3*e*Math.pow(r,2)},e.erase=function(t=255,a=255){e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgba(0, 0, 0, ${t/255})`,e.ctx.strokeStyle=`rgba(0, 0, 0, ${a/255})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,a)=>{const o=e._pixelDensity;return e.ctx.isPointInPath(t*o,a*o)},e.inStroke=(t,a)=>{const o=e._pixelDensity;return e.ctx.isPointInStroke(t*o,a*o)}},Q5.modules.q2d_image=(e,t)=>{e.createImage=(t,a,o)=>(o??={},o.alpha??=!0,o.colorSpace??=e.canvas.colorSpace||Q5.canvasOptions.colorSpace,new Q5.Image(t,a,o)),e._tint=null;let a=null,o=null,n=null;function r(t,a){a??=t||e.canvas.height,t??=e.canvas.width,null==o&&(o=new e._OffscreenCanvas(t,a).getContext("2d",{colorSpace:e.canvas.colorSpace})),o.canvas.width==t&&o.canvas.height==a||(o.canvas.width=t,o.canvas.height=a)}function s(t){o.clearRect(0,0,o.canvas.width,o.canvas.height),o.filter=t,o.drawImage(e.canvas,0,0),e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()}e._softFilter=()=>{throw"Load q5-2d-soft-filters.js to use software filters."},e.filter=(t,a)=>{if(!e.ctx.filter)return e._softFilter(t,a);if(r(),"string"==typeof t)s(t);else if(t==Q5.THRESHOLD){a??=.5,a=Math.max(a,1e-5),s(`saturate(0%) brightness(${Math.floor(.5/a*100)}%) contrast(1000000%)`)}else t==Q5.GRAY?s("saturate(0%)"):t==Q5.OPAQUE?(o.fillStyle="black",o.fillRect(0,0,o.canvas.width,o.canvas.height),o.drawImage(e.canvas,0,0),e.ctx.save(),e.ctx.resetTransform(),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()):t==Q5.INVERT?s("invert(100%)"):t==Q5.BLUR?s(`blur(${Math.ceil(a*e._pixelDensity/1)||1}px)`):e._softFilter(t,a)},e.resize=(a,n)=>{r(),o.drawImage(e.canvas,0,0),t.width=a,t.height=n,e.canvas.width=a*e._pixelDensity,e.canvas.height=n*e._pixelDensity,e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.drawImage(o.canvas,0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e.trim=()=>{let t=e._pixelDensity||1,a=e.ctx.getImageData(0,0,e.width*t,e.height*t).data,o=e.width,n=0,r=e.height,s=0;for(let i=0;i<e.height*t;i++)for(let l=0;l<e.width*t;l++){0!==a[4*(i*e.width*t+l)+3]&&(l<o&&(o=l),l>n&&(n=l),i<r&&(r=i),i>s&&(s=i))}return r=Math.floor(r/t),s=Math.floor(s/t),o=Math.floor(o/t),n=Math.floor(n/t),e.get(o,r,n-o+1,s-r+1)},e.mask=t=>{e.ctx.save(),e.ctx.resetTransform();let a=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="destination-in",e.ctx.drawImage(t.canvas,0,0),e.ctx.globalCompositeOperation=a,e.ctx.restore()},e._save=async(e,t,a)=>{if(t=t||"untitled","jpg"==(a=a||"png")||"png"==a||"webp"==a)if(e instanceof OffscreenCanvas){const t=await e.convertToBlob({type:"image/"+a});e=await new Promise((e=>{const a=new FileReader;a.onloadend=()=>e(a.result),a.readAsDataURL(t)}))}else e=e.toDataURL("image/"+a);else{let t="text/plain";"json"==a&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),e=new Blob([e],{type:t}),e=URL.createObjectURL(e)}let o=document.createElement("a");o.href=e,o.download=t+"."+a,document.body.append(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(o.href)},e.save=(t,a,o)=>{if((!t||"string"==typeof t&&(!a||!o&&a.length<5))&&(o=a,a=t,t=e.canvas),o)return e._save(t,a,o);a?(a=a.split("."),e._save(t,a[0],a.at(-1))):e._save(t)},e.get=(t,a,o,n)=>{let r=e._pixelDensity||1;if(void 0!==t&&void 0===o){let o=e.ctx.getImageData(t*r,a*r,1,1).data;return new e.Color(o[0],o[1],o[2],o[3]/255)}t=(t||0)*r,a=(a||0)*r;let s=o=o||e.width,i=n=n||e.height;o*=r,n*=r;let l=e.createImage(o,n),c=e.ctx.getImageData(t,a,o,n);return l.ctx.putImageData(c,0,0),l._pixelDensity=r,l.width=s,l.height=i,l},e.set=(t,a,o)=>{if(o.canvas){let n=e._tint;return e._tint=null,e.image(o,t,a),void(e._tint=n)}e.pixels.length||e.loadPixels();let n=e._pixelDensity||1;for(let r=0;r<n;r++)for(let s=0;s<n;s++){let i=4*((a*n+r)*e.canvas.width+t*n+s);e.pixels[i]=o.r??o.l,e.pixels[i+1]=o.g??o.c,e.pixels[i+2]=o.b??o.h,e.pixels[i+3]=o.a}},e.loadPixels=()=>{a=e.ctx.getImageData(0,0,e.canvas.width,e.canvas.height),t.pixels=a.data},e.updatePixels=()=>{null!=a&&e.ctx.putImageData(a,0,0)},e._tinted=function(t){let a=t.a;t.a=255,r(),o.clearRect(0,0,o.canvas.width,o.canvas.height),o.fillStyle=t.toString(),o.fillRect(0,0,o.canvas.width,o.canvas.height),o.globalCompositeOperation="multiply",o.drawImage(e.ctx.canvas,0,0),o.globalCompositeOperation="source-over",e.ctx.save(),e.ctx.resetTransform();let n=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="source-in",e.ctx.drawImage(o.canvas,0,0),e.ctx.globalCompositeOperation=n,e.ctx.restore(),o.globalAlpha=a/255,o.clearRect(0,0,o.canvas.width,o.canvas.height),o.drawImage(e.ctx.canvas,0,0),o.globalAlpha=1,e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.ctx.canvas.width,e.ctx.canvas.height),e.ctx.drawImage(o.canvas,0,0),e.ctx.restore()},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,"image"!=e._scope&&(e.saveCanvas=e.canvas.save=e.save,e.tint=function(t){e._tint=t._q5Color?t:e.color(...arguments)},e.noTint=()=>e._tint=null,e.imageMode=t=>e._imageMode=t,e.image=(t,a,o,r,s,i=0,l=0,c,d)=>{e._da&&(a*=e._da,o*=e._da,r*=e._da,s*=e._da,i*=e._da,l*=e._da,c*=e._da,d*=e._da);let h=t.canvas||t;var u,_;Q5._createNodeJSCanvas&&(h=h.context.canvas),t.canvas&&null!=e._tint&&(u=t.canvas.width,_=t.canvas.height,_??=u||e.canvas.height,u??=e.canvas.width,null==n&&(n=new e._OffscreenCanvas(u,_).getContext("2d",{colorSpace:e.canvas.colorSpace})),n.canvas.width==u&&n.canvas.height==_||(n.canvas.width=u,n.canvas.height=_),n.drawImage(t.canvas,0,0),t._tinted(e._tint)),r??=t.width||t.videoWidth,s??=t.height||t.videoHeight,"center"==e._imageMode&&(a-=.5*r,o-=.5*s);let p=t._pixelDensity||1;c?c*=p:c=h.width||h.videoWidth,d?d*=p:d=h.height||h.videoHeight,e.ctx.drawImage(h,i*p,l*p,c,d,a,o,r,s),function(){if(!t._q5||!e._tint)return;let a=t.ctx;a.save(),a.resetTransform(),a.clearRect(0,0,a.canvas.width,a.canvas.height),a.drawImage(n.canvas,0,0),a.restore()}()},e.loadImage=function(a,o,n){if(a.canvas)return a;if("gif"==a.slice(-3).toLowerCase())throw new Error("q5 doesn't support GIFs due to their impact on performance. Use a video or animation instead.");t._preloadCount++;let r=[...arguments].at(-1);n="object"==typeof r?r:null;let s=e.createImage(1,1,n);function i(e){let a=s.ctx;s.width=a.canvas.width=e.naturalWidth||e.width,s.height=a.canvas.height=e.naturalHeight||e.height,a.drawImage(e,0,0),t._preloadCount--,o&&o(s)}if(Q5._nodejs&&global.CairoCanvas)global.CairoCanvas.loadImage(a).then(i).catch((e=>{throw t._preloadCount--,e}));else{let e=new window.Image;e.src=a,e.crossOrigin="Anonymous",e._pixelDensity=1,e.onload=()=>i(e),e.onerror=e=>{throw t._preloadCount--,e}}return s})},Q5.imageModules=["q2d_canvas","q2d_image"];class _Q5Image{constructor(e,t,a){let o=this;o._scope="image",o.canvas=o.ctx=o.drawingContext=null,o.pixels=[];for(let e of Q5.imageModules)Q5.modules[e](o,o);delete this.createCanvas,this._createCanvas(e,t,"2d",a),this._loop=!1}get w(){return this.width}get h(){return this.height}}Q5.Image??=_Q5Image,Q5.THRESHOLD=1,Q5.GRAY=2,Q5.OPAQUE=3,Q5.INVERT=4,Q5.POSTERIZE=5,Q5.DILATE=6,Q5.ERODE=7,Q5.BLUR=8,Q5.modules.q2d_soft_filters=e=>{let t=null;function a(){let a=e.canvas.width*e.canvas.height*4;t&&a==t.length||(t=new Uint8ClampedArray(a))}e._softFilter=(o,n)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let a=0;a<e.length;a+=4){const o=.2126*e[a]+.7152*e[a+1]+.0722*e[a+2];e[a]=e[a+1]=e[a+2]=o>=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t<e.length;t+=4){const a=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];e[t]=e[t+1]=e[t+2]=a}},e._filters[Q5.OPAQUE]=e=>{for(let t=0;t<e.length;t+=4)e[t+3]=255},e._filters[Q5.INVERT]=e=>{for(let t=0;t<e.length;t+=4)e[t]=255-e[t],e[t+1]=255-e[t+1],e[t+2]=255-e[t+2]},e._filters[Q5.POSTERIZE]=(e,t=4)=>{let a=t-1;for(let o=0;o<e.length;o+=4)e[o]=255*(e[o]*t>>8)/a,e[o+1]=255*(e[o+1]*t>>8)/a,e[o+2]=255*(e[o+2]*t>>8)/a},e._filters[Q5.DILATE]=o=>{a(),t.set(o);let[n,r]=[e.canvas.width,e.canvas.height];for(let e=0;e<r;e++)for(let a=0;a<n;a++){let s=4*Math.max(a-1,0),i=4*Math.min(a+1,n-1),l=4*Math.max(e-1,0)*n,c=4*Math.min(e+1,r-1)*n,d=4*e*n,h=4*a;for(let e=0;e<4;e++){let a=e+l,n=e+c,r=e+d;o[d+h+e]=Math.max(t[a+h],t[r+s],t[r+h],t[r+i],t[n+h])}}},e._filters[Q5.ERODE]=o=>{a(),t.set(o);let[n,r]=[e.canvas.width,e.canvas.height];for(let e=0;e<r;e++)for(let a=0;a<n;a++){let s=4*Math.max(a-1,0),i=4*Math.min(a+1,n-1),l=4*Math.max(e-1,0)*n,c=4*Math.min(e+1,r-1)*n,d=4*e*n,h=4*a;for(let e=0;e<4;e++){let a=e+l,n=e+c,r=e+d;o[d+h+e]=Math.min(t[a+h],t[r+s],t[r+h],t[r+i],t[n+h])}}},e._filters[Q5.BLUR]=(o,n)=>{n=n||1,n=Math.floor(n*e._pixelDensity),a(),t.set(o);let r=2*n+1,s=function(e){let t=new Float32Array(e),a=.3*n+.8,o=a*a*2;for(let n=0;n<e;n++){let r=n-e/2,s=Math.exp(-r*r/o)/(2.5066282746*a);t[n]=s}return t}(r),[i,l]=[e.canvas.width,e.canvas.height];for(let e=0;e<l;e++)for(let a=0;a<i;a++){let l=0,c=0,d=0,h=0;for(let o=0;o<r;o++){let r=4*(e*i+Math.min(Math.max(a-n+o,0),i-1));l+=t[r]*s[o],c+=t[r+1]*s[o],d+=t[r+2]*s[o],h+=t[r+3]*s[o]}let u=4*(e*i+a);o[u]=l,o[u+1]=c,o[u+2]=d,o[u+3]=h}t.set(o);for(let e=0;e<l;e++)for(let a=0;a<i;a++){let c=0,d=0,h=0,u=0;for(let o=0;o<r;o++){let r=4*(Math.min(Math.max(e-n+o,0),l-1)*i+a);c+=t[r]*s[o],d+=t[r+1]*s[o],h+=t[r+2]*s[o],u+=t[r+3]*s[o]}let _=4*(e*i+a);o[_]=c,o[_+1]=d,o[_+2]=h,o[_+3]=u}});let r=e.ctx.getImageData(0,0,e.canvas.width,e.canvas.height);e._filters[o](r.data,n),e.ctx.putImageData(r,0,0)}},Q5.modules.q2d_text=(e,t)=>{e.NORMAL="normal",e.ITALIC="italic",e.BOLD="bold",e.BOLDITALIC="italic bold",e.CENTER="center",e.LEFT="left",e.RIGHT="right",e.TOP="top",e.BOTTOM="bottom",e.BASELINE="alphabetic",e._textFont="sans-serif",e._textSize=12,e._textLeading=15,e._textLeadDiff=3,e._textStyle="normal",e.loadFont=(e,a)=>{t._preloadCount++;let o=e.split("/").pop().split(".")[0].replace(" ",""),n=new FontFace(o,`url(${e})`);return document.fonts.add(n),n.load().then((()=>{t._preloadCount--,a&&a(o)})),o},e.textFont=t=>e._textFont=t,e.textSize=t=>{if(void 0===t)return e._textSize;e._da&&(t*=e._da),e._textSize=t,e._leadingSet||(e._textLeading=1.25*t,e._textLeadDiff=e._textLeading-t)},e.textLeading=t=>{if(void 0===t)return e._textLeading;e._da&&(t*=e._da),e._textLeading=t,e._textLeadDiff=t-e._textSize,e._leadingSet=!0},e.textStyle=t=>e._textStyle=t,e.textAlign=(t,a)=>{e.ctx.textAlign=t,a&&(e.ctx.textBaseline=a==e.CENTER?"middle":a)},e.textWidth=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).width),e.textAscent=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(e.ctx.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`,e.ctx.measureText(t).actualBoundingBoxDescent),e._textCache=!!Q5.Image,e._TimedCache=class extends Map{constructor(){super(),this.maxSize=500}set(e,t){t.lastAccessed=Date.now(),super.set(e,t),this.size>this.maxSize&&this.gc()}get(e){const t=super.get(e);return t&&(t.lastAccessed=Date.now()),t}gc(){let e,t=1/0,a=0;for(const[o,n]of this.entries())n.lastAccessed<t&&(t=n.lastAccessed,e=a),a++;a=e;for(const t of this.keys()){if(0==a){e=t;break}a--}this.delete(e)}},e._tic=new e._TimedCache,e.textCache=(t,a)=>(a&&(e._tic.maxSize=a),void 0!==t&&(e._textCache=t),e._textCache),e._genTextImageKey=(t,a,o)=>t.slice(0,200)+e._textStyle+e._textSize+e._textFont+(e._doFill?e.ctx.fillStyle:"")+"_"+(e._doStroke&&e._strokeSet?e.ctx.lineWidth+e.ctx.strokeStyle+"_":"")+(a||"")+(o?"x"+o:""),e.createTextImage=(t,a,o)=>{let n=e._textCache;e._textCache=!0,e._genTextImage=!0,e.text(t,0,0,a,o),e._genTextImage=!1;let r=e._genTextImageKey(t,a,o);return e._textCache=n,e._tic.get(r)},e.text=(t,a,o,n,r)=>{if(void 0===t)return;if(t=t.toString(),e._da&&(a*=e._da,o*=e._da),!e._doFill&&!e._doStroke)return;let s,i,l,c,d,h,u,_,p=e.ctx.getTransform(),g=e._genTextImage||e._textCache&&(0!=p.b||0!=p.c);if(g){if(c=e._genTextImageKey(t,n,r),i=e._tic.get(c),i&&!e._genTextImage)return void e.textImage(i,a,o);l=e.createGraphics.call(e,1,1),s=l.ctx}else s=e.ctx,d=a,h=o;s.font=`${e._textStyle} ${e._textSize}px ${e._textFont}`;let x=t.split("\n");if(g){d=0,h=e._textLeading*x.length;let a=s.measureText(" ");u=a.fontBoundingBoxAscent,_=a.fontBoundingBoxDescent,r??=h+_,l.resizeCanvas(Math.ceil(s.measureText(t).width),Math.ceil(r)),s.fillStyle=e.ctx.fillStyle,s.strokeStyle=e.ctx.strokeStyle,s.lineWidth=e.ctx.lineWidth}let m=s.fillStyle;e._fillSet||(s.fillStyle="black");for(let t=0;t<x.length&&(e._doStroke&&e._strokeSet&&s.strokeText(x[t],d,h),e._doFill&&s.fillText(x[t],d,h),h+=e._textLeading,!(h>r));t++);e._fillSet||(s.fillStyle=m),g&&(i=l.get(),i._ascent=u,i._descent=_,e._tic.set(c,i),e._genTextImage||e.textImage(i,a,o))},e.textImage=(t,a,o)=>{let n=e._imageMode;e._imageMode="corner","center"==e.ctx.textAlign?a-=.5*t.width:"right"==e.ctx.textAlign&&(a-=t.width),"alphabetic"==e.ctx.textBaseline&&(o-=e._textLeading),"middle"==e.ctx.textBaseline?o-=t._descent+.5*t._ascent+e._textLeadDiff:"bottom"==e.ctx.textBaseline?o-=t._ascent+t._descent+e._textLeadDiff:"top"==e.ctx.textBaseline&&(o-=t._descent+e._textLeadDiff),e.image(t,a,o),e._imageMode=n},e.nf=(e,t,a)=>{let o=e<0,n=(e=Math.abs(e)).toFixed(a).split(".");n[0]=n[0].padStart(t,"0");let r=n.join(".");return o&&(r="-"+r),r}},Q5.modules.ai=e=>{e.askAI=(e="")=>{throw Error("Ask AI ✨ "+e)},e._aiErrorAssistance=async t=>{let a=t.message?.includes("Ask AI ✨");if(a||console.error(t),Q5.disableFriendlyErrors)return;!a&&Q5.errorTolerant||e.noLoop();let o=t.stack?.split("\n");if(!t.stack||o.length<=1)return;let n=1,r="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(n=0,r="@");o[n].indexOf("q5.js:")>=0;)n++;let s=o[n].split(r).at(-1);s=s.split(":");let i=parseInt(s.at(-2));a&&i++;let l=s.slice(0,-2).join(":"),c=l.split("/").at(-1);try{let e=(await(await fetch(l)).text()).split("\n"),o=e[i-1].trim(),n="",r=1;for(;n.length<1600&&(i-r>=0&&(n=e[i-r].trim()+"\n"+n),i+r<e.length);)n+=e[i+r].trim()+"\n",r++;let s="https://chatgpt.com/?q=q5.js+"+(a&&t.message.length>10?t.message.slice(10):"Whats+wrong+with+this+line%3F+short+answer")+(a?"":"%0A%0A"+encodeURIComponent(t.name+": "+t.message))+"%0A%0ALine%3A+"+encodeURIComponent(o)+"%0A%0AExcerpt+for+context%3A%0A%0A"+encodeURIComponent(n);a||console.log("Error in "+c+" on line "+i+":\n\n"+o),console.warn("Ask AI ✨ "+s),a&&window.open(s,"_blank")}catch(e){}}},Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e._colorMode="rgb",Q5.supportsHDR?e.Color=Q5.ColorRGBA_P3:e.Color=Q5.ColorRGBA,e.colorMode=a=>{e._colorMode=a,"oklch"==a?t.Color=Q5.ColorOKLCH:"rgb"==a?"srgb"==e.canvas.colorSpace?t.Color=Q5.ColorRGBA:t.Color=Q5.ColorRGBA_P3:"srgb"==a&&(t.Color=Q5.ColorRGBA,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],crimson:[220,20,60],cyan:[0,255,255],darkviolet:[148,0,211],gold:[255,215,0],green:[0,128,0],gray:[128,128,128],grey:[128,128,128],hotpink:[255,105,180],indigo:[75,0,130],khaki:[240,230,140],lightgreen:[144,238,144],lime:[0,255,0],magenta:[255,0,255],navy:[0,0,128],orange:[255,165,0],olive:[128,128,0],peachpuff:[255,218,185],pink:[255,192,203],purple:[128,0,128],red:[255,0,0],skyblue:[135,206,235],tan:[210,180,140],turquoise:[64,224,208],transparent:[0,0,0,0],white:[255,255,255],violet:[238,130,238],yellow:[255,255,0]},e.color=function(t,a,o,n){let r=e.Color;if(t._q5Color)return new r(...t.levels);let s=arguments;if(1==s.length){if("string"==typeof t)return"#"==t[0]?t.length<=5?new r(parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16),4==t.length?null:parseInt(t[4]+t[4],16)):new r(parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16),7==t.length?null:parseInt(t.slice(7,9),16)):e._namedColors[t]?new r(...e._namedColors[t]):(console.error("q5 can't parse color: "+t+"\nOnly numeric input, hex, and common named colors are supported."),new r(0,0,0));if(Array.isArray(t))return new r(...t)}if("rgb"==e._colorMode){if(1==s.length)return new r(t,t,t);if(2==s.length)return new r(t,t,t,a);if(3==s.length)return new r(t,a,o);if(4==s.length)return new r(t,a,o,n)}},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=e=>100*(.2126*e.r+.7152*e.g+.0722*e.b)/255,e.lerpColor=(t,a,o)=>{if("rgb"==e._colorMode)return new e.Color(e.constrain(e.lerp(t.r,a.r,o),0,255),e.constrain(e.lerp(t.g,a.g,o),0,255),e.constrain(e.lerp(t.b,a.b,o),0,255),e.constrain(e.lerp(t.a,a.a,o),0,255));{let n=a.h-t.h;n>180&&(n-=360),n<-180&&(n+=360);let r=t.h+o*n;return r<0&&(r+=360),r>360&&(r-=360),new e.Color(e.constrain(e.lerp(t.l,a.l,o),0,100),e.constrain(e.lerp(t.c,a.c,o),0,100),r,e.constrain(e.lerp(t.a,a.a,o),0,255))}}},Q5.Color=class{constructor(){this._q5Color=!0}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,a,o){super(),this.l=e,this.c=t,this.h=a,this.a=o??1}toString(){return`color(oklch ${this.l} ${this.c} ${this.h} / ${this.a})`}},Q5.ColorRGBA=class extends Q5.Color{constructor(e,t,a,o){super(),this.r=e,this.g=t,this.b=a,this.a=o??255}setRed(e){this.r=e}setGreen(e){this.g=e}setBlue(e){this.b=e}setAlpha(e){this.a=e}get levels(){return[this.r,this.g,this.b,this.a]}toString(){return`rgb(${this.r} ${this.g} ${this.b} / ${this.a/255})`}},Q5.ColorRGBA_P3=class extends Q5.ColorRGBA{constructor(e,t,a,o){super(e,t,a,o),this._edited=!0}get r(){return this._r}set r(e){this._r=e,this._edited=!0}get g(){return this._g}set g(e){this._g=e,this._edited=!0}get b(){return this._b}set b(e){this._b=e,this._edited=!0}get a(){return this._a}set a(e){this._a=e,this._edited=!0}toString(){if(this._edited){let e=(this._r/255).toFixed(3),t=(this._g/255).toFixed(3),a=(this._b/255).toFixed(3),o=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${a} / ${o})`,this._edited=!1}return this._css}},Q5.modules.display=e=>{if(!e.canvas||"graphics"==e._scope)return;let t=e.canvas;0!=Q5._instanceCount||Q5._nodejs||document.head.insertAdjacentHTML("beforeend","<style>\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\n.q5Canvas {\n\toutline: none;\n\t-webkit-touch-callout: none;\n\t-webkit-text-size-adjust: none;\n\t-webkit-user-select: none;\n\toverscroll-behavior: none;\n}\n.q5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.q5-centered,\n.q5-maxed,\n.q5-fullscreen {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.q5-centered,\nmain.q5-maxed,\n.q5-fullscreen {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>"),e._adjustDisplay=()=>{let a=t.style,o=t.parentElement;a&&o&&t.displayMode&&("pixelated"==t.renderQuality&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),"normal"==t.displayMode?(o.classList.remove("q5-centered","q5-maxed","q5-fullscreen"),a.width=t.w*t.displayScale+"px",a.height=t.h*t.displayScale+"px"):(o.classList.add("q5-"+t.displayMode),o=o.getBoundingClientRect(),t.w/t.h>o.width/o.height?("centered"==t.displayMode?(a.width=t.w*t.displayScale+"px",a.maxWidth="100%"):a.width="100%",a.height="auto",a.maxHeight=""):(a.width="auto",a.maxWidth="","centered"==t.displayMode?(a.height=t.h*t.displayScale+"px",a.maxHeight="100%"):a.height="100%")))},e.displayMode=(a="normal",o="default",n=1)=>{"string"==typeof n&&(n=parseFloat(n.slice(1))),Object.assign(t,{displayMode:a,renderQuality:o,displayScale:n}),e._adjustDisplay()}},Q5.modules.input=(e,t)=>{if("graphics"==e._scope)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.mouseButton=null,e.keyIsPressed=!1,e.mouseIsPressed=!1,e.key=null,e.keyCode=null,e.UP_ARROW=38,e.DOWN_ARROW=40,e.LEFT_ARROW=37,e.RIGHT_ARROW=39,e.SHIFT=16,e.TAB=9,e.BACKSPACE=8,e.ENTER=e.RETURN=13,e.ALT=e.OPTION=18,e.CONTROL=17,e.DELETE=46,e.ESCAPE=27,e.ARROW="default",e.CROSS="crosshair",e.HAND="pointer",e.MOVE="move",e.TEXT="text";let a={},o=[e.LEFT,e.CENTER,e.RIGHT],n=e.canvas;function r(t){const a=e.canvas.getBoundingClientRect(),o=e.canvas.scrollWidth/e.width||1,n=e.canvas.scrollHeight/e.height||1;return{x:(t.clientX-a.left)/o,y:(t.clientY-a.top)/n,id:t.identifier}}if(e._startAudio=()=>{e.getAudioContext&&"suspended"==e.getAudioContext()?.state&&e.userStartAudio()},e._updateMouse=a=>{if(a.changedTouches)return;let o=e.canvas.getBoundingClientRect(),n=e.canvas.scrollWidth/e.width||1,r=e.canvas.scrollHeight/e.height||1;t.mouseX=(a.clientX-o.left)/n,t.mouseY=(a.clientY-o.top)/r},e._onmousedown=a=>{e._startAudio(),e._updateMouse(a),t.mouseIsPressed=!0,t.mouseButton=o[a.button],e.mousePressed(a)},e._onmousemove=t=>{e._updateMouse(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t)},e._onmouseup=a=>{e._updateMouse(a),t.mouseIsPressed=!1,e.mouseReleased(a)},e._onclick=a=>{e._updateMouse(a),t.mouseIsPressed=!0,e.mouseClicked(a),t.mouseIsPressed=!1},n.addEventListener("mousedown",(t=>e._onmousedown(t))),n.addEventListener("mouseup",(t=>e._onmouseup(t))),n.addEventListener("click",(t=>e._onclick(t))),e.cursor=(t,a,o)=>{let n="";t.includes(".")&&(t=`url("${t}")`,n=", auto"),void 0!==a&&(t+=" "+a+" "+o),e.canvas.style.cursor=t+n},e.noCursor=()=>{e.canvas.style.cursor="none"},e.requestPointerLock=document.body?.requestPointerLock,e.exitPointerLock=document.exitPointerLock,e._onkeydown=o=>{o.repeat||(e._startAudio(),t.keyIsPressed=!0,t.key=o.key,t.keyCode=o.keyCode,a[e.keyCode]=a[e.key.toLowerCase()]=!0,e.keyPressed(o),1==o.key.length&&e.keyTyped(o))},e._onkeyup=o=>{t.keyIsPressed=!1,t.key=o.key,t.keyCode=o.keyCode,a[e.keyCode]=a[e.key.toLowerCase()]=!1,e.keyReleased(o)},e.keyIsDown=e=>!!a["string"==typeof e?e.toLowerCase():e],e._ontouchstart=a=>{e._startAudio(),t.touches=[...a.touches].map(r),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,t.mouseIsPressed=!0,t.mouseButton=e.LEFT,e.mousePressed(a)||a.preventDefault()),e.touchStarted(a)||a.preventDefault()},e._ontouchmove=a=>{t.touches=[...a.touches].map(r),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,e.mouseDragged(a)||a.preventDefault()),e.touchMoved(a)||a.preventDefault()},e._ontouchend=a=>{t.touches=[...a.touches].map(r),e._isTouchAware||e.touches.length||(t.mouseIsPressed=!1,e.mouseReleased(a)||a.preventDefault()),e.touchEnded(a)||a.preventDefault()},n.addEventListener("touchstart",(t=>e._ontouchstart(t))),n.addEventListener("touchmove",(t=>e._ontouchmove(t))),n.addEventListener("touchcancel",(t=>e._ontouchend(t))),n.addEventListener("touchend",(t=>e._ontouchend(t))),window){let t=window.addEventListener;t("mousemove",(t=>e._onmousemove(t)),!1),t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1)}},Q5.modules.math=(e,t)=>{function a(){let e,t,a=4294967295;return{setSeed(o){e=t=(o??Math.random()*a)>>>0},getSeed:()=>t,rand:()=>(e^=e<<17,e^=e>>13,e^=e<<5,(e>>>0)/a)}}e.DEGREES="degrees",e.RADIANS="radians",e.PI=Math.PI,e.HALF_PI=Math.PI/2,e.QUARTER_PI=Math.PI/4,e.abs=Math.abs,e.ceil=Math.ceil,e.exp=Math.exp,e.floor=Math.floor,e.loge=Math.log,e.mag=Math.hypot,e.max=Math.max,e.min=Math.min,e.round=Math.round,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2,e.angleMode=t=>e._angleMode=t,e._DEGTORAD=Math.PI/180,e._RADTODEG=180/Math.PI,e.degrees=t=>t*e._RADTODEG,e.radians=t=>t*e._DEGTORAD,e.map=(e,t,a,o,n,r)=>{let s=o+1*(e-t)/(a-t)*(n-o);return r?o<n?Math.min(Math.max(s,o),n):Math.min(Math.max(s,n),o):s},e.lerp=(e,t,a)=>e*(1-a)+t*a,e.constrain=(e,t,a)=>Math.min(Math.max(e,t),a),e.dist=function(){let e=arguments;return 4==e.length?Math.hypot(e[0]-e[2],e[1]-e[3]):Math.hypot(e[0]-e[3],e[1]-e[4],e[2]-e[5])},e.norm=(t,a,o)=>e.map(t,a,o,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.sin(t)),e.cos=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.cos(t)),e.tan=t=>("degrees"==e._angleMode&&(t=e.radians(t)),Math.tan(t)),e.asin=t=>{let a=Math.asin(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.acos=t=>{let a=Math.acos(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.atan=t=>{let a=Math.atan(t);return"degrees"==e._angleMode&&(a=e.degrees(a)),a},e.atan2=(t,a)=>{let o=Math.atan2(t,a);return"degrees"==e._angleMode&&(o=e.degrees(o)),o};let o=a();o.setSeed(),e.randomSeed=e=>o.setSeed(e),e.random=(e,t)=>void 0===e?o.rand():"number"==typeof e?void 0!==t?o.rand()*(t-e)+e:o.rand()*e:e[Math.trunc(e.length*o.rand())],e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,a;return{setSeed(o){a=t=(o??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(a=(1664525*a+1013904223)%e,a/e)}}():t==e.SHR3&&(o=a()),o.setSeed()};var n=new function(){var e,t,a,n=new Array(128),r=new Array(256),s=new Array(128),i=new Array(128),l=new Array(256),c=new Array(256),d=()=>4294967296*o.rand()-2147483648,h=()=>.5+2.328306e-10*(d()|0),u=()=>{for(var t,o,r,l,c=3.44262;;){if(t=a*s[e],0==e){do{r=h(),l=h(),t=.2904764*-Math.log(r),o=-Math.log(l)}while(o+o<t*t);return a>0?c+t:-c-t}if(i[e]+h()*(i[e-1]-i[e])<Math.exp(-.5*t*t))return t;if(a=d(),e=127&a,Math.abs(a)<n[e])return a*s[e]}},_=()=>{for(var a;;){if(0==e)return 7.69711-Math.log(h());if(a=t*l[e],c[e]+h()*(c[e-1]-c[e])<Math.exp(-a))return a;if((t=d())<r[e=255&t])return t*l[e]}};this.SHR3=d,this.UNI=h,this.RNOR=()=>(a=d(),e=127&a,Math.abs(a)<n[e]?a*s[e]:u()),this.REXP=()=>(t=d()>>>0)<n[e=255&t]?t*l[e]:_(),this.zigset=()=>{var e,t,a=2147483648,o=4294967296,d=3.442619855899,h=d,u=.00991256303526217,_=7.697117470131487,p=_,g=.003949659822581572;for(e=u/Math.exp(-.5*d*d),n[0]=Math.floor(d/e*a),n[1]=0,s[0]=e/a,s[127]=d/a,i[0]=1,i[127]=Math.exp(-.5*d*d),t=126;t>=1;t--)d=Math.sqrt(-2*Math.log(u/d+Math.exp(-.5*d*d))),n[t+1]=Math.floor(d/h*a),h=d,i[t]=Math.exp(-.5*d*d),s[t]=d/a;for(e=g/Math.exp(-_),r[0]=Math.floor(_/e*o),r[1]=0,l[0]=e/o,l[255]=_/o,c[0]=1,c[255]=Math.exp(-_),t=254;t>=1;t--)_=-Math.log(g/_+Math.exp(-_)),r[t+1]=Math.floor(_/p*o),p=_,c[t]=Math.exp(-_),l[t]=_/o}};let r;n.hasInit=!1,e.randomGaussian=(e,t)=>(n.hasInit||(n.zigset(),n.hasInit=!0),n.RNOR()*t+e),e.randomExponential=()=>(n.hasInit||(n.zigset(),n.hasInit=!0),n.REXP()),e.PERLIN="perlin",e.SIMPLEX="simplex",e.BLOCKY="blocky",e.Noise=Q5.PerlinNoise,e.noiseMode=e=>{t.Noise=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],r=null},e.noiseSeed=t=>{r=new e.Noise(t)},e.noise=(t=0,a=0,o=0)=>(r??=new e.Noise,r.noise(t,a,o)),e.noiseDetail=(t,a)=>{r??=new e.Noise,t>0&&(r.octaves=t),a>0&&(r.falloff=a)}},Q5.Noise=class{},Q5.PerlinNoise=class extends Q5.Noise{constructor(e){super(),this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.octaves=1,this.falloff=.5,this.p=null==e?Array.from({length:256},(()=>Math.floor(256*Math.random()))):this.seedPermutation(e),this.p=this.p.concat(this.p)}seedPermutation(e){let t,a,o=[];for(let e=0;e<256;e++)o[e]=e;for(let n=255;n>0;n--)t=(e=16807*e%2147483647)%(n+1),a=o[n],o[n]=o[t],o[t]=a;return o}dot(e,t,a,o){return e[0]*t+e[1]*a+e[2]*o}mix(e,t,a){return(1-a)*e+a*t}fade(e){return e*e*e*(e*(6*e-15)+10)}noise(e,t,a){let o=this,n=0,r=1,s=1,i=0;for(let l=0;l<o.octaves;l++){const l=255&Math.floor(e*r),c=255&Math.floor(t*r),d=255&Math.floor(a*r),h=e*r-Math.floor(e*r),u=t*r-Math.floor(t*r),_=a*r-Math.floor(a*r),p=o.fade(h),g=o.fade(u),x=o.fade(_),m=o.p[l]+c,f=o.p[m]+d,v=o.p[m+1]+d,y=o.p[l+1]+c,w=o.p[y]+d,M=o.p[y+1]+d,C=o.mix(o.dot(o.grad3[o.p[f]%12],h,u,_),o.dot(o.grad3[o.p[w]%12],h-1,u,_),p),S=o.mix(o.dot(o.grad3[o.p[v]%12],h,u-1,_),o.dot(o.grad3[o.p[M]%12],h-1,u-1,_),p),b=o.mix(o.dot(o.grad3[o.p[f+1]%12],h,u,_-1),o.dot(o.grad3[o.p[w+1]%12],h-1,u,_-1),p),R=o.mix(o.dot(o.grad3[o.p[v+1]%12],h,u-1,_-1),o.dot(o.grad3[o.p[M+1]%12],h-1,u-1,_-1),p),E=o.mix(C,S,g),I=o.mix(b,R,g);n+=o.mix(E,I,x)*s,i+=s,s*=o.falloff,r*=2}return(n/i+1)/2}},Q5.modules.sound=(e,t)=>{e.loadSound=(a,o)=>{t._preloadCount++,e.aud??=new window.AudioContext;let n=new Audio(a);return n.addEventListener("canplaythrough",(()=>{t._preloadCount--,o&&o(n)})),n.load(),n.setVolume=e=>n.volume=e,n.setLoop=e=>n.loop=e,n.panner=e.aud.createStereoPanner(),n.source=e.aud.createMediaElementSource(n),n.source.connect(n.panner),n.panner.connect(e.aud.destination),Object.defineProperty(n,"pan",{get:()=>n.panner.pan.value,set:e=>n.panner.pan.value=e}),n.setPan=e=>n.pan=e,n},e.getAudioContext=()=>e.aud,e.userStartAudio=()=>e.aud.resume()},Q5.modules.util=(e,t)=>{e._loadFile=(e,a,o)=>{t._preloadCount++;let n={};return fetch(e).then((e=>"json"==o?e.json():"text"==o?e.text():void 0)).then((e=>{t._preloadCount--,Object.assign(n,e),a&&a(e)})),n},e.loadStrings=(t,a)=>e._loadFile(t,a,"text"),e.loadJSON=(t,a)=>e._loadFile(t,a,"json"),"object"==typeof localStorage&&(e.storeItem=localStorage.setItem,e.getItem=localStorage.getItem,e.removeItem=localStorage.removeItem,e.clearStorage=localStorage.clear),e.year=()=>(new Date).getFullYear(),e.day=()=>(new Date).getDay(),e.hour=()=>(new Date).getHours(),e.minute=()=>(new Date).getMinutes(),e.second=()=>(new Date).getSeconds()},Q5.modules.vector=e=>{e.createVector=(t,a,o)=>new Q5.Vector(t,a,o,e)},Q5.Vector=class{constructor(e,t,a,o){this.x=e||0,this.y=t||0,this.z=a||0,this._$=o||window,this._cn=null,this._cnsq=null}set(e,t,a){this.x=e||0,this.y=t||0,this.z=a||0}copy(){return new Q5.Vector(this.x,this.y,this.z)}_arg2v(e,t,a){return void 0!==e.x?e:void 0!==t?{x:e,y:t,z:a||0}:{x:e,y:e,z:e}}_calcNorm(){this._cnsq=this.x*this.x+this.y*this.y+this.z*this.z,this._cn=Math.sqrt(this._cnsq)}add(){let e=this._arg2v(...arguments);return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}rem(){let e=this._arg2v(...arguments);return this.x%=e.x,this.y%=e.y,this.z%=e.z,this}sub(){let e=this._arg2v(...arguments);return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}mult(){let e=this._arg2v(...arguments);return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}div(){let e=this._arg2v(...arguments);return e.x?this.x/=e.x:this.x=0,e.y?this.y/=e.y:this.y=0,e.z?this.z/=e.z:this.z=0,this}mag(){return this._calcNorm(),this._cn}magSq(){return this._calcNorm(),this._cnsq}dot(){let e=this._arg2v(...arguments);return this.x*e.x+this.y*e.y+this.z*e.z}dist(){let e=this._arg2v(...arguments),t=this.x-e.x,a=this.y-e.y,o=this.z-e.z;return Math.sqrt(t*t+a*a+o*o)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,a=this.z*e.x-this.x*e.z,o=this.x*e.y-this.y*e.x;return this.x=t,this.y=a,this.z=o,this}normalize(){this._calcNorm();let e=this._cn;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._cn=1,this._cnsq=1,this}limit(e){this._calcNorm();let t=this._cn;if(t>e){let a=e/t;this.x*=a,this.y*=a,this.z*=a,this._cn=e,this._cnsq=e*e}return this}setMag(e){this._calcNorm();let t=e/this._cn;return this.x*=t,this.y*=t,this.z*=t,this._cn=e,this._cnsq=e*e,this}heading(){return this._$.atan2(this.y,this.x)}rotate(e){let t=this._$.cos(e),a=this._$.sin(e),o=this.x*t-this.y*a,n=this.x*a+this.y*t;return this.x=o,this.y=n,this}angleBetween(){let e=this._arg2v(...arguments),t=Q5.Vector.cross(this,e);return this._$.atan2(t.mag(),this.dot(e))*Math.sign(t.z||1)}lerp(){let e=[...arguments],t=this._arg2v(...e.slice(0,-1)),a=e.at(-1);return this.x+=(t.x-this.x)*a,this.y+=(t.y-this.y)*a,this.z+=(t.z-this.z)*a,this}reflect(e){return e.normalize(),this.sub(e.mult(2*this.dot(e)))}array(){return[this.x,this.y,this.z]}equals(e,t){return t??=Number.EPSILON||0,Math.abs(e.x-this.x)<t&&Math.abs(e.y-this.y)<t&&Math.abs(e.z-this.z)<t}fromAngle(e,t){return void 0===t&&(t=1),this._cn=t,this._cnsq=t*t,this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this.z=0,this}fromAngles(e,t,a){void 0===a&&(a=1),this._cn=a,this._cnsq=a*a;const o=this._$.cos(t),n=this._$.sin(t),r=this._$.cos(e),s=this._$.sin(e);return this.x=a*s*n,this.y=-a*r,this.z=a*s*o,this}random2D(){return this._cn=this._cnsq=1,this.fromAngle(Math.random()*Math.PI*2)}random3D(){return this._cn=this._cnsq=1,this.fromAngles(Math.random()*Math.PI*2,Math.random()*Math.PI*2)}toString(){return`[${this.x}, ${this.y}, ${this.z}]`}},Q5.Vector.add=(e,t)=>e.copy().add(t),Q5.Vector.cross=(e,t)=>e.copy().cross(t),Q5.Vector.dist=(e,t)=>Math.hypot(e.x-t.x,e.y-t.y,e.z-t.z),Q5.Vector.div=(e,t)=>e.copy().div(t),Q5.Vector.dot=(e,t)=>e.copy().dot(t),Q5.Vector.equals=(e,t,a)=>e.equals(t,a),Q5.Vector.lerp=(e,t,a)=>e.copy().lerp(t,a),Q5.Vector.limit=(e,t)=>e.copy().limit(t),Q5.Vector.heading=e=>this._$.atan2(e.y,e.x),Q5.Vector.magSq=e=>e.x*e.x+e.y*e.y+e.z*e.z,Q5.Vector.mag=e=>Math.sqrt(Q5.Vector.magSq(e)),Q5.Vector.mult=(e,t)=>e.copy().mult(t),Q5.Vector.normalize=e=>e.copy().normalize(),Q5.Vector.rem=(e,t)=>e.copy().rem(t),Q5.Vector.sub=(e,t)=>e.copy().sub(t);for(let e of["fromAngle","fromAngles","random2D","random3D"])Q5.Vector[e]=(t,a,o)=>(new Q5.Vector)[e](t,a,o);
@@ -262,6 +262,7 @@ Q5.modules.q2d_canvas = ($, p) => {
262
262
  let g = new Q5('graphics');
263
263
  opt ??= {};
264
264
  opt.alpha ??= true;
265
+ opt.colorSpace ??= $.canvas.colorSpace;
265
266
  g._createCanvas.call($, w, h, opt);
266
267
  return g;
267
268
  };
@@ -278,7 +279,6 @@ Q5.modules.q2d_canvas = ($, p) => {
278
279
 
279
280
  Q5.canvasOptions = {
280
281
  alpha: false,
281
- desynchronized: false,
282
282
  colorSpace: 'display-p3'
283
283
  };
284
284
 
@@ -70,7 +70,7 @@ Q5.modules.q2d_drawing = ($) => {
70
70
  $._strokeSet = true;
71
71
  if (Q5.Color) {
72
72
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
73
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
73
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
74
74
  if (c.a <= 0) return ($._doStroke = false);
75
75
  }
76
76
  $.ctx.strokeStyle = c.toString();
@@ -81,7 +81,7 @@ Q5.modules.q2d_drawing = ($) => {
81
81
  $._fillSet = true;
82
82
  if (Q5.Color) {
83
83
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
84
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
84
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
85
85
  if (c.a <= 0) return ($._doFill = false);
86
86
  }
87
87
  $.ctx.fillStyle = c.toString();
@@ -108,7 +108,7 @@ Q5.modules.q2d_drawing = ($) => {
108
108
  $.ctx.resetTransform();
109
109
  if (Q5.Color) {
110
110
  if (!c._q5Color && typeof c != 'string') c = $.color(...arguments);
111
- else if ($._basicColors[c]) c = $.color(...$._basicColors[c]);
111
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
112
112
  }
113
113
  $.ctx.fillStyle = c.toString();
114
114
  $.ctx.fillRect(0, 0, $.canvas.width, $.canvas.height);
@@ -130,21 +130,22 @@ Q5.modules.q2d_drawing = ($) => {
130
130
  }
131
131
  };
132
132
 
133
- function normAng(x) {
134
- let full = $._angleMode == $.DEGREES ? 360 : $.TAU;
135
- x = x % full;
136
- if (x < 0) x += full;
137
- return x;
138
- }
139
-
140
- function arc(x, y, w, h, start, stop, mode, detail) {
133
+ function arc(x, y, w, h, lo, hi, mode, detail) {
141
134
  if (!$._doFill && !$._doStroke) return;
142
- let lo = normAng(start);
143
- let hi = normAng(stop);
144
- if (lo > hi) [lo, hi] = [hi, lo];
135
+ let d = $._angleMode == 'degrees';
136
+ let full = d ? 360 : $.TAU;
137
+ lo %= full;
138
+ hi %= full;
139
+ if (lo < 0) lo += full;
140
+ if (hi < 0) hi += full;
145
141
  if (lo == 0 && hi == 0) return;
142
+ if (lo > hi) [lo, hi] = [hi, lo];
146
143
  $.ctx.beginPath();
147
144
  if (w == h) {
145
+ if (d) {
146
+ lo = $.radians(lo);
147
+ hi = $.radians(hi);
148
+ }
148
149
  $.ctx.arc(x, y, w / 2, lo, hi);
149
150
  } else {
150
151
  for (let i = 0; i < detail + 1; i++) {
@@ -511,7 +512,7 @@ Q5.modules.q2d_drawing = ($) => {
511
512
  };
512
513
 
513
514
  $.inStroke = (x, y) => {
514
- const pd = pixelDensity();
515
+ const pd = $._pixelDensity;
515
516
  return $.ctx.isPointInStroke(x * pd, y * pd);
516
517
  };
517
518
  };
@@ -1,5 +1,8 @@
1
1
  Q5.modules.q2d_image = ($, p) => {
2
2
  $.createImage = (w, h, opt) => {
3
+ opt ??= {};
4
+ opt.alpha ??= true;
5
+ opt.colorSpace ??= $.canvas.colorSpace || Q5.canvasOptions.colorSpace;
3
6
  return new Q5.Image(w, h, opt);
4
7
  };
5
8
 
@@ -321,22 +324,26 @@ Q5.modules.q2d_image = ($, p) => {
321
324
  $.loadImage = function (url, cb, opt) {
322
325
  if (url.canvas) return url;
323
326
  if (url.slice(-3).toLowerCase() == 'gif') {
324
- throw `In q5, GIFs are not supported due to their impact on performance. Use a video or p5play animation instead.`;
327
+ throw new Error(`q5 doesn't support GIFs due to their impact on performance. Use a video or animation instead.`);
325
328
  }
326
329
  p._preloadCount++;
327
330
  let last = [...arguments].at(-1);
328
- opt = typeof last == 'object' ? last : true;
329
- let g = $.createImage(1, 1, opt.alpha);
330
- let c = g.ctx;
331
+ opt = typeof last == 'object' ? last : null;
332
+
333
+ let g = $.createImage(1, 1, opt);
334
+
335
+ function loaded(img) {
336
+ let c = g.ctx;
337
+ g.width = c.canvas.width = img.naturalWidth || img.width;
338
+ g.height = c.canvas.height = img.naturalHeight || img.height;
339
+ c.drawImage(img, 0, 0);
340
+ p._preloadCount--;
341
+ if (cb) cb(g);
342
+ }
343
+
331
344
  if (Q5._nodejs && global.CairoCanvas) {
332
- CairoCanvas.loadImage(url)
333
- .then((img) => {
334
- g.width = c.canvas.width = img.width;
335
- g.height = c.canvas.height = img.height;
336
- c.drawImage(img, 0, 0);
337
- p._preloadCount--;
338
- if (cb) cb(g);
339
- })
345
+ global.CairoCanvas.loadImage(url)
346
+ .then(loaded)
340
347
  .catch((e) => {
341
348
  p._preloadCount--;
342
349
  throw e;
@@ -346,13 +353,7 @@ Q5.modules.q2d_image = ($, p) => {
346
353
  img.src = url;
347
354
  img.crossOrigin = 'Anonymous';
348
355
  img._pixelDensity = 1;
349
- img.onload = () => {
350
- g.width = c.canvas.width = img.naturalWidth;
351
- g.height = c.canvas.height = img.naturalHeight;
352
- c.drawImage(img, 0, 0);
353
- p._preloadCount--;
354
- if (cb) cb(g);
355
- };
356
+ img.onload = () => loaded(img);
356
357
  img.onerror = (e) => {
357
358
  p._preloadCount--;
358
359
  throw e;
@@ -376,8 +377,7 @@ class _Q5Image {
376
377
  Q5.modules[m]($, $);
377
378
  }
378
379
  delete this.createCanvas;
379
- opt ??= {};
380
- opt.alpha ??= true;
380
+
381
381
  this._createCanvas(w, h, '2d', opt);
382
382
  this._loop = false;
383
383
  }
package/src/q5-2d-text.js CHANGED
@@ -19,9 +19,8 @@ Q5.modules.q2d_text = ($, p) => {
19
19
 
20
20
  $.loadFont = (url, cb) => {
21
21
  p._preloadCount++;
22
- let sp = url.split('/');
23
- let name = sp[sp.length - 1].split('.')[0].replace(' ', '');
24
- let f = new FontFace(name, 'url(' + url + ')');
22
+ let name = url.split('/').pop().split('.')[0].replace(' ', '');
23
+ let f = new FontFace(name, `url(${url})`);
25
24
  document.fonts.add(f);
26
25
  f.load().then(() => {
27
26
  p._preloadCount--;
@@ -141,7 +140,6 @@ Q5.modules.q2d_text = ($, p) => {
141
140
  }
142
141
  if (!$._doFill && !$._doStroke) return;
143
142
  let c, ti, tg, k, cX, cY, _ascent, _descent;
144
- let pd = 1;
145
143
  let t = $.ctx.getTransform();
146
144
  let useCache = $._genTextImage || ($._textCache && (t.b != 0 || t.c != 0));
147
145
  if (!useCache) {
@@ -157,7 +155,6 @@ Q5.modules.q2d_text = ($, p) => {
157
155
  }
158
156
  tg = $.createGraphics.call($, 1, 1);
159
157
  c = tg.ctx;
160
- pd = $._pixelDensity;
161
158
  }
162
159
  c.font = `${$._textStyle} ${$._textSize}px ${$._textFont}`;
163
160
  let lines = str.split('\n');
package/src/q5-ai.js CHANGED
@@ -7,7 +7,7 @@ Q5.modules.ai = ($) => {
7
7
  let askAI = e.message?.includes('Ask AI ✨');
8
8
  if (!askAI) console.error(e);
9
9
  if (Q5.disableFriendlyErrors) return;
10
- if (askAI || !Q5.errorTolerant) noLoop();
10
+ if (askAI || !Q5.errorTolerant) $.noLoop();
11
11
  let stackLines = e.stack?.split('\n');
12
12
  if (!e.stack || stackLines.length <= 1) return;
13
13
 
package/src/q5-color.js CHANGED
@@ -17,7 +17,7 @@ Q5.modules.color = ($, p) => {
17
17
  }
18
18
  };
19
19
 
20
- $._basicColors = {
20
+ $._namedColors = {
21
21
  aqua: [0, 255, 255],
22
22
  black: [0, 0, 0],
23
23
  blue: [0, 0, 255],
@@ -58,14 +58,28 @@ Q5.modules.color = ($, p) => {
58
58
  if (args.length == 1) {
59
59
  if (typeof c0 == 'string') {
60
60
  if (c0[0] == '#') {
61
- return new C(
62
- parseInt(c0.slice(1, 3), 16),
63
- parseInt(c0.slice(3, 5), 16),
64
- parseInt(c0.slice(5, 7), 16),
65
- c0.length != 9 ? null : parseInt(c0.slice(7, 9), 16)
61
+ if (c0.length <= 5) {
62
+ return new C(
63
+ parseInt(c0[1] + c0[1], 16),
64
+ parseInt(c0[2] + c0[2], 16),
65
+ parseInt(c0[3] + c0[3], 16),
66
+ c0.length == 4 ? null : parseInt(c0[4] + c0[4], 16)
67
+ );
68
+ } else {
69
+ return new C(
70
+ parseInt(c0.slice(1, 3), 16),
71
+ parseInt(c0.slice(3, 5), 16),
72
+ parseInt(c0.slice(5, 7), 16),
73
+ c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16)
74
+ );
75
+ }
76
+ } else if ($._namedColors[c0]) return new C(...$._namedColors[c0]);
77
+ else {
78
+ console.error(
79
+ "q5 can't parse color: " + c0 + '\nOnly numeric input, hex, and common named colors are supported.'
66
80
  );
67
- } else if ($._basicColors[c0]) return new C(...$._basicColors[c0]);
68
- else return new C(0, 0, 0);
81
+ return new C(0, 0, 0);
82
+ }
69
83
  } else if (Array.isArray(c0)) return new C(...c0);
70
84
  }
71
85
  if ($._colorMode == 'rgb') {
package/src/q5-core.js CHANGED
@@ -81,7 +81,6 @@ function Q5(scope, parent) {
81
81
  p.frameCount++;
82
82
  let pre = performance.now();
83
83
  for (let m of Q5.prototype._methods.pre) m.call($);
84
- firstVertex = true;
85
84
  if ($.ctx) $.ctx.save();
86
85
  $.draw();
87
86
  for (let m of Q5.prototype._methods.post) m.call($);
@@ -207,7 +206,7 @@ function Q5(scope, parent) {
207
206
  else if ($._isGlobal) {
208
207
  $[k] = () => {
209
208
  try {
210
- t[k]();
209
+ return t[k]();
211
210
  } catch (e) {
212
211
  if ($._aiErrorAssistance) $._aiErrorAssistance(e);
213
212
  else console.error(e);
@@ -264,7 +263,7 @@ Q5.prototype.registerPreloadMethod = (n, fn) => (Q5.prototype[n] = fn[n]);
264
263
 
265
264
  if (Q5._nodejs) global.p5 ??= global.Q5 = Q5;
266
265
  else if (typeof window == 'object') window.p5 ??= window.Q5 = Q5;
267
- else window = 0;
266
+ else global.window = 0;
268
267
 
269
268
  if (typeof document == 'object') {
270
269
  document.addEventListener('DOMContentLoaded', () => {
package/src/q5-input.js CHANGED
@@ -94,24 +94,22 @@ Q5.modules.input = ($, p) => {
94
94
 
95
95
  $._onkeydown = (e) => {
96
96
  if (e.repeat) return;
97
- $._startAudio;
97
+ $._startAudio();
98
98
  p.keyIsPressed = true;
99
99
  p.key = e.key;
100
100
  p.keyCode = e.keyCode;
101
- keysHeld[$.keyCode] = keysHeld[$.key] = true;
101
+ keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = true;
102
102
  $.keyPressed(e);
103
- if (e.key.length == 1) {
104
- $.keyTyped(e);
105
- }
103
+ if (e.key.length == 1) $.keyTyped(e);
106
104
  };
107
105
  $._onkeyup = (e) => {
108
106
  p.keyIsPressed = false;
109
107
  p.key = e.key;
110
108
  p.keyCode = e.keyCode;
111
- keysHeld[$.keyCode] = keysHeld[$.key] = false;
109
+ keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
112
110
  $.keyReleased(e);
113
111
  };
114
- $.keyIsDown = (x) => !!keysHeld[x];
112
+ $.keyIsDown = (v) => !!keysHeld[typeof v == 'string' ? v.toLowerCase() : v];
115
113
 
116
114
  function getTouchInfo(touch) {
117
115
  const rect = $.canvas.getBoundingClientRect();
package/src/q5-math.js CHANGED
@@ -302,9 +302,7 @@ Q5.modules.math = ($, p) => {
302
302
  };
303
303
  };
304
304
 
305
- Q5.Noise = class {
306
- constructor() {}
307
- };
305
+ Q5.Noise = class {};
308
306
 
309
307
  Q5.PerlinNoise = class extends Q5.Noise {
310
308
  constructor(seed) {
package/src/q5-vector.js CHANGED
@@ -154,7 +154,7 @@ Q5.Vector = class {
154
154
  lerp() {
155
155
  let args = [...arguments];
156
156
  let u = this._arg2v(...args.slice(0, -1));
157
- let amt = args[args.length - 1];
157
+ let amt = args.at(-1);
158
158
  this.x += (u.x - this.x) * amt;
159
159
  this.y += (u.y - this.y) * amt;
160
160
  this.z += (u.z - this.z) * amt;