q5 3.6.5 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/defs/q5-c2d.d.ts CHANGED
@@ -259,7 +259,9 @@ declare global {
259
259
  // 🌆 image
260
260
 
261
261
  /** 🌆
262
- * Loads an image from a URL and optionally runs a callback function.
262
+ * Loads an image from a URL.
263
+ *
264
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for an image to load.
263
265
  * @param {string} url url of the image to load
264
266
  * @returns {Q5.Image & PromiseLike<Q5.Image>} image
265
267
  * @example
@@ -488,6 +490,8 @@ declare global {
488
490
  *
489
491
  * If you make changes to the canvas or image, you must call `loadPixels`
490
492
  * before using this function to get current color data.
493
+ *
494
+ * Not applicable to WebGPU canvases.
491
495
  * @param {number} x
492
496
  * @param {number} y
493
497
  * @param {number} [w] width of the area, default is 1
@@ -516,12 +520,14 @@ declare global {
516
520
  function get(x: number, y: number, w?: number, h?: number): Q5.Image | number[];
517
521
 
518
522
  /** 🌆
519
- * Sets a pixel's color in the image or canvas.
523
+ * Sets a pixel's color in the image or canvas. Color mode must be RGB.
520
524
  *
521
525
  * Or if a canvas or image is provided, it's drawn on top of the
522
526
  * destination image or canvas, ignoring its tint setting.
523
527
  *
524
528
  * Run `updatePixels` to apply the changes.
529
+ *
530
+ * Not applicable to WebGPU canvases.
525
531
  * @param {number} x
526
532
  * @param {number} y
527
533
  * @param {any} val color, canvas, or image
@@ -539,14 +545,14 @@ declare global {
539
545
  /** 🌆
540
546
  * Array of pixel color data from a canvas or image.
541
547
  *
548
+ * Empty by default, populate by running `loadPixels`.
549
+ *
542
550
  * Each pixel is represented by four consecutive values in the array,
543
551
  * corresponding to its red, green, blue, and alpha channels.
544
552
  *
545
553
  * The top left pixel's data is at the beginning of the array
546
554
  * and the bottom right pixel's data is at the end, going from
547
555
  * left to right and top to bottom.
548
- *
549
- * Use `loadPixels` to load current pixel data from a canvas or image.
550
556
  */
551
557
  var pixels: number[];
552
558
 
@@ -554,7 +560,9 @@ declare global {
554
560
  * Loads pixel data into `pixels` from the canvas or image.
555
561
  *
556
562
  * The example below sets some pixels' green channel
557
- * to a random 0-255 value.
563
+ * to a random value.
564
+ *
565
+ * Not applicable to WebGPU canvases.
558
566
  * @example
559
567
  * frameRate(5);
560
568
  * let icon = loadImage('/q5js_icon.png');
@@ -572,6 +580,8 @@ declare global {
572
580
 
573
581
  /** 🌆
574
582
  * Applies changes in the `pixels` array to the canvas or image.
583
+ *
584
+ * Not applicable to WebGPU canvases.
575
585
  * @example
576
586
  * createCanvas(200);
577
587
  *
@@ -591,6 +601,8 @@ declare global {
591
601
  *
592
602
  * A CSS filter string can also be used.
593
603
  * https://developer.mozilla.org/docs/Web/CSS/filter
604
+ *
605
+ * Not applicable to WebGPU canvases.
594
606
  * @param {string} type filter type or a CSS filter string
595
607
  * @param {number} [value] optional value, depends on filter type
596
608
  * @example
@@ -675,7 +687,9 @@ declare global {
675
687
  // 📘 text
676
688
 
677
689
  /** 📘
678
- * Renders text to the screen. Text can be positioned with the x and y
690
+ * Renders text on the canvas.
691
+ *
692
+ * Text can be positioned with the x and y
679
693
  * parameters and can optionally be constrained.
680
694
  * @param {string} str string of text to display
681
695
  * @param {number} x x-coordinate of the text's position
@@ -715,10 +729,10 @@ declare global {
715
729
  *
716
730
  * If no fonts are loaded, the default sans-serif font is used.
717
731
  *
718
- * In q5 WebGPU, only fonts in [MSDF format](https://github.com/q5js/q5.js/wiki/q5-WebGPU-renderer#text-rendering)
719
- * with the file ending "-msdf.json" can be used to render text with
720
- * the `text` function. Fonts in other formats can be used with the
721
- * [`textImage`](https://q5js.org/learn/#textImage) function.
732
+ * In q5 WebGPU, fonts in [MSDF format](https://github.com/q5js/q5.js/wiki/q5-WebGPU-renderer#text-rendering)
733
+ * with the file ending "-msdf.json" can be used for high performance text rendering. Make your own using the [MSDF font converter](https://msdf-bmfont.donmccurdy.com/).
734
+ *
735
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for a font to load.
722
736
  * @param {string} url URL of the font to load
723
737
  * @returns {FontFace & PromiseLike<FontFace>} font
724
738
  * @example
@@ -1019,6 +1033,10 @@ declare global {
1019
1033
  // 🖲 input
1020
1034
 
1021
1035
  /**
1036
+ * q5's input handling is very basic.
1037
+ *
1038
+ * For better input handling, including game controller support, consider using the [p5play](https://p5play.org/) addon with q5.
1039
+ *
1022
1040
  * Note that input responses inside `draw` can be delayed by
1023
1041
  * up to one frame cycle: from the exact moment an input event occurs
1024
1042
  * to the next time a frame is drawn.
@@ -2832,15 +2850,15 @@ declare global {
2832
2850
  // 🔊 sound
2833
2851
 
2834
2852
  /**
2835
- * q5.js includes low latency sound playback and basic mixing powered
2836
- * by WebAudio.
2853
+ * q5 includes low latency sound playback and basic mixing capabilities
2854
+ * powered by WebAudio.
2837
2855
  *
2838
- * For audio filtering, synthesis, and analysis, consider using
2839
- * [p5.sound](https://p5js.org/reference/p5.sound/).
2856
+ * For audio filtering, synthesis, and analysis, consider using the
2857
+ * [p5.sound](https://p5js.org/reference/p5.sound/) addon with q5.
2840
2858
  */
2841
2859
 
2842
2860
  /** 🔊
2843
- * Loads audio data from a file and returns a `Q5.Sound` object.
2861
+ * Loads audio data from a file and returns a `Sound` object.
2844
2862
  *
2845
2863
  * Use functions like `play`, `pause`, and `stop` to
2846
2864
  * control playback. Note that sounds can only be played after the
@@ -2852,14 +2870,9 @@ declare global {
2852
2870
  *
2853
2871
  * Use `loaded`, `paused`, and `ended` to check the sound's status.
2854
2872
  *
2855
- * The entire sound file must be loaded before playback can start,
2856
- * to stream larger audio files use the `loadAudio` function instead.
2857
- *
2858
- * For backwards compatibility with the p5.sound API, the functions
2859
- * `setVolume`, `setLoop`, `setPan`, `isLoaded`, and `isPlaying`
2860
- * are also implemented, but their use is deprecated.
2873
+ * The entire sound file must be loaded before playback can start, use `await` to wait for a sound to load. To stream larger audio files use the `loadAudio` function instead.
2861
2874
  * @param {string} url sound file
2862
- * @returns {Sound & PromiseLike<Sound>} a new `Sound` object
2875
+ * @returns {Sound & PromiseLike<Sound>} sound
2863
2876
  * @example
2864
2877
  * createCanvas(200);
2865
2878
  *
@@ -2949,6 +2962,9 @@ declare global {
2949
2962
  *
2950
2963
  * If this function is run when the sound is paused,
2951
2964
  * all playback instances will be resumed.
2965
+ *
2966
+ * Use `await` to wait for the sound to finish playing.
2967
+ * @returns {Promise<void>} a promise that resolves when the sound finishes playing
2952
2968
  */
2953
2969
  play(): void;
2954
2970
 
@@ -3365,6 +3381,8 @@ declare global {
3365
3381
  *
3366
3382
  * File type is determined by file extension. q5 supports loading
3367
3383
  * text, json, csv, font, audio, and image files.
3384
+ *
3385
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for assets to load.
3368
3386
  * @param {...string} urls
3369
3387
  * @returns {Promise<any[]>} a promise that resolves with objects
3370
3388
  * @example
@@ -3409,43 +3427,37 @@ declare global {
3409
3427
 
3410
3428
  /** 🛠
3411
3429
  * Loads a text file from the specified url.
3430
+ *
3431
+ * Using `await` to get the loaded text as a string is recommended.
3412
3432
  * @param {string} url text file
3413
- * @returns {object & PromiseLike<string>} an object containing the loaded text in the property `obj.text` or a promise
3433
+ * @returns {object & PromiseLike<string>} an object containing the loaded text in the property `obj.text` or use `await` to get the text string directly
3414
3434
  */
3415
3435
  function loadText(url: string): object & PromiseLike<string>;
3416
3436
 
3417
3437
  /** 🛠
3418
3438
  * Loads a JSON file from the specified url.
3439
+ *
3440
+ * Using `await` to get the loaded JSON object or array is recommended.
3419
3441
  * @param {string} url JSON file
3420
- * @returns {any & PromiseLike<any>} an object or array containing the loaded JSON or a promise
3442
+ * @returns {any & PromiseLike<any>} an object or array containing the loaded JSON
3421
3443
  */
3422
3444
  function loadJSON(url: string): any & PromiseLike<any>;
3423
3445
 
3424
3446
  /** 🛠
3425
3447
  * Loads a CSV file from the specified url.
3448
+ *
3449
+ * Using `await` to get the loaded CSV as an array of objects is recommended.
3426
3450
  * @param {string} url CSV file
3427
- * @returns {object[] & PromiseLike<object[]>} an array of objects containing the loaded CSV or a promise
3451
+ * @returns {object[] & PromiseLike<object[]>} an array of objects containing the loaded CSV
3428
3452
  */
3429
3453
  function loadCSV(url: string): object[] & PromiseLike<object[]>;
3430
3454
 
3431
3455
  /** 🛠
3432
3456
  * Loads an xml file from the specified url.
3433
- * @param {string} url xml file
3434
- * @returns {Element & PromiseLike<Element>} an object containing the loaded XML in a property called `obj.DOM` or a promise
3435
- * @example
3436
- * async function setup() {
3437
- * createCanvas(200);
3438
- * background(200);
3439
- * textSize(32);
3440
- *
3441
- * let myXML = await loadXML('/assets/animals.xml');
3442
3457
  *
3443
- * let mammals = myXML.getElementsByTagName('mammal');
3444
- * let y = 64;
3445
- * for (let mammal of mammals) {
3446
- * text(mammal.textContent, 20, (y += 32));
3447
- * }
3448
- * }
3458
+ * Using `await` to get the loaded XML Element is recommended.
3459
+ * @param {string} url xml file
3460
+ * @returns {Element & PromiseLike<Element>} an object containing the loaded XML Element in a property called `obj.DOM` or use await to get the XML Element directly
3449
3461
  */
3450
3462
  function loadXML(url: string): object & PromiseLike<Element>;
3451
3463
 
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q5/q5",
3
- "version": "3.6.5",
3
+ "version": "3.7.0",
4
4
  "license": "LGPL-3.0",
5
5
  "description": "Beginner friendly graphics powered by WebGPU and optimized for interactive art!",
6
6
  "author": "quinton-ashley",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "3.6.5",
3
+ "version": "3.7.0",
4
4
  "description": "Beginner friendly graphics powered by WebGPU and optimized for interactive art!",
5
5
  "author": "quinton-ashley",
6
6
  "contributors": [
package/q5.d.ts CHANGED
@@ -259,7 +259,9 @@ declare global {
259
259
  // 🌆 image
260
260
 
261
261
  /** 🌆
262
- * Loads an image from a URL and optionally runs a callback function.
262
+ * Loads an image from a URL.
263
+ *
264
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for an image to load.
263
265
  * @param {string} url url of the image to load
264
266
  * @returns {Q5.Image & PromiseLike<Q5.Image>} image
265
267
  * @example
@@ -488,6 +490,8 @@ declare global {
488
490
  *
489
491
  * If you make changes to the canvas or image, you must call `loadPixels`
490
492
  * before using this function to get current color data.
493
+ *
494
+ * Not applicable to WebGPU canvases.
491
495
  * @param {number} x
492
496
  * @param {number} y
493
497
  * @param {number} [w] width of the area, default is 1
@@ -516,12 +520,14 @@ declare global {
516
520
  function get(x: number, y: number, w?: number, h?: number): Q5.Image | number[];
517
521
 
518
522
  /** 🌆
519
- * Sets a pixel's color in the image or canvas.
523
+ * Sets a pixel's color in the image or canvas. Color mode must be RGB.
520
524
  *
521
525
  * Or if a canvas or image is provided, it's drawn on top of the
522
526
  * destination image or canvas, ignoring its tint setting.
523
527
  *
524
528
  * Run `updatePixels` to apply the changes.
529
+ *
530
+ * Not applicable to WebGPU canvases.
525
531
  * @param {number} x
526
532
  * @param {number} y
527
533
  * @param {any} val color, canvas, or image
@@ -539,14 +545,14 @@ declare global {
539
545
  /** 🌆
540
546
  * Array of pixel color data from a canvas or image.
541
547
  *
548
+ * Empty by default, populate by running `loadPixels`.
549
+ *
542
550
  * Each pixel is represented by four consecutive values in the array,
543
551
  * corresponding to its red, green, blue, and alpha channels.
544
552
  *
545
553
  * The top left pixel's data is at the beginning of the array
546
554
  * and the bottom right pixel's data is at the end, going from
547
555
  * left to right and top to bottom.
548
- *
549
- * Use `loadPixels` to load current pixel data from a canvas or image.
550
556
  */
551
557
  var pixels: number[];
552
558
 
@@ -554,7 +560,9 @@ declare global {
554
560
  * Loads pixel data into `pixels` from the canvas or image.
555
561
  *
556
562
  * The example below sets some pixels' green channel
557
- * to a random 0-255 value.
563
+ * to a random value.
564
+ *
565
+ * Not applicable to WebGPU canvases.
558
566
  * @example
559
567
  * frameRate(5);
560
568
  * let icon = loadImage('/q5js_icon.png');
@@ -572,6 +580,8 @@ declare global {
572
580
 
573
581
  /** 🌆
574
582
  * Applies changes in the `pixels` array to the canvas or image.
583
+ *
584
+ * Not applicable to WebGPU canvases.
575
585
  * @example
576
586
  * createCanvas(200);
577
587
  *
@@ -591,6 +601,8 @@ declare global {
591
601
  *
592
602
  * A CSS filter string can also be used.
593
603
  * https://developer.mozilla.org/docs/Web/CSS/filter
604
+ *
605
+ * Not applicable to WebGPU canvases.
594
606
  * @param {string} type filter type or a CSS filter string
595
607
  * @param {number} [value] optional value, depends on filter type
596
608
  * @example
@@ -675,7 +687,9 @@ declare global {
675
687
  // 📘 text
676
688
 
677
689
  /** 📘
678
- * Renders text to the screen. Text can be positioned with the x and y
690
+ * Renders text on the canvas.
691
+ *
692
+ * Text can be positioned with the x and y
679
693
  * parameters and can optionally be constrained.
680
694
  * @param {string} str string of text to display
681
695
  * @param {number} x x-coordinate of the text's position
@@ -715,10 +729,10 @@ declare global {
715
729
  *
716
730
  * If no fonts are loaded, the default sans-serif font is used.
717
731
  *
718
- * In q5 WebGPU, only fonts in [MSDF format](https://github.com/q5js/q5.js/wiki/q5-WebGPU-renderer#text-rendering)
719
- * with the file ending "-msdf.json" can be used to render text with
720
- * the `text` function. Fonts in other formats can be used with the
721
- * [`textImage`](https://q5js.org/learn/#textImage) function.
732
+ * In q5 WebGPU, fonts in [MSDF format](https://github.com/q5js/q5.js/wiki/q5-WebGPU-renderer#text-rendering)
733
+ * with the file ending "-msdf.json" can be used for high performance text rendering. Make your own using the [MSDF font converter](https://msdf-bmfont.donmccurdy.com/).
734
+ *
735
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for a font to load.
722
736
  * @param {string} url URL of the font to load
723
737
  * @returns {FontFace & PromiseLike<FontFace>} font
724
738
  * @example
@@ -1019,6 +1033,10 @@ declare global {
1019
1033
  // 🖲 input
1020
1034
 
1021
1035
  /**
1036
+ * q5's input handling is very basic.
1037
+ *
1038
+ * For better input handling, including game controller support, consider using the [p5play](https://p5play.org/) addon with q5.
1039
+ *
1022
1040
  * Note that input responses inside `draw` can be delayed by
1023
1041
  * up to one frame cycle: from the exact moment an input event occurs
1024
1042
  * to the next time a frame is drawn.
@@ -2832,15 +2850,15 @@ declare global {
2832
2850
  // 🔊 sound
2833
2851
 
2834
2852
  /**
2835
- * q5.js includes low latency sound playback and basic mixing powered
2836
- * by WebAudio.
2853
+ * q5 includes low latency sound playback and basic mixing capabilities
2854
+ * powered by WebAudio.
2837
2855
  *
2838
- * For audio filtering, synthesis, and analysis, consider using
2839
- * [p5.sound](https://p5js.org/reference/p5.sound/).
2856
+ * For audio filtering, synthesis, and analysis, consider using the
2857
+ * [p5.sound](https://p5js.org/reference/p5.sound/) addon with q5.
2840
2858
  */
2841
2859
 
2842
2860
  /** 🔊
2843
- * Loads audio data from a file and returns a `Q5.Sound` object.
2861
+ * Loads audio data from a file and returns a `Sound` object.
2844
2862
  *
2845
2863
  * Use functions like `play`, `pause`, and `stop` to
2846
2864
  * control playback. Note that sounds can only be played after the
@@ -2852,14 +2870,9 @@ declare global {
2852
2870
  *
2853
2871
  * Use `loaded`, `paused`, and `ended` to check the sound's status.
2854
2872
  *
2855
- * The entire sound file must be loaded before playback can start,
2856
- * to stream larger audio files use the `loadAudio` function instead.
2857
- *
2858
- * For backwards compatibility with the p5.sound API, the functions
2859
- * `setVolume`, `setLoop`, `setPan`, `isLoaded`, and `isPlaying`
2860
- * are also implemented, but their use is deprecated.
2873
+ * The entire sound file must be loaded before playback can start, use `await` to wait for a sound to load. To stream larger audio files use the `loadAudio` function instead.
2861
2874
  * @param {string} url sound file
2862
- * @returns {Sound & PromiseLike<Sound>} a new `Sound` object
2875
+ * @returns {Sound & PromiseLike<Sound>} sound
2863
2876
  * @example
2864
2877
  * createCanvas(200);
2865
2878
  *
@@ -2949,6 +2962,9 @@ declare global {
2949
2962
  *
2950
2963
  * If this function is run when the sound is paused,
2951
2964
  * all playback instances will be resumed.
2965
+ *
2966
+ * Use `await` to wait for the sound to finish playing.
2967
+ * @returns {Promise<void>} a promise that resolves when the sound finishes playing
2952
2968
  */
2953
2969
  play(): void;
2954
2970
 
@@ -3365,6 +3381,8 @@ declare global {
3365
3381
  *
3366
3382
  * File type is determined by file extension. q5 supports loading
3367
3383
  * text, json, csv, font, audio, and image files.
3384
+ *
3385
+ * By default, assets are loaded in parallel before q5 runs `draw`. Use `await` to wait for assets to load.
3368
3386
  * @param {...string} urls
3369
3387
  * @returns {Promise<any[]>} a promise that resolves with objects
3370
3388
  * @example
@@ -3409,43 +3427,37 @@ declare global {
3409
3427
 
3410
3428
  /** 🛠
3411
3429
  * Loads a text file from the specified url.
3430
+ *
3431
+ * Using `await` to get the loaded text as a string is recommended.
3412
3432
  * @param {string} url text file
3413
- * @returns {object & PromiseLike<string>} an object containing the loaded text in the property `obj.text` or a promise
3433
+ * @returns {object & PromiseLike<string>} an object containing the loaded text in the property `obj.text` or use `await` to get the text string directly
3414
3434
  */
3415
3435
  function loadText(url: string): object & PromiseLike<string>;
3416
3436
 
3417
3437
  /** 🛠
3418
3438
  * Loads a JSON file from the specified url.
3439
+ *
3440
+ * Using `await` to get the loaded JSON object or array is recommended.
3419
3441
  * @param {string} url JSON file
3420
- * @returns {any & PromiseLike<any>} an object or array containing the loaded JSON or a promise
3442
+ * @returns {any & PromiseLike<any>} an object or array containing the loaded JSON
3421
3443
  */
3422
3444
  function loadJSON(url: string): any & PromiseLike<any>;
3423
3445
 
3424
3446
  /** 🛠
3425
3447
  * Loads a CSV file from the specified url.
3448
+ *
3449
+ * Using `await` to get the loaded CSV as an array of objects is recommended.
3426
3450
  * @param {string} url CSV file
3427
- * @returns {object[] & PromiseLike<object[]>} an array of objects containing the loaded CSV or a promise
3451
+ * @returns {object[] & PromiseLike<object[]>} an array of objects containing the loaded CSV
3428
3452
  */
3429
3453
  function loadCSV(url: string): object[] & PromiseLike<object[]>;
3430
3454
 
3431
3455
  /** 🛠
3432
3456
  * Loads an xml file from the specified url.
3433
- * @param {string} url xml file
3434
- * @returns {Element & PromiseLike<Element>} an object containing the loaded XML in a property called `obj.DOM` or a promise
3435
- * @example
3436
- * async function setup() {
3437
- * createCanvas(200);
3438
- * background(200);
3439
- * textSize(32);
3440
- *
3441
- * let myXML = await loadXML('/assets/animals.xml');
3442
3457
  *
3443
- * let mammals = myXML.getElementsByTagName('mammal');
3444
- * let y = 64;
3445
- * for (let mammal of mammals) {
3446
- * text(mammal.textContent, 20, (y += 32));
3447
- * }
3448
- * }
3458
+ * Using `await` to get the loaded XML Element is recommended.
3459
+ * @param {string} url xml file
3460
+ * @returns {Element & PromiseLike<Element>} an object containing the loaded XML Element in a property called `obj.DOM` or use await to get the XML Element directly
3449
3461
  */
3450
3462
  function loadXML(url: string): object & PromiseLike<Element>;
3451
3463
 
package/q5.js CHANGED
@@ -1662,7 +1662,7 @@ Q5.renderers.c2d.image = ($, q) => {
1662
1662
  img.ctx.drawImage(c, x, y, w * pd, h * pd, 0, 0, w, h);
1663
1663
  img.width = w;
1664
1664
  img.height = h;
1665
- if ($._webgpuInst) $._webgpuInst._makeDrawable(img);
1665
+ if ($._owner?._makeDrawable) $._owner._makeDrawable(img);
1666
1666
  return img;
1667
1667
  };
1668
1668
 
@@ -1677,15 +1677,29 @@ Q5.renderers.c2d.image = ($, q) => {
1677
1677
  $._tint = old;
1678
1678
  return;
1679
1679
  }
1680
+
1680
1681
  if (!pixels) $.loadPixels();
1681
- let mod = $._pixelDensity || 1;
1682
+
1683
+ let mod = $._pixelDensity || 1,
1684
+ r = val.r,
1685
+ g = val.g,
1686
+ b = val.b,
1687
+ a = val.a;
1688
+
1689
+ if (($._colorFormat || $._owner?._colorFormat) == 1) {
1690
+ r *= 255;
1691
+ g *= 255;
1692
+ b *= 255;
1693
+ a *= 255;
1694
+ }
1695
+
1682
1696
  for (let i = 0; i < mod; i++) {
1683
1697
  for (let j = 0; j < mod; j++) {
1684
1698
  let idx = 4 * ((y * mod + i) * c.width + x * mod + j);
1685
- pixels[idx] = val.r;
1686
- pixels[idx + 1] = val.g;
1687
- pixels[idx + 2] = val.b;
1688
- pixels[idx + 3] = val.a;
1699
+ pixels[idx] = r;
1700
+ pixels[idx + 1] = g;
1701
+ pixels[idx + 2] = b;
1702
+ pixels[idx + 3] = a;
1689
1703
  }
1690
1704
  }
1691
1705
  };
@@ -4556,32 +4570,47 @@ Q5.Sound = class {
4556
4570
  source.start(0, source._offset, source._duration);
4557
4571
 
4558
4572
  this.sources.add(source);
4559
- source.onended = () => {
4560
- if (!this.paused) {
4561
- this.ended = true;
4562
- if (this._onended) this._onended();
4563
- this.sources.delete(source);
4564
- }
4565
- };
4573
+
4574
+ source.promise = new Promise((resolve) => {
4575
+ source.onended = () => {
4576
+ if (!this.paused) {
4577
+ this.ended = true;
4578
+ if (this._onended) this._onended();
4579
+ this.sources.delete(source);
4580
+ resolve();
4581
+ }
4582
+ };
4583
+ });
4584
+
4585
+ return source;
4566
4586
  }
4567
4587
 
4568
4588
  play(time = 0, duration) {
4569
4589
  if (!this.loaded) return;
4570
4590
 
4591
+ let source;
4592
+
4571
4593
  if (!this.paused) {
4572
- this._newSource(time, duration);
4594
+ source = this._newSource(time, duration);
4573
4595
  } else {
4574
4596
  let timings = [];
4575
4597
  for (let source of this.sources) {
4576
- timings.push(source._offset, source._duration);
4598
+ timings.push({ offset: source._offset, duration: source._duration });
4577
4599
  this.sources.delete(source);
4578
4600
  }
4579
- for (let i = 0; i < timings.length; i += 2) {
4580
- this._newSource(timings[i], timings[i + 1]);
4601
+ timings.sort((a, b) => {
4602
+ let durA = a.duration ?? this.buffer.duration - a.offset;
4603
+ let durB = b.duration ?? this.buffer.duration - b.offset;
4604
+ return durA - durB;
4605
+ });
4606
+ for (let t of timings) {
4607
+ source = this._newSource(t.offset, t.duration);
4581
4608
  }
4582
4609
  }
4583
4610
 
4584
4611
  this.paused = this.ended = false;
4612
+
4613
+ return source.promise;
4585
4614
  }
4586
4615
 
4587
4616
  pause() {
@@ -7505,7 +7534,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
7505
7534
 
7506
7535
  $._makeDrawable = (g) => {
7507
7536
  $._addTexture(g);
7508
- g._webgpuInst = $;
7537
+ g._owner = $;
7509
7538
  };
7510
7539
 
7511
7540
  $.createImage = (w, h, opt) => {
package/q5.min.js CHANGED
@@ -6,4 +6,4 @@
6
6
  * @license LGPL-3.0
7
7
  * @class Q5
8
8
  */
9
- function Q5(e,t,r){let n,i=this;i._isQ5=i._q5=!0,i._parent=t,i.ready=new Promise((e=>{n=e})),"webgpu-fallback"==r?(i._renderer="c2d",i._webgpu=i._webgpuFallback=!0):(i._renderer=r||"c2d",i["_"+i._renderer]=!0);let a,o="auto"==e;if(e??="global","auto"==e){if(!(window.setup||window.update||Q5.update||window.draw||Q5.draw))return;e="global"}"global"==e&&(Q5._hasGlobal=i._isGlobal=!0,a=Q5._esm?globalThis:Q5._server?global:window),"graphics"==e&&(i._isGraphics=!0),"image"==e&&(i._isImage=!0);let s=new Proxy(i,{set:(e,t,r)=>(i[t]=r,i._isGlobal&&(a[t]=r),!0)});i.canvas=i.ctx=i.drawingContext=null,i.pixels=[];let l=null,d=!0;async function c(e){for(let t of Q5.hooks[e])await t.call(i,s)}i.frameCount=0,i.deltaTime=16,i._targetFrameRate=0,i._targetFrameDuration=16.666666666666668,i._frameRate=i._fps=60,i._loop=!0;let h=0;i.millis=()=>performance.now()-h,i.noCanvas=()=>{i.canvas?.remove&&i.canvas.remove(),i.canvas=0,s.ctx=s.drawingContext=0},window&&(i.windowWidth=window.innerWidth,i.windowHeight=window.innerHeight,i.deviceOrientation=window.screen?.orientation?.type),i._loaders=[],i.loadAll=()=>{let e=[...i._loaders];return i._loaders=[],i._g&&(e=e.concat(i._g._loaders),i._g._loaders=[]),Promise.all(e)},i.isPreloadSupported=()=>!0,i.disablePreload=()=>i._disablePreload=!0;const u=[];async function f(e){let t=e||performance.now();if(i._didResize&&(i.windowResized(),i._didResize=!1),i._loop)if(d)l=g(f);else{let e=t+i._targetFrameDuration,r=e-performance.now();for(;r<0;)r+=i._targetFrameDuration;l=setTimeout((()=>f(e)),r)}else if(i.frameCount&&!i._redraw)return;if(i.frameCount&&d&&!i._redraw){if(t-i._lastFrameTime<i._targetFrameDuration-4)return}s.deltaTime=t-i._lastFrameTime,i._frameRate=1e3/i.deltaTime,s.frameCount++;let r=performance.now();i.resetMatrix(),i._beginRender&&i._beginRender(),await c("predraw");try{await i.draw()}catch(e){throw Q5.errorTolerant||i.noLoop(),i._fes&&i._fes(e),e}await c("postdraw"),await i.postProcess(),i._render&&i._render(),i._finishRender&&i._finishRender(),s.pmouseX=i.mouseX,s.pmouseY=i.mouseY,s.moveX=s.moveY=0,i._lastFrameTime=t;let n=performance.now();i._fps=Math.round(1e3/(n-r))}i._incrementPreload=()=>{i._loaders.push(new Promise((e=>u.push(e))))},i._decrementPreload=()=>{u.length&&u.pop()()},i.noLoop=()=>{i._loop=!1,null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l)),l=null},i.loop=()=>{i._loop=!0,i._setupDone&&null==l&&f()},i.isLooping=()=>i._loop,i.redraw=async(e=1)=>{i._redraw=!0;for(let t=0;t<e;t++)await f();i._redraw=!1},i.remove=async()=>{i.noLoop(),i.canvas.remove(),await c("remove")},i.frameRate=e=>(e&&e!=i._targetFrameRate&&(i._targetFrameRate=e,i._targetFrameDuration=1e3/e,i._loop&&null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l),l=null),d=e<=60,i._setupDone&&(l=d?g(f):setTimeout((()=>f()),i._targetFrameDuration))),i._frameRate),i.getTargetFrameRate=()=>i._targetFrameRate||60,i.getFPS=()=>i._fps,i.Element=function(e){this.elt=e},i._elements=[],i.describe=()=>{},i.log=i.print=console.log;for(let e in Q5.modules)Q5.modules[e](i,s);let p=Q5.renderers[i._renderer];for(let e in p)p[e](i,s);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(i[e]=Q5[e]);if(i._isGraphics)return;if(i._isGlobal){let e=Object.assign({},i);delete e.Color,Object.assign(Q5,e),delete Q5.Q5}for(let e of Q5.hooks.init)e.call(i,s);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof i[e]&&(i[e]=t.bind(i));for(let[e,t]of Object.entries(Q5.preloadMethods))i[e]=function(){return i._incrementPreload(),t.apply(i,arguments)};if(i._isGlobal){let e=Object.getOwnPropertyNames(i);for(let t of e)"_"!=t[0]&&(a[t]=i[t]);for(let e of["_incrementPreload","_decrementPreload"])a[e]=i[e]}"function"==typeof e&&e(i),Q5._instanceCount++;let g=window.requestAnimationFrame||function(e){const t=i._lastFrameTime+i._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},m=a||i,x=["postProcess","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","doubleClicked","mouseWheel","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized","preload"];for(let e of x)i[e]??=()=>{};x.pop();let _=["update","draw","drawFrame",...x];if(i._isGlobal)for(let e of _)Q5[e]?i[e]=Q5[e]:Object.defineProperty(Q5,e,{get:()=>i[e],set:t=>i[e]=t});function v(e){const t=m[e]||i[e];i[e]=e=>{try{return t(e)}catch(e){throw i._fes&&i._fes(e),e}}}async function b(){await c("presetup"),n(),v("preload"),i.preload(),await Promise.race([new Promise((e=>{!function t(){i.setup||i.update||i.draw||m.setup||m.update||m.draw?e():i._setupDone||(i.canvas?.ready&&i._render&&(i._beginRender(),i._render(),i._finishRender()),g(t))}()})),new Promise((e=>{setTimeout((()=>{i._loaders.length||e()}),500)}))]),i._disablePreload||await i.loadAll(),i.setup??=m.setup||(()=>{}),v("setup");for(let e of x)v(e);i.draw??=m.draw||(()=>{}),h=performance.now(),await i.setup(),i._setupDone=!0,null===i.ctx&&i.createCanvas(200,200),await c("postsetup"),i.frameCount||(i._lastFrameTime=performance.now()-15,g(f))}Q5.instances.push(i),o||Q5._esm?b():setTimeout(b,32)}function createCanvas(e,t,r){if(Q5._hasGlobal)return;if("c2d"==e||"c2d"==t||"c2d"==r||"c2d"==r?.renderer||!Q5._esm){let n=new Q5,i=n.createCanvas(e,t,r);return n.ready.then((()=>i))}return Q5.WebGPU().then((n=>n.createCanvas(e,t,r)))}Q5.renderers={},Q5.modules={},Q5._server="object"==typeof process,Q5._esm=void 0===this,Q5._instanceCount=0,Q5.instances=[],Q5._friendlyError=(e,t)=>{Q5.disableFriendlyErrors||console.error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.hooks={init:[],presetup:[],postsetup:[],predraw:[],postdraw:[],remove:[]},Q5.addHook=(e,t)=>Q5.hooks[e].push(t),Q5.registerAddon=e=>{let t={};e(Q5,Q5.prototype,t);for(let e in t)Q5.hooks[e].push(t[e])},Q5.prototype.registerMethod=(e,t)=>{("beforeSetup"==e||e.includes("Preload"))&&(e="presetup"),"afterSetup"==e&&(e="postsetup"),"pre"==e&&(e="predraw"),"post"==e&&(e="postdraw"),Q5.hooks[e].push(t)},Q5.preloadMethods={},Q5.prototype.registerPreloadMethod=(e,t)=>Q5.preloadMethods[e]=t[e],Q5._server&&(global.q5=global.Q5=Q5,global.p5??=Q5),"object"==typeof window?(window.q5=window.Q5=Q5,window.p5??=Q5,window.createCanvas=createCanvas,window.C2D="c2d",window.WEBGPU="webgpu"):global.window=0,Q5.version=Q5.VERSION="3.6","object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||(Q5.update||Q5.draw?Q5.WebGPU():new Q5("auto"))})),Q5.modules.canvas=(e,t)=>{e._Canvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._server?Q5._createServerCanvas&&(t.canvas=Q5._createServerCanvas(200,200)):(e._isImage||e._isGraphics)&&(t.canvas=new e._Canvas(200,200)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas()),e.displayDensity=()=>window.devicePixelRatio||1,e.width=200,e.height=200,e._pixelDensity=1;let r=e.canvas;if(r&&(r.width=200,r.height=200,r.colorSpace=Q5.canvasOptions.colorSpace,e._isImage||(r.renderer=e._renderer,r[e._renderer]=!0,e._pixelDensity=Math.ceil(e.displayDensity()))),e._adjustDisplay=e=>{let t=r.style;t&&e&&(t.width=r.w+"px",t.height=r.h+"px")},e.createCanvas=function(t,i,a){(isNaN(t)||"string"==typeof t&&!t.includes(":"))&&(a=t,t=null),"number"!=typeof i&&(a=i,i=null),a??=arguments[3],"string"==typeof a&&(a={renderer:a});let o=Object.assign({},Q5.canvasOptions);if("object"==typeof a&&Object.assign(o,a),!e._isImage)if(e._isGraphics)e._pixelDensity=this._pixelDensity;else if(Q5._server)r.visible=!0;else{let t=r,i=document.body||document.documentElement;for(;t&&t.parentElement!=i;)t=t.parentElement;if(t||(document.getElementById(r.id)?.remove(),n()),window.IntersectionObserver){let t=!1;new IntersectionObserver((n=>{if(n[0].isIntersecting)r.visible=!0;else{let e=r.getBoundingClientRect();r.visible=e.top<window.innerHeight&&e.bottom>0&&e.left<window.innerWidth&&e.right>0}t||(e._wasLooping=e._loop,t=!0),r.visible?e._wasLooping&&!e._loop&&e.loop():(e._wasLooping=e._loop,e.noLoop())})).observe(r)}}e._setCanvasSize(t,i),Object.assign(r,o);let s=e._createCanvas(r.w,r.h,o);return e._addEventMethods&&e._addEventMethods(r),e.canvas.ready=!0,s},e.createGraphics=function(t,r,n={}){"string"==typeof n&&(n={renderer:n});let i=new Q5("graphics",void 0,n.renderer||(e._webgpuFallback?"webgpu-fallback":e._renderer));n.alpha??=!0,n.colorSpace??=e.canvas.colorSpace,n.pixelDensity??=e._pixelDensity,i._defaultImageScale=e._defaultImageScale,i.createCanvas.call(e,t,r,n);let a=i._pixelDensity*e._defaultImageScale;return i.defaultWidth=t*a,i.defaultHeight=r*a,i},e._setCanvasSize=(n,i)=>{i??=n??window.innerHeight,n??=window.innerWidth,r.w=n=Math.ceil(n),r.h=i=Math.ceil(i),t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity),t.width=n,t.height=i,e.displayMode&&!r.displayMode?e.displayMode():e._adjustDisplay(!0)},e._setImageSize=(n,i)=>{t.width=r.w=n,t.height=r.h=i,t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity)},e.defaultImageScale=t=>t?(e._g&&(e._g._defaultImageScale=t),e._defaultImageScale=t):e._defaultImageScale,e.defaultImageScale(.5),!e._isImage){if(r&&!e._isGraphics){function n(){let t=e._parent;if(t??=document.getElementsByTagName("main")[0],!t){t=document.createElement("main"),(document.body||document.documentElement).appendChild(t)}r.parent(t),document.body||document.addEventListener("DOMContentLoaded",(()=>{document.body&&document.body.appendChild(t)}))}r.parent=t=>{function n(){e.frameCount>1&&(e._didResize=!0,e._adjustDisplay())}r.parentElement&&r.parentElement.removeChild(r),"string"==typeof t&&(t=document.getElementById(t)),t.append(r),"function"==typeof ResizeObserver?(e._ro&&e._ro.disconnect(),e._ro=new ResizeObserver(n),e._ro.observe(t)):e.frameCount||window.addEventListener("resize",n)},n()}e.resizeCanvas=(t,n)=>{if(!e.ctx)return e.createCanvas(t,n);t==r.w&&n==r.h||e._resizeCanvas(t,n)},r&&!Q5._createServerCanvas&&(r.resize=e.resizeCanvas),e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._resizeCanvas(r.w,r.h),e._g&&e._g.pixelDensity(t),t):e._pixelDensity,window&&!e._isGraphics&&window.addEventListener("resize",(()=>{e._didResize=!0,t.windowWidth=window.innerWidth,t.windowHeight=window.innerHeight,t.deviceOrientation=window.screen?.orientation?.type}))}},Q5.CENTER="center",Q5.LEFT="left",Q5.RIGHT="right",Q5.TOP="top",Q5.BOTTOM="bottom",Q5.BASELINE="alphabetic",Q5.MIDDLE="middle",Q5.NORMAL="normal",Q5.ITALIC="italic",Q5.BOLD="bold",Q5.BOLDITALIC="italic bold",Q5.ROUND="round",Q5.SQUARE="butt",Q5.PROJECT="square",Q5.MITER="miter",Q5.BEVEL="bevel",Q5.NONE="none",Q5.SIMPLE="simple",Q5.CHORD_OPEN=0,Q5.PIE_OPEN=1,Q5.PIE=2,Q5.CHORD=3,Q5.RADIUS="radius",Q5.CORNER="corner",Q5.CORNERS="corners",Q5.OPEN=0,Q5.CLOSE=1,Q5.VIDEO="video",Q5.AUDIO="audio",Q5.LANDSCAPE="landscape",Q5.PORTRAIT="portrait",Q5.BLEND="source-over",Q5.REMOVE="destination-out",Q5.ADD="lighter",Q5.DARKEST="darken",Q5.LIGHTEST="lighten",Q5.DIFFERENCE="difference",Q5.SUBTRACT="subtract",Q5.EXCLUSION="exclusion",Q5.MULTIPLY="multiply",Q5.SCREEN="screen",Q5.REPLACE="copy",Q5.OVERLAY="overlay",Q5.HARD_LIGHT="hard-light",Q5.SOFT_LIGHT="soft-light",Q5.DODGE="color-dodge",Q5.BURN="color-burn",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.SEPIA=9,Q5.BRIGHTNESS=10,Q5.SATURATION=11,Q5.CONTRAST=12,Q5.HUE_ROTATE=13,Q5.C2D=Q5.P2D=Q5.P2DHDR="c2d",Q5.WEBGL="webgl",Q5.GPU=Q5.WEBGPU="webgpu",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.renderers.c2d={},Q5.renderers.c2d.canvas=(e,t)=>{let r=e.canvas;function n(){let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r]}e.colorMode&&e.colorMode("rgb",e._webgpu?1:255),e._createCanvas=function(n,i,a){if(r)return t.ctx=t.drawingContext=r.getContext("2d",a),e._isImage||(e.ctx.fillStyle=e._fill="white",e.ctx.strokeStyle=e._stroke="black",e.ctx.lineCap="round",e.ctx.lineJoin="miter",e.ctx.textAlign="left",e._strokeWeight=1),e.ctx.scale(e._pixelDensity,e._pixelDensity),e.ctx.save(),r;console.error("q5 canvas could not be created. skia-canvas and jsdom packages not found.")},e.clear=()=>{e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e._isImage||(e.background=function(t){e.ctx.save(),e.ctx.resetTransform(),e.ctx.globalAlpha=1,t.canvas?e.image(t,0,0,e.canvas.width,e.canvas.height):(Q5.Color&&!t._isColor&&(t=e.color(...arguments)),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height)),e.ctx.restore()},e._resizeCanvas=(t,n)=>{let i,a={};for(let t in e.ctx)"function"!=typeof e.ctx[t]&&(a[t]=e.ctx[t]);if(delete a.canvas,e.frameCount>1){i=new e._Canvas(r.width,r.height),i.w=r.w,i.h=r.h,i.getContext("2d").drawImage(r,0,0)}e._setCanvasSize(t,n);for(let t in a)e.ctx[t]=a[t];e.scale(e._pixelDensity),i&&e.ctx.drawImage(i,0,0,i.w,i.h)},e.fill=function(t){if(e._doFill=e._fillSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doFill=!1;e.ctx.fillStyle=e._fill=t.toString()},e.stroke=function(t){if(e._doStroke=e._strokeSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=e._stroke=t.toString()},e.strokeWeight=t=>{t||(e._doStroke=!1),e.ctx.lineWidth=e._strokeWeight=t||1e-4},e.noFill=()=>e._doFill=!1,e.noStroke=()=>e._doStroke=!1,e.opacity=t=>e.ctx.globalAlpha=t,e._getFillIdx=()=>e._fill,e._setFillIdx=t=>e._fill=t,e._getStrokeIdx=()=>e._stroke,e._setStrokeIdx=t=>e._stroke=t,e._doShadow=!1,e._shadowOffsetX=e._shadowOffsetY=e._shadowBlur=10,e.shadow=function(t){if(Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doShadow=!1;e.ctx.shadowColor=e._shadow=t.toString(),e._doShadow=!0,e.ctx.shadowOffsetX||=e._shadowOffsetX,e.ctx.shadowOffsetY||=e._shadowOffsetY,e.ctx.shadowBlur||=e._shadowBlur},e.shadowBox=(t,r,n)=>{e.ctx.shadowOffsetX=e._shadowOffsetX=t,e.ctx.shadowOffsetY=e._shadowOffsetY=r||t,e.ctx.shadowBlur=e._shadowBlur=n||0},e.noShadow=()=>{e._doShadow=!1,e.ctx.shadowOffsetX=e.ctx.shadowOffsetY=e.ctx.shadowBlur=0},e.translate=(t,r)=>{t.x&&(r=t.y,t=t.x),e.ctx.translate(t,r)},e.rotate=t=>{e._angleMode&&(t=e.radians(t)),e.ctx.rotate(t)},e.scale=(t,r)=>{t.x&&(r=t.y,t=t.x),r??=t,e.ctx.scale(t,r)},e.applyMatrix=(t,r,n,i,a,o)=>e.ctx.transform(t,r,n,i,a,o),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&&(e.ctx.resetTransform(),e.scale(e._pixelDensity),e._webgpu&&e.translate(e.halfWidth,e.halfHeight))},e._styleNames=["_fill","_stroke","_strokeWeight","_doFill","_doStroke","_fillSet","_strokeSet","_shadow","_doShadow","_shadowOffsetX","_shadowOffsetY","_shadowBlur","_tint","_textSize","_textAlign","_textBaseline","_imageMode","_rectMode","_ellipseMode","_colorMode","_colorFormat","Color"],e._styles=[],e.pushStyles=()=>{let t={};for(let r of e._styleNames)t[r]=e[r];e._styles.push(t),e._fontMod&&e._updateFont()},e.popStyles=()=>{n(),e.ctx.fillStyle=e._fill,e.ctx.strokeStyle=e._stroke,e.ctx.lineWidth=e._strokeWeight,e.ctx.shadowColor=e._shadow,e.ctx.shadowOffsetX=e._doShadow?e._shadowOffsetX:0,e.ctx.shadowOffsetY=e._doShadow?e._shadowOffsetY:0,e.ctx.shadowBlur=e._doShadow?e._shadowBlur:0},e.pushMatrix=()=>e.ctx.save(),e.popMatrix=()=>e.ctx.restore(),e.push=()=>{e.pushStyles(),e.ctx.save()},e.pop=()=>{e.ctx.restore(),n()})},Q5.renderers.c2d.shapes=e=>{e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=Q5.CENTER,e._rectMode=Q5.CORNER;let t=!0,r=[];function n(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}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=()=>{},e.line=(t,r,n,i)=>{e._doStroke&&(e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(n,i),e.ctx.stroke())};const i=2*Math.PI;function a(t,r,n,a,o,s,l){if(e._angleMode&&(o=e.radians(o),s=e.radians(s)),(o%=i)<0&&(o+=i),(s%=i)<0&&(s+=i),o>s&&(s+=i),o==s)return e.ellipse(t,r,n,a);if(n/=2,a/=2,n=Math.abs(n),a=Math.abs(a),e._doFill||l!=e.PIE_OPEN||(l=e.CHORD_OPEN),e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),l!=e.PIE&&l!=e.PIE_OPEN||e.ctx.lineTo(t,r),e._doFill&&e.ctx.fill(),e._doStroke){if(l!=e.PIE&&l!=e.CHORD||e.ctx.closePath(),l!=e.PIE_OPEN)return e.ctx.stroke();e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),e.ctx.stroke()}}function o(t,r,a,o){e.ctx.beginPath(),e.ctx.ellipse(t,r,Math.abs(a/2),Math.abs(o/2),0,0,i),n()}function s(t,r,i,a,o,l,d,c){return void 0===o?function(t,r,i,a){e.ctx.beginPath(),e.ctx.rect(t,r,i,a),n()}(t,r,i,a):void 0===l?s(t,r,i,a,o,o,o,o):(e.ctx.beginPath(),e.ctx.roundRect(t,r,i,a,[o,l,d,c]),void n())}e.arc=(t,r,n,i,o,s,l)=>{if(o==s)return e.ellipse(t,r,n,i);l??=e.PIE_OPEN,e._ellipseMode==e.CENTER?a(t,r,n,i,o,s,l):e._ellipseMode==e.RADIUS?a(t,r,2*n,2*i,o,s,l):e._ellipseMode==e.CORNER?a(t+n/2,r+i/2,n,i,o,s,l):e._ellipseMode==e.CORNERS&&a((t+n)/2,(r+i)/2,n-t,i-r,o,s,l)},e.ellipse=(t,r,n,i)=>{i??=n,e._ellipseMode==e.CENTER?o(t,r,n,i):e._ellipseMode==e.RADIUS?o(t,r,2*n,2*i):e._ellipseMode==e.CORNER?o(t+n/2,r+i/2,n,i):e._ellipseMode==e.CORNERS&&o((t+n)/2,(r+i)/2,n-t,i-r)},e.circle=(t,r,a)=>{e._ellipseMode==e.CENTER?(e.ctx.beginPath(),e.ctx.arc(t,r,Math.abs(a/2),0,i),n()):e.ellipse(t,r,a,a)},e.point=(t,r)=>{e._doStroke&&(t.x&&(r=t.y,t=t.x),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(t,r),e.ctx.stroke())},e.rect=(t,r,n,i=n,a,o,l,d)=>{e._rectMode==e.CENTER?s(t-n/2,r-i/2,n,i,a,o,l,d):e._rectMode==e.RADIUS?s(t-n,r-i,2*n,2*i,a,o,l,d):e._rectMode==e.CORNER?s(t,r,n,i,a,o,l,d):e._rectMode==e.CORNERS&&s(t,r,n-t,i-r,a,o,l,d)},e.square=(t,r,n,i,a,o,s)=>e.rect(t,r,n,n,i,a,o,s),e.capsule=(t,r,i,a,o)=>{const s=i-t,l=a-r,d=Math.hypot(s,l);if(0===d)return e.circle(t,r,2*o);const c=Math.atan2(l,s),h=-l/d*o,u=s/d*o;e.ctx.beginPath(),e.ctx.moveTo(t-h,r-u),e.ctx.arc(t,r,o,c-e.HALF_PI,c+e.HALF_PI,!0),e.ctx.lineTo(i+h,a+u),e.ctx.arc(i,a,o,c+e.HALF_PI,c-e.HALF_PI,!0),e.ctx.closePath(),n()},e.beginShape=()=>{r=[],e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),r=[],t=!0},e.endContour=()=>{r=[],t=!0},e.vertex=(n,i)=>{r=[],t?e.ctx.moveTo(n,i):e.ctx.lineTo(n,i),t=!1},e.bezierVertex=(t,n,i,a,o,s)=>{r=[],e.ctx.bezierCurveTo(t,n,i,a,o,s)},e.quadraticVertex=(t,n,i,a)=>{r=[],e.ctx.quadraticCurveTo(t,n,i,a)},e.bezier=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(n,i,a,o,s,l),e.endShape()},e.triangle=(t,r,n,i,a,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.endShape(e.CLOSE)},e.quad=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{r=[],t&&e.ctx.closePath(),n()},e.curveVertex=(n,i)=>{if(r.push([n,i]),r.length<4)return;let a=r.at(-4),o=r.at(-3),s=r.at(-2),l=r.at(-1),d=o[0]+(s[0]-a[0])/6,c=o[1]+(s[1]-a[1])/6,h=s[0]-(l[0]-o[0])/6,u=s[1]-(l[1]-o[1])/6;t&&(e.ctx.moveTo(o[0],o[1]),t=!1),e.ctx.bezierCurveTo(d,c,h,u,s[0],s[1])},e.curve=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(n,i),e.curveVertex(a,o),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,r,n,i)=>{const a=i*i*i,o=i*i;return e*(-.5*a+o-.5*i)+t*(1.5*a-2.5*o+1)+r*(-1.5*a+2*o+.5*i)+n*(.5*a-.5*o)},e.bezierPoint=(e,t,r,n,i)=>{const a=1-i;return Math.pow(a,3)*e+3*Math.pow(a,2)*i*t+3*a*Math.pow(i,2)*r+Math.pow(i,3)*n},e.curveTangent=(e,t,r,n,i)=>{const a=i*i;return e*(-3*a/2+2*i-.5)+t*(9*a/2-5*i)+r*(-9*a/2+4*i+.5)+n*(3*a/2-i)},e.bezierTangent=(e,t,r,n,i)=>{const a=1-i;return 3*n*Math.pow(i,2)-3*r*Math.pow(i,2)+6*r*a*i-6*t*a*i+3*t*Math.pow(a,2)-3*e*Math.pow(a,2)},e.erase=function(t,r){255==e._colorFormat&&(t&&(t/=255),r&&(r/=255)),e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgb(0 0 0 / ${t||1})`,e.ctx.strokeStyle=`rgb(0 0 0 / ${r||1})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInPath(t*n,r*n)},e.inStroke=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInStroke(t*n,r*n)}},Q5.renderers.c2d.image=(e,t)=>{const r=e.canvas;r&&(r.convertToBlob??=e=>new Promise((t=>{r.toBlob((e=>t(e)),e.type,e.quality)}))),e._tint=null;let n=null,i=null;e.createImage=(t,r,n={})=>(n.colorSpace??=e.canvas.colorSpace,n.defaultImageScale??=e._defaultImageScale,new Q5.Image(t,r,n)),e.loadImage=function(t,r,n){if(t.canvas)return t;if("gif"==t.slice(-3).toLowerCase())throw new Error("q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84");let i=[...arguments].at(-1);"object"==typeof i?(n=i,r=null):n=void 0;let a=e.createImage(1,1,n),o=a._pixelDensity,s=new window.Image;return s.crossOrigin="Anonymous",a.promise=new Promise(((t,i)=>{s.onload=()=>{delete a.then,a._usedAwait&&(a=e.createImage(1,1,n)),s._pixelDensity=o,a.defaultWidth=s.width*e._defaultImageScale,a.defaultHeight=s.height*e._defaultImageScale,a.naturalWidth=s.naturalWidth||s.width,a.naturalHeight=s.naturalHeight||s.height,a._setImageSize(Math.ceil(a.naturalWidth/o),Math.ceil(a.naturalHeight/o)),a.ctx.drawImage(s,0,0),r&&r(a),t(a)},s.onerror=i})),e._loaders.push(a.promise),a.then=(e,t)=>(a._usedAwait=!0,a.promise.then(e,t)),a.src=s.src=t,a},e._imageMode=Q5.CORNER,e.imageMode=t=>e._imageMode=t,e.image=(t,r,n,i,a,o=0,s=0,l,d)=>{if(!t)return;let c=t.canvas||t;i??=t.defaultWidth||c.width||t.videoWidth,a??=t.defaultHeight||c.height||t.videoHeight,"center"==e._imageMode&&(r-=.5*i,n-=.5*a);let h=t._pixelDensity||1;if(l?l*=h:l=c.width||c.videoWidth,d?d*=h:d=c.height||c.videoHeight,e._tint){if(t._retint||t._tint!=e._tint){t._tintImg??=e.createImage(t.w,t.h,{pixelDensity:h}),t._tintImg.width==t.width&&t._tintImg.height==t.height||t._tintImg.resize(t.w,t.h);let r=t._tintImg.ctx;r.globalCompositeOperation="copy",r.fillStyle=e._tint,r.fillRect(0,0,t.width,t.height),t?.canvas?.alpha&&(r.globalCompositeOperation="destination-in",r.drawImage(c,0,0,t.width,t.height)),r.globalCompositeOperation="multiply",r.drawImage(c,0,0,t.width,t.height),t._tint=e._tint,t._retint=!1}c=t._tintImg.canvas}t.flipped&&(e.ctx.save(),e.ctx.translate(r+i,0),e.ctx.scale(-1,1),r=0),e.ctx.drawImage(c,o*h,s*h,l,d,r,n,i,a),t.flipped&&e.ctx.restore()},e.filter=(t,n)=>{e.ctx.save();let i="";if(e.ctx.filter){if("string"==typeof t)i=t;else if(t==Q5.GRAY)i="saturate(0%)";else if(t==Q5.INVERT)i="invert(100%)";else if(t==Q5.BLUR){i=`blur(${Math.ceil(n*e._pixelDensity)||1}px)`}else if(t==Q5.THRESHOLD){n??=.5,i=`saturate(0%) brightness(${Math.floor(.5/Math.max(n,1e-5)*100)}%) contrast(1000000%)`}else if(t==Q5.SEPIA)i=`sepia(${n??1})`;else if(t==Q5.BRIGHTNESS)i=`brightness(${n??1})`;else if(t==Q5.SATURATION)i=`saturate(${n??1})`;else if(t==Q5.CONTRAST)i=`contrast(${n??1})`;else if(t==Q5.HUE_ROTATE){i=`hue-rotate(${n}${0==e._angleMode?"rad":"deg"})`}if(i&&(e.ctx.filter=i,"none"==e.ctx.filter))throw new Error(`Invalid filter format: ${t}`)}i||e._softFilter(t,n),e.ctx.globalCompositeOperation="source-over",e.ctx.drawImage(r,0,0,r.w,r.h),e.ctx.restore(),e.modified=e._retint=!0},e._isImage&&(e.resize=(t,n)=>{let i=new e._Canvas(r.width,r.height);i.getContext("2d",{colorSpace:r.colorSpace}).drawImage(r,0,0),e._setImageSize(t,n),e.defaultWidth=r.width*e._defaultImageScale,e.defaultHeight=r.height*e._defaultImageScale,e.ctx.clearRect(0,0,r.width,r.height),e.ctx.drawImage(i,0,0,r.width,r.height),e.modified=e._retint=!0}),e._getImageData=(t,n,i,a)=>e.ctx.getImageData(t,n,i,a,{colorSpace:r.colorSpace}),e.trim=()=>{let t=e._pixelDensity||1,n=r.width,i=r.height,a=e._getImageData(0,0,n,i).data,o=n,s=0,l=i,d=0,c=3;for(let e=0;e<i;e++)for(let t=0;t<n;t++)0!==a[c]&&(t<o&&(o=t),t>s&&(s=t),e<l&&(l=e),e>d&&(d=e)),c+=4;return l=Math.floor(l/t),d=Math.floor(d/t),o=Math.floor(o/t),s=Math.floor(s/t),e.get(o,l,s-o+1,d-l+1)},e.mask=t=>{e.ctx.save(),e.ctx.resetTransform();let r=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="destination-in",e.ctx.drawImage(t.canvas,0,0),e.ctx.globalCompositeOperation=r,e.ctx.restore(),e.modified=e._retint=!0},e.inset=(t,n,i,a,o,s,l,d)=>{let c=e._pixelDensity||1;e.ctx.drawImage(r,t*c,n*c,i*c,a*c,o,s,l,d),e.modified=e._retint=!0},e.copy=()=>{let t=e.get();for(let r in e)"function"==typeof e[r]||/(canvas|ctx|texture)/.test(r)||(t[r]=e[r]);return t},e.get=(t,n,a,o)=>{let s=e._pixelDensity||1;if(void 0!==t&&void 0===a){i||e.loadPixels();let a=Math.floor(t*s),o=4*(Math.floor(n*s)*r.width+a);return[i[o],i[o+1],i[o+2],i[o+3]]}t=Math.floor(t||0)*s,n=Math.floor(n||0)*s,a??=e.width,o??=e.height;let l=e.createImage(a,o,{pixelDensity:s});return l.ctx.drawImage(r,t,n,a*s,o*s,0,0,a,o),l.width=a,l.height=o,e._webgpuInst&&e._webgpuInst._makeDrawable(l),l},e.set=(t,n,a)=>{if(t=Math.floor(t),n=Math.floor(n),e.modified=e._retint=!0,a.canvas){let r=e._tint;return e._tint=null,e.image(a,t,n),void(e._tint=r)}i||e.loadPixels();let o=e._pixelDensity||1;for(let e=0;e<o;e++)for(let s=0;s<o;s++){let l=4*((n*o+e)*r.width+t*o+s);i[l]=a.r,i[l+1]=a.g,i[l+2]=a.b,i[l+3]=a.a}},e.loadPixels=()=>{n=e._getImageData(0,0,r.width,r.height),t.pixels=i=n.data},e.updatePixels=()=>{null!=n&&(e.ctx.putImageData(n,0,0),e.modified=e._retint=!0)},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,e._isImage||(e.tint=function(t){e._tint=(t._isColor?t:e.color(...arguments)).toString()},e.noTint=()=>e._tint=null)},Q5.Image=class{constructor(e,t,r={}){r.alpha??=!0,r.colorSpace??=Q5.canvasOptions.colorSpace;let n=this;n._isImage=!0,n.canvas=n.ctx=n.drawingContext=null,n.pixels=[],Q5.modules.canvas(n,n);let i=Q5.renderers.c2d;for(let e of["canvas","image","softFilters"])i[e]&&i[e](n,n);n._pixelDensity=r.pixelDensity||1,n._defaultImageScale=r.defaultImageScale||2,n.createCanvas(e,t,r);let a=n._pixelDensity*n._defaultImageScale;n.defaultWidth=e*a,n.defaultHeight=t*a,delete n.createCanvas,n._loop=!1}get w(){return this.width}get h(){return this.height}},Q5.renderers.c2d.softFilters=e=>{let t=null;function r(){let r=e.canvas.width*e.canvas.height*4;t&&t.length==r||(t=new Uint8ClampedArray(r))}e._softFilter=(n,i)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let r=0;r<e.length;r+=4){const n=.2126*e[r]+.7152*e[r+1]+.0722*e[r+2];e[r]=e[r+1]=e[r+2]=n>=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t<e.length;t+=4){const r=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];e[t]=e[t+1]=e[t+2]=r}},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 r=t-1;for(let n=0;n<e.length;n+=4)e[n]=255*(e[n]*t>>8)/r,e[n+1]=255*(e[n+1]*t>>8)/r,e[n+2]=255*(e[n+2]*t>>8)/r},e._filters[Q5.DILATE]=(n,i)=>{i??=Math.max,r(),t.set(n);let[a,o]=[e.canvas.width,e.canvas.height];for(let e=0;e<o;e++)for(let r=0;r<a;r++){let s=4*Math.max(r-1,0),l=4*Math.min(r+1,a-1),d=4*Math.max(e-1,0)*a,c=4*Math.min(e+1,o-1)*a,h=4*e*a,u=4*r;for(let e=0;e<4;e++){let r=e+d,a=e+c,o=e+h;n[h+u+e]=i(t[r+u],t[o+s],t[o+u],t[o+l],t[a+u])}}},e._filters[Q5.ERODE]=t=>{e._filters[Q5.DILATE](t,Math.min)},e._filters[Q5.BLUR]=(n,i)=>{i=i||1,i=Math.floor(i*e._pixelDensity),r(),t.set(n);let a=2*i+1,o=function(e){let t=new Float32Array(e),r=.3*i+.8,n=r*r*2;for(let i=0;i<e;i++){let a=i-e/2,o=Math.exp(-a*a/n)/(2.5066282746*r);t[i]=o}return t}(a),[s,l]=[e.canvas.width,e.canvas.height];for(let e=0;e<l;e++)for(let r=0;r<s;r++){let l=0,d=0,c=0,h=0;for(let n=0;n<a;n++){let a=4*(e*s+Math.min(Math.max(r-i+n,0),s-1));l+=t[a]*o[n],d+=t[a+1]*o[n],c+=t[a+2]*o[n],h+=t[a+3]*o[n]}let u=4*(e*s+r);n[u]=l,n[u+1]=d,n[u+2]=c,n[u+3]=h}t.set(n);for(let e=0;e<l;e++)for(let r=0;r<s;r++){let d=0,c=0,h=0,u=0;for(let n=0;n<a;n++){let a=4*(Math.min(Math.max(e-i+n,0),l-1)*s+r);d+=t[a]*o[n],c+=t[a+1]*o[n],h+=t[a+2]*o[n],u+=t[a+3]*o[n]}let f=4*(e*s+r);n[f]=d,n[f+1]=c,n[f+2]=h,n[f+3]=u}});let a=e._getImageData(0,0,e.canvas.width,e.canvas.height);e._filters[n](a.data,i),e.ctx.putImageData(a,0,0)}},Q5.renderers.c2d.text=(e,t)=>{e._textAlign="left",e._textBaseline="alphabetic",e._textSize=12;let r="sans-serif",n=!1,i=15,a=3,o="normal",s="normal",l=0,d=!1,c=0;e._fontMod=!1;let h=e._textCache={};e.loadFont=(t,r)=>{let n;if(t.includes("fonts.googleapis.com/css"))n=function(e,t){e.startsWith("http")||(e="https://"+e);const r=new URL(e).searchParams,n=r.get("family");if(!n)return console.error("Invalid Google Fonts URL: missing family parameter"),null;const i=n.split(":")[0];let a={family:i};return a.promise=(async()=>{try{const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch Google Font: ${r.status} ${r.statusText}`);let n,o=await r.text(),s=/@font-face\s*{([^}]*)}/g,l=/src:\s*url\(([^)]+)\)[^;]*;/,d=/font-family:\s*['"]([^'"]+)['"]/,c=/font-weight:\s*([^;]+);/,h=/font-style:\s*([^;]+);/,u=[];for(;null!==(n=s.exec(o));){let e=n[1],t=l.exec(e);if(!t)continue;let r=t[1],i=d.exec(e);if(!i)continue;let a=i[1],o=c.exec(e),s=o?o[1]:"400",f=h.exec(e),p=f?f[1]:"normal",g=`${a}-${s}-${p}`.replace(/\s+/g,"-"),m=new FontFace(a,`url(${r})`,{weight:s,style:p});document.fonts.add(m);try{await m.load(),u.push(m)}catch(e){console.error(`Failed to load font face: ${g}`,e)}}return a._usedAwait&&(a={family:i}),a.faces=u,delete a.then,t&&t(a),a}catch(e){throw console.error("Error loading Google Font:",e),e}})(),a}(t,r);else{let e=t.split("/").pop().split(".")[0].replace(" ","");n={family:e};let i=new FontFace(e,`url(${encodeURI(t)})`);document.fonts.add(i),n.promise=new Promise(((e,t)=>{i.load().then((()=>{delete n.then,r&&r(i),e(i)})).catch((e=>{t(e)}))}))}return e._loaders.push(n.promise),e.textFont(n.family),n.then=(e,t)=>(n._usedAwait=!0,n.promise.then(e,t)),n},e.textFont=t=>{if(t&&"string"!=typeof t&&(t=t.family),!t||t==r)return r;r=t,e._fontMod=!0,l=-1},e.textSize=t=>{if(null==t)return e._textSize;e._textSize=t,e._fontMod=!0,l=-1,n||(i=1.25*t,a=i-t)},e.textStyle=t=>{if(!t)return o;o=t,e._fontMod=!0,l=-1},e.textWeight=t=>{if(!t)return s;s=t,e._fontMod=!0,l=-1},e.textLeading=t=>null==t?i||1.25*e._textSize:(n=!0,t==i?i:(i=t,a=t-e._textSize,void(l=-1))),e.textAlign=(t,r)=>{e.ctx.textAlign=e._textAlign=t,r&&(e.ctx.textBaseline=e._textBaseline=r==e.CENTER?"middle":r)},e._updateFont=()=>{e.ctx.font=`${o} ${s} ${e._textSize}px ${r}`,e._fontMod=!1},e.textWidth=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).width),e.textAscent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxDescent),e.textFill=e.fill,e.textStroke=e.stroke;e.createTextImage=(t,r,n)=>{d=!0;let i=e.text(t,0,0,r,n);return d=!1,i};let u=[];e.text=(t,n,s,f,p)=>{if(void 0===t||!e._doFill&&!e._doStroke)return;t=t.toString();let g,m,x,_,v,b,y,w,S=e.ctx;if(e._fontMod&&e._updateFont(),d)if(-1==l&&(()=>{let t=r+e._textSize+o+i,n=5381;for(let e=0;e<t.length;e++)n=33*n^t.charCodeAt(e);l=n>>>0})(),m=e._fill+e._stroke+e._strokeWeight,x=h[t],x?_=x[l]:x=h[t]={},_){if(g=_[m],g)return g;if(_.size>=4){for(let e in _){g=_[e],delete _[e];break}v=!0}}else _=x[l]={};if(-1==t.indexOf("\n")?u[0]=t:u=t.split("\n"),t.length>f){let e=[];for(let t of u){let r=0;for(;r<t.length;){let n=r+f;if(n>=t.length){e.push(t.slice(r));break}let i=t.lastIndexOf(" ",n);(-1===i||i<r)&&(i=n),e.push(t.slice(r,i)),r=i+1}}u=e}if(d){if(b=0,y=i,g){let e=g.canvas;g.ctx.clearRect(0,0,e.width,e.height),g.modified=!0}else{let t=e.ctx.textBaseline;e.ctx.textBaseline="alphabetic";let r=S.measureText(" "),n=r.fontBoundingBoxAscent,o=r.fontBoundingBoxDescent;e.ctx.textBaseline=t;let s=0;for(let e of u){let t=S.measureText(e).width;t>s&&(s=t)}let l=Math.ceil(s),d=Math.ceil(i*u.length+o);g=e.createImage.call(e,l,d,{pixelDensity:e._pixelDensity,defaultImageScale:1/e._pixelDensity}),g._ascent=n,g._descent=o,g._top=o+a,g._middle=g._top+.5*n+i*(u.length-1)*.5,g._bottom=g._top+n+i*(u.length-1),g._leading=i}S=g.ctx,S.font=e.ctx.font,S.fillStyle=e._fill,S.strokeStyle=e._stroke,S.lineWidth=e.ctx.lineWidth}else b=n,y=s,"middle"==e._textBaseline?y-=i*(u.length-1)*.5:"bottom"==e._textBaseline&&(y-=i*(u.length-1));e._fillSet||(w=S.fillStyle,S.fillStyle="black");let C=0;for(let t of u)if(e._doStroke&&e._strokeSet&&S.strokeText(t,b,y),e._doFill&&S.fillText(t,b,y),y+=i,C++,C>=p)break;if(u=[],e._fillSet||(S.fillStyle=w),d){if(_[m]=g,v||(_.size||(Object.defineProperty(_,"size",{writable:!0,enumerable:!1}),_.size=0),_.size++,c++),c>Q5.MAX_TEXT_IMAGES){for(const e in h){x=h[e];for(const e in x){_=x[e];for(let e in _){let t=_[e];t._texture&&t._texture.destroy(),delete _[e]}}}c=0}return g}},e.textImage=(t,r,n)=>{"string"==typeof t&&(t=e.createTextImage(t));let i=e._imageMode;e._imageMode="corner";let a=e._textAlign;"center"==a?r-=t.canvas.hw:"right"==a&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?n-=t._leading:"middle"==o?n-=t._middle:"bottom"==o?n-=t._bottom:"top"==o&&(n-=t._top),e.image(t,r,n),e._imageMode=i}},Q5.fonts=[],Q5.MAX_TEXT_IMAGES=5e3,Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e.RGBHDR=e._colorMode="rgb",e.HSL="hsl",e.HSB="hsb",e.OKLCH="oklch",e.SRGB="srgb",e.DISPLAY_P3="display-p3",e.colorMode=(r,n,i)=>{e._colorMode=r;let a="srgb"==e.canvas.colorSpace||"srgb"==i;e._srgb=a,n??="rgb"==r&&(e._c2d||a)?255:1,e._colorFormat="integer"==n||255==n?255:1,"oklch"==r?t.Color=Q5.ColorOKLCH:"hsl"==r?t.Color=a?Q5.ColorHSL:Q5.ColorHSL_P3:"hsb"==r?t.Color=a?Q5.ColorHSB:Q5.ColorHSB_P3:(255==e._colorFormat?t.Color=a?Q5.ColorRGB_8:Q5.ColorRGB_P3_8:t.Color=a?Q5.ColorRGB:Q5.ColorRGB_P3,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],coral:[255,127,80],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],silver:[192,192,192],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=(t,r,n,i)=>{let a=e.Color;if(t._isColor)return new a(...t.levels);if(null==r){if("string"==typeof t){if("#"==t[0])t.length<=5?(t.length>4&&(i=parseInt(t[4]+t[4],16)),n=parseInt(t[3]+t[3],16),r=parseInt(t[2]+t[2],16),t=parseInt(t[1]+t[1],16)):(t.length>7&&(i=parseInt(t.slice(7,9),16)),n=parseInt(t.slice(5,7),16),r=parseInt(t.slice(3,5),16),t=parseInt(t.slice(1,3),16));else{if(!e._namedColors[t]){let e=new a(0,0,0);return e._css=t,e.toString=function(){return this._css},e}if([t,r,n,i]=e._namedColors[t],"rgb"!=e._colorMode)return a=e._srgb?Q5.ColorRGB_8:Q5.ColorRGB_P3_8,new a(t,r,n,i)}1==e._colorFormat&&(t/=255,r&&(r/=255),n&&(n/=255),i&&(i/=255))}(Array.isArray(t)||t.constructor==Float32Array)&&([t,r,n,i]=t)}return null==n?e._colorMode==Q5.OKLCH?new a(t,0,0,r):new a(t,t,t,r):new a(t,r,n,i)},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=t=>{if(t.l)return t.l;let r=100*(.2126*t.r+.7152*t.g+.0722*t.b);return 255==e._colorFormat?r/255:r},e.hue=t=>{if(t.h)return t.h;let r=t.r,n=t.g,i=t.b;255==e._colorFormat&&(r/=255,n/=255,i/=255);let a,o=Math.max(r,n,i),s=Math.min(r,n,i);return a=o==s?0:o==r?60*(n-i)/(o-s):o==n?60*(i-r)/(o-s)+120:60*(r-n)/(o-s)+240,a<0&&(a+=360),a},e.lerpColor=(t,r,n)=>{if(n=Math.max(0,Math.min(1,n)),"rgb"==e._colorMode)return new e.Color(e.lerp(t.r,r.r,n),e.lerp(t.g,r.g,n),e.lerp(t.b,r.b,n),e.lerp(t.a,r.a,n));{let i=r.h-t.h;i>180&&(i-=360),i<-180&&(i+=360);let a=t.h+n*i;return a<0&&(a+=360),a>360&&(a-=360),new e.Color(e.lerp(t.l,r.l,n),e.lerp(t.c,r.c,n),a,e.lerp(t.a,r.a,n))}}},Q5.Color=class{constructor(){this._isColor=!0,this._q5Color=!0}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,r,n){super(),this.l=e,this.c=t,this.h=r,this.a=n??1}get levels(){return[this.l,this.c,this.h,this.a]}equals(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h&&this.a==e.a}isSameColor(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h}toString(){return`oklch(${this.l} ${this.c} ${this.h} / ${this.a})`}get lightness(){return this.l}set lightness(e){this.l=e}get chroma(){return this.c}set chroma(e){this.c=e}get hue(){return this.h}set hue(e){this.h=e}},Q5.ColorRGB=class extends Q5.Color{constructor(e,t,r,n){super(),this.r=e,this.g=t,this.b=r,this.a=n??1}get levels(){return[this.r,this.g,this.b,this.a]}equals(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b}toString(){return`color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`}get red(){return this.r}set red(e){this.r=e}get green(){return this.g}set green(e){this.g=e}get blue(){return this.b}set blue(e){this.b=e}},Q5.ColorRGB_P3=class extends Q5.ColorRGB{toString(){return`color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`}},Q5.ColorRGB_8=class extends Q5.ColorRGB{constructor(e,t,r,n){super(e,t,r,n??255)}setRed(e){this.r=e}setGreen(e){this.g=e}setBlue(e){this.b=e}setAlpha(e){this.a=e}toString(){return`rgb(${this.r} ${this.g} ${this.b} / ${this.a/255})`}},Q5.ColorRGB_P3_8=class extends Q5.ColorRGB_8{constructor(e,t,r,n){super(e,t,r,n??255),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),r=(this._b/255).toFixed(3),n=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${r} / ${n})`,this._edited=!1}return this._css}},Q5.ColorHSL=class extends Q5.Color{constructor(e,t,r,n){super(),this.h=e,this.s=t,this.l=r,this.a=n??1}get levels(){return[this.h,this.s,this.l,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l}toString(){return`hsl(${this.h} ${this.s} ${this.l} / ${this.a})`}get hue(){return this.h}set hue(e){this.h=e}get saturation(){return this.s}set saturation(e){this.s=e}get lightness(){return this.l}set lightness(e){this.l=e}},Q5.ColorHSL_P3=class extends Q5.ColorHSL{toString(){return`color(display-p3 ${Q5.HSLtoRGB(this.h,this.s,this.l).join(" ")} / ${this.a})`}},Q5.ColorHSB=class extends Q5.ColorHSL{constructor(e,t,r,n){super(e,t,r,n),delete this.l,this.b=r}get levels(){return[this.h,this.s,this.b,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b}toString(){return`hsl(${Q5.HSBtoHSL(this.h,this.s,this.b).join(" ")} / ${this.a})`}get v(){return this.b}set v(e){this.b=e}get brightness(){return this.b}set brightness(e){this.b=e}get value(){return this.b}set value(e){this.b=e}},Q5.ColorHSB_P3=class extends Q5.ColorHSB{toString(){return`color(display-p3 ${Q5.HSLtoRGB(...Q5.HSBtoHSL(this.h,this.s,this.b)).join(" ")} / ${this.a})`}},Q5.HSLtoRGB=(e,t,r)=>{r/=100;let n=t/100*Math.min(r,1-r),i=(t,i=(t+e/30)%12)=>r-n*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]},Q5.HSBtoHSL=(e,t,r,n=r*(1-t/200))=>[e,n&&100!=n?(r-n)/Math.min(n,100-n)*100:0,n];{const e=(e,t)=>[e[0]*t[0]+e[1]*t[1]+e[2]*t[2],e[3]*t[0]+e[4]*t[1]+e[5]*t[2],e[6]*t[0]+e[7]*t[1]+e[8]*t[2]],t=(e,t,r)=>[e,isNaN(r)?0:t*Math.cos(r*Math.PI/180),isNaN(r)?0:t*Math.sin(r*Math.PI/180)],r=e=>e.map((e=>Math.max(0,Math.min(1,Math.abs(e)>.0031308?(e<0?-1:1)*(1.055*Math.abs(e)**(1/2.4)-.055):12.92*e)))),n=t=>{const r=e([1,.3963377773761749,.2158037573099136,1,-.1055613458156586,-.0638541728258133,1,-.0894841775298119,-1.2914855480194092],t);return e([1.2268798758459243,-.5578149944602171,.2813910456659647,-.0405757452148008,1.112286803280317,-.0717110580655164,-.0763729366746601,-.4214933324022432,1.5869240198367816],r.map((e=>e**3)))},i=t=>e([3.2409699419045226,-1.537383177570094,-.4986107602930034,-.9692436362808796,1.8759675015077202,.04155505740717559,.05563007969699366,-.20397695888897652,1.0569715142428786],t);Q5.OKLCHtoRGB=(e,a,o)=>r(i(n(t(e,a,o))))}Q5.modules.display=e=>{if(!e.canvas||e._isGraphics)return;let t=e.canvas;e.MAXED="maxed",e.SMOOTH="smooth",e.PIXELATED="pixelated",0!=Q5._instanceCount||Q5._server||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 display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.q5-centered,\nmain.q5-maxed {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>"),e._adjustDisplay=e=>{let r=t.style;if(r)if("normal"==t.displayMode){if(!e)return;r.width=t.w*t.displayScale+"px",r.height=t.h*t.displayScale+"px"}else{let e=t.parentElement.getBoundingClientRect();t.w/t.h>e.width/e.height?("centered"==t.displayMode?(r.width=t.w*t.displayScale+"px",r.maxWidth="100%"):r.width="100%",r.height="auto",r.maxHeight=""):(r.width="auto",r.maxWidth="","centered"==t.displayMode?(r.height=t.h*t.displayScale+"px",r.maxHeight="100%"):r.height="100%")}},e.displayMode=(r="normal",n="smooth",i=1)=>{Q5._server||("string"==typeof i&&(i=parseFloat(i.slice(1))),"fullscreen"==r&&(r="maxed"),"center"==r&&(r="centered"),t.displayMode&&(t.parentElement.classList.remove("q5-"+t.displayMode),t.classList.remove("q5-pixelated")),t.parentElement.classList.add("q5-"+r),"pixelated"==n&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.defaultImageScale(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),Object.assign(t,{displayMode:r,renderQuality:n,displayScale:i}),e.ctx&&e.pushStyles(),e._adjustDisplay(!0),e.ctx&&e.popStyles())},e.fullscreen=e=>{if(null==e)return document.fullscreenElement;e?document.body.requestFullscreen():document.exitFullscreen()}},Q5.modules.dom=(e,t)=>{e.elementMode=t=>e._elementMode=t,e.createElement=(t,r)=>{let n=document.createElement(t);return"center"==e._elementMode&&(n.style.transform="translate(-50%, -50%)"),r&&(n.innerHTML=r),Object.defineProperty(n,"x",{get:()=>n._x,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetLeft+t;n.style.left=i+"px",n._x=i}}),Object.defineProperty(n,"y",{get:()=>n._y,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetTop+t;n.style.top=i+"px",n._y=i}}),Object.defineProperty(n,"width",{get:()=>parseFloat(n.style.width||0),set:e=>n.style.width=e+"px"}),Object.defineProperty(n,"height",{get:()=>parseFloat(n.style.height||0),set:e=>n.style.height=e+"px"}),n.position=(e,t,r)=>(r&&(n.style.position=r),n.x=e,n.y=t,n),Object.defineProperty(n,"size",{writable:!0}),n.size=(e,t)=>(n.width=e,n.height=t,n),n.center=()=>(n.style.position="absolute",n.x=e.canvas.hw,n.y=e.canvas.hh,n),n.show=()=>(n.style.display="",n),n.hide=()=>(n.style.display="none",n),n.parent=e=>(e.append(n),n),e._addEventMethods(n),e._elements.push(n),e.canvas?e.canvas.parentElement.append(n):document.body.append(n),n.elt=n,n},e.createEl=e.createElement,e._addEventMethods=e=>{let t=e.addEventListener;e.mousePressed=e=>t("mousedown",e),e.mouseReleased=e=>t("mouseup",e),e.mouseClicked=e=>t("click",e),e.mouseMoved=e=>t("mousemove",e),e.mouseWheel=e=>t("wheel",e)},e.createA=(t,r,n)=>{let i=e.createEl("a",r);return i.href=t,i.target=n?"_blank":"_self",i},e.createButton=t=>e.createEl("button",t),e.createCheckbox=(t="",r=!1)=>{let n=e.createEl("input");n.type="checkbox",n.checked=r;let i=e.createEl("label",t);return i.addEventListener("click",(()=>{n.checked=!n.checked,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))})),n.insertAdjacentElement("afterend",i),n.label=i,n},e.createColorPicker=(t="#ffffff")=>{let r=e.createEl("input");return r.type="color",r.value=t.toString(),r},e.createDiv=t=>e.createEl("div",t),e.createImg=t=>{let r=e.createEl("img");return r.crossOrigin="anonymous",r.src=t,r},e.createInput=(t="",r="text")=>{let n=e.createEl("input");return n.value=t,n.type=r,n.style.boxSizing="border-box",n},e.createP=t=>e.createEl("p",t);let r=0;function n(t){t.width||=t.videoWidth,t.height||=t.videoHeight,t.defaultWidth=t.width*e._defaultImageScale,t.defaultHeight=t.height*e._defaultImageScale,t.ready=!0}e.createRadio=t=>{let n=e.createEl("div");return n.name=t||"radio"+r++,n.buttons=[],Object.defineProperty(n,"value",{get:()=>n.selected?.value,set:e=>{let t=n.buttons.find((t=>t.value==e));t&&(t.checked=!0,n.selected=t)}}),n.option=(t,r)=>{let i=e.createEl("input");i.type="radio",i.name=n.name,i.value=r||t,i.addEventListener("input",(()=>n.selected=i));let a=e.createEl("label",t);return a.addEventListener("click",(()=>{i.checked=!0,n.selected=i,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0}))})),i.label=a,n.append(i),n.append(a),n.buttons.push(i),n},n},e.createSelect=t=>{let r=e.createEl("select");if(t){let n=e.createEl("option",t);n.disabled=!0,n.selected=!0,r.append(n)}return Object.defineProperty(r,"selected",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.textContent)):r.selectedOptions[0]?.textContent,set:e=>{if(r.multiple)Array.from(r.options).forEach((t=>{t.selected=e.includes(t.textContent)}));else{const t=Array.from(r.options).find((t=>t.textContent===e));t&&(t.selected=!0)}}}),Object.defineProperty(r,"value",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.value)):r.selectedOptions[0]?.value,set:e=>{if(r.multiple)r.options.forEach((t=>t.selected=e.includes(t.value)));else{let t;for(let n=0;n<r.options.length;n++)if(r.options[n].value==e){t=r.options[n];break}t&&(t.selected=!0)}}}),r.option=(t,n)=>{let i=e.createEl("option",t);return i.value=n||t,r.append(i),r},r},e.createSlider=(t,r,n,i)=>{let a=e.createEl("input");return a.type="range",a.min=t,a.max=r,a.step=i,a.value=n,a.val=()=>parseFloat(a.value),a},e.createSpan=t=>e.createEl("span",t),e.createVideo=t=>{let r=e.createEl("video");return r.crossOrigin="anonymous",t&&(r.promise=new Promise((i=>{r.addEventListener("loadeddata",(()=>{delete r.then,r._usedAwait&&(r=e.createEl("video"),r.crossOrigin="anonymous",r.src=t),n(r),i(r)})),r.src=t})),e._loaders.push(r.promise),r.then=(e,t)=>(r._usedAwait=!0,r.promise.then(e,t))),r},e.createCapture=function(t,r=!0,i){let a="string"==typeof t?{[t]:!0}:t||{video:!0,audio:!0};!0===a.video&&(a.video={width:3840,height:2160}),a.video.facingMode??="user";let o=e.createVideo();return o.promise=(async()=>{let t;try{t=await navigator.mediaDevices.getUserMedia(a)}catch(e){throw e}return delete o.then,o._usedAwait&&(o=e.createVideo()),function(t){t.playsinline=t.autoplay=!0,r&&(t.flipped=!0,t.style.transform="scale(-1, 1)"),t.loadPixels=()=>{let r=e.createGraphics(t.videoWidth,t.videoHeight,{renderer:"c2d"});r.image(t,0,0),r.loadPixels(),t.pixels=r.pixels,r.remove()}}(o),o.srcObject=t,await new Promise((e=>o.addEventListener("loadeddata",e))),n(o),i&&i(o),o})(),e._loaders.push(o.promise),o.then=(e,t)=>(o._usedAwait=!0,o.promise.then(e,t)),o},e.findElement=e=>document.querySelector(e),e.findElements=e=>document.querySelectorAll(e)},Q5.modules.fes=e=>{if(e._fes=async t=>{if(Q5.disableFriendlyErrors)return;t._handledByFES=!0;let r=t.stack?.split("\n");if(!r?.length)return;let n=1,i="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(n=0,i="@");r[n].indexOf("q5")>=0;)n++;let a=r[n].split(i).at(-1);a.startsWith("blob:")&&(a=a.slice(5)),a=a.split(")")[0];let o=a.split(":"),s=parseInt(o.at(-2));o[o.length-1]=o.at(-1).split(")")[0];let l=t.file||o.slice(0,-2).join(":"),d=l.split("/").at(-1);try{let t=(await(await fetch(l)).text()).split("\n"),r=t[s-1]?.trim()??"",n=["🐛","🐞","🐜","🦗","🦋","🪲"][Math.floor(6*Math.random())],i=window.self!==window.top,a=`q5.js ${n}`,o=` Error in ${d} on line ${s}:\n\n${r}`;i?e.log(a+o):e.log(`%c${a}%c${o}`,"background: #b7ebff; color: #000;","")}catch(e){}},"undefined"!=typeof window&&window.addEventListener){let t=new Error,r=t.stack?.split("\n")||"";for(let t of r){let r=t.match(/(https?:\/\/[^\s)]+\.js|\b\/[^\s)]+\.js)/);if(r){let t=r[1];if(!/q5|p5play/i.test(t)){e._sketchFile=t;break}}}e._sketchFile&&(window.addEventListener("error",(t=>{let r=t.error;t.filename!==e._sketchFile||r?._handledByFES||(r.file=t.filename,e._fes(r))})),window.addEventListener("unhandledrejection",(t=>{let r=t.reason;r?.stack?.includes(e._sketchFile)&&!r?._handledByFES&&e._fes(r)})))}if(e._isGlobal&&0!=Q5.online&&null!=typeof navigator&&navigator.onLine){!async function(){try{let e=await fetch("https://data.jsdelivr.com/v1/package/npm/q5");if(!e.ok)return;let t=(await e.json()).tags.latest;t=t.slice(0,t.lastIndexOf(".")),t!=Q5.version&&console.warn(`q5.js v${t} is now available! Consider updating from v${Q5.version}.`)}catch(e){}}()}},Q5.modules.input=(e,t)=>{if(e._isGraphics)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.pointers={},e.mouseButton="",e.keyIsPressed=!1,e.mouseIsPressed=!1,e.key="",e.keyCode=0,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 r={},n=[Q5.LEFT,Q5.CENTER,Q5.RIGHT],i=e.canvas;e._startAudio=()=>{Q5.aud&&"running"==Q5.aud?.state||e.userStartAudio()},e._updatePointer=r=>{let n=r.pointerId;e.pointers[n]??={event:r};let a,o,s=e.pointers[n];if(s.event=r,i){let t=i.getBoundingClientRect(),n=i.scrollWidth/e.width||1,s=i.scrollHeight/e.height||1;a=(r.clientX-t.left)/n,o=(r.clientY-t.top)/s,e._webgpu&&(a-=i.hw,o-=i.hh)}else a=r.clientX,o=r.clientY;s.x=a,s.y=o,!r.isPrimary&&r.pointerId||(document.pointerLockElement?(t.mouseX+=r.movementX,t.mouseY+=r.movementY):(t.mouseX=a,t.mouseY=o),t.moveX=r.movementX,t.moveY=r.movementY)};let a=0;function o(t){const r=e.canvas.getBoundingClientRect(),n=e.canvas.scrollWidth/e.width||1,i=e.canvas.scrollHeight/e.height||1;let a=0,o=0;return e._webgpu&&(a=e.halfWidth,o=e.halfHeight),{x:(t.clientX-r.left)/n-a,y:(t.clientY-r.top)/i-o,id:t.identifier}}if(e._onpointerdown=r=>{a++,e._startAudio(),e._updatePointer(r),t.mouseIsPressed=!0,t.mouseButton=n[r.button],e.mousePressed(r)},e._onpointermove=t=>{i&&!i.visible||(e._updatePointer(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t))},e._onpointerup=r=>{t.mouseIsPressed=!1,a>0&&(a--,e._updatePointer(r),delete e.pointers[r.pointerId],e.mouseReleased(r))},e._onclick=r=>{e._updatePointer(r),t.mouseIsPressed=!0,e.mouseClicked(r),t.mouseIsPressed=!1},e._ondblclick=r=>{e._updatePointer(r),t.mouseIsPressed=!0,e.doubleClicked(r),t.mouseIsPressed=!1},e._onwheel=t=>{e._updatePointer(t),t.delta=t.deltaY;let r=e.mouseWheel(t);(e._isGlobal&&!r||0==r)&&t.preventDefault()},e.cursor=(t,r,n)=>{let i="";t.includes(".")&&(t=`url("${t}")`,i=", auto"),void 0!==r&&(t+=" "+r+" "+n),e.canvas.style.cursor=t+i},e.noCursor=()=>e.canvas.style.cursor="none",e.pointerLock=(e=!1)=>{document.body?.requestPointerLock({unadjustedMovement:e})},e._onkeydown=n=>{n.repeat||(e._startAudio(),t.keyIsPressed=!0,t.key=n.key,t.keyCode=n.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!0,e.keyPressed(n),1==n.key.length&&e.keyTyped(n))},e._onkeyup=n=>{t.keyIsPressed=!1,t.key=n.key,t.keyCode=n.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!1,e.keyReleased(n)},e.keyIsDown=e=>!!r["string"==typeof e?e.toLowerCase():e],e._updateTouches=t=>{if(i&&!i.visible)return;let r=[...t.changedTouches].map(o);for(let t of r){let r=e.touches.find((e=>e.id==t.id));r?(r.x=t.x,r.y=t.y):e.touches.push(t)}for(let r=e.touches.length-1;r>=0;r--){let n=e.touches[r],i=!1;for(let e=0;e<t.touches.length;e++)if(t.touches[e].identifier===n.id){i=!0;break}i||e.touches.splice(r,1)}},e._ontouchstart=t=>{e._startAudio(),e.touchStarted(t)||t.preventDefault()},e._ontouchmove=t=>{e.touchMoved(t)||t.preventDefault()},e._ontouchend=t=>{e.touchEnded(t)||t.preventDefault()},window){let t=window.addEventListener;t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1);let r=window.PointerEvent?"pointer":"mouse";t(r+"move",(t=>e._onpointermove(t)),!1),t(r+"up",(t=>e._onpointerup(t))),t(r+"cancel",(t=>e._onpointerup(t))),t("touchstart",(t=>e._updateTouches(t))),t("touchmove",(t=>e._updateTouches(t))),t("touchend",(t=>e._updateTouches(t))),t("touchcancel",(t=>e._updateTouches(t))),i&&i.addEventListener("wheel",(t=>e._onwheel(t))),!e._isGlobal&&i&&(t=i.addEventListener.bind(i)),t(r+"down",(t=>e._onpointerdown(t))),t("click",(t=>e._onclick(t))),t("dblclick",(t=>e._ondblclick(t))),i&&(t=i.addEventListener.bind(i)),t("touchstart",(t=>e._ontouchstart(t))),t("touchmove",(t=>e._ontouchmove(t))),t("touchend",(t=>e._ontouchend(t))),t("touchcancel",(t=>e._ontouchend(t)))}},Q5.modules.math=(e,t)=>{e.RADIANS=0,e.DEGREES=1,e.PI=Math.PI,e.HALF_PI=Math.PI/2,e.QUARTER_PI=Math.PI/4,e.TWO_PI=e.TAU=2*Math.PI,e.abs=Math.abs,e.ceil=Math.ceil,e.exp=Math.exp,e.floor=e.int=Math.floor,e.loge=Math.log,e.mag=Math.hypot,e.max=Math.max,e.min=Math.min,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2,e.round=(e,t=0)=>{let r=10**t;return Math.round(e*r)/r};let r=e._angleMode=0;e.angleMode=t=>(r=e._angleMode=0==t||"radians"==t?0:1,r?"degrees":"radians");let n=e._DEGTORAD=Math.PI/180,i=e._RADTODEG=180/Math.PI;function a(){let e,t,r=4294967295;return{setSeed(n){e=t=(n??Math.random()*r)>>>0},getSeed:()=>t,rand:()=>(e^=e<<17,e^=e>>13,e^=e<<5,(e>>>0)/r)}}e.degrees=t=>t*e._RADTODEG,e.radians=t=>t*e._DEGTORAD,e.map=Q5.prototype.map=(e,t,r,n,i,a)=>{let o=n+1*(e-t)/(r-t)*(i-n);return a?n<i?Math.min(Math.max(o,n),i):Math.min(Math.max(o,i),n):o},e.dist=function(){let e=arguments;return 2==e.length?Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y):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.lerp=(e,t,r)=>e*(1-r)+t*r,e.constrain=(e,t,r)=>Math.min(Math.max(e,t),r),e.norm=(t,r,n)=>e.map(t,r,n,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=e=>Math.sin(r?e*n:e),e.cos=e=>Math.cos(r?e*n:e),e.tan=e=>Math.tan(r?e*n:e),e.asin=e=>{let t=Math.asin(e);return r?t*i:t},e.acos=e=>{let t=Math.acos(e);return r?t*i:t},e.atan=e=>{let t=Math.atan(e);return r?t*i:t},e.atan2=(e,t)=>{let n=Math.atan2(e,t);return r?n*i:n};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.jit=(t=1)=>e.random(-t,t),e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,r;return{setSeed(n){r=t=(n??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(r=(1664525*r+1013904223)%e,r/e)}}():t==e.SHR3&&(o=a()),o.setSeed()};var s=new function(){var e,t,r,n=new Array(128),i=new Array(256),a=new Array(128),s=new Array(128),l=new Array(256),d=new Array(256),c=()=>4294967296*o.rand()-2147483648,h=()=>.5+2.328306e-10*(c()|0),u=()=>{for(var t,i,o,l,d=3.44262;;){if(t=r*a[e],0==e){do{o=h(),l=h(),t=.2904764*-Math.log(o),i=-Math.log(l)}while(i+i<t*t);return r>0?d+t:-d-t}if(s[e]+h()*(s[e-1]-s[e])<Math.exp(-.5*t*t))return t;if(r=c(),e=127&r,Math.abs(r)<n[e])return r*a[e]}},f=()=>{for(var r;;){if(0==e)return 7.69711-Math.log(h());if(r=t*l[e],d[e]+h()*(d[e-1]-d[e])<Math.exp(-r))return r;if((t=c())<i[e=255&t])return t*l[e]}};this.SHR3=c,this.UNI=h,this.RNOR=()=>(r=c(),e=127&r,Math.abs(r)<n[e]?r*a[e]:u()),this.REXP=()=>(t=c()>>>0)<n[e=255&t]?t*l[e]:f(),this.zigset=()=>{var e,t,r=2147483648,o=4294967296,c=3.442619855899,h=c,u=.00991256303526217,f=7.697117470131487,p=f,g=.003949659822581572;for(e=u/Math.exp(-.5*c*c),n[0]=Math.floor(c/e*r),n[1]=0,a[0]=e/r,a[127]=c/r,s[0]=1,s[127]=Math.exp(-.5*c*c),t=126;t>=1;t--)c=Math.sqrt(-2*Math.log(u/c+Math.exp(-.5*c*c))),n[t+1]=Math.floor(c/h*r),h=c,s[t]=Math.exp(-.5*c*c),a[t]=c/r;for(e=g/Math.exp(-f),i[0]=Math.floor(f/e*o),i[1]=0,l[0]=e/o,l[255]=f/o,d[0]=1,d[255]=Math.exp(-f),t=254;t>=1;t--)f=-Math.log(g/f+Math.exp(-f)),i[t+1]=Math.floor(f/p*o),p=f,d[t]=Math.exp(-f),l[t]=f/o}};let l;s.hasInit=!1,e.randomGaussian=(e,t)=>(s.hasInit||(s.zigset(),s.hasInit=!0),s.RNOR()*t+e),e.randomExponential=()=>(s.hasInit||(s.zigset(),s.hasInit=!0),s.REXP()),e.PERLIN="perlin",e.SIMPLEX="simplex",e.BLOCKY="blocky",e.NoiseGenerator=Q5.PerlinNoise,e.noiseMode=e=>{t.NoiseGenerator=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],l=null},e.noiseSeed=t=>{l=new e.NoiseGenerator(t)},e.noise=(t=0,r=0,n=0)=>(l??=new e.NoiseGenerator,l.noise(t,r,n)),e.noiseDetail=(t,r)=>{l??=new e.NoiseGenerator,t>0&&(l.octaves=t),r>0&&(l.falloff=r)}},Q5.NoiseGenerator=class{},Q5.PerlinNoise=class extends Q5.NoiseGenerator{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,r,n=[];for(let e=0;e<256;e++)n[e]=e;for(let i=255;i>0;i--)t=(e=16807*e%2147483647)%(i+1),r=n[i],n[i]=n[t],n[t]=r;return n}dot(e,t,r,n){return e[0]*t+e[1]*r+e[2]*n}mix(e,t,r){return(1-r)*e+r*t}fade(e){return e*e*e*(e*(6*e-15)+10)}noise(e,t,r){let n=this,i=0,a=1,o=1,s=0;for(let l=0;l<n.octaves;l++){const l=255&Math.floor(e*a),d=255&Math.floor(t*a),c=255&Math.floor(r*a),h=e*a-Math.floor(e*a),u=t*a-Math.floor(t*a),f=r*a-Math.floor(r*a),p=n.fade(h),g=n.fade(u),m=n.fade(f),x=n.p[l]+d,_=n.p[x]+c,v=n.p[x+1]+c,b=n.p[l+1]+d,y=n.p[b]+c,w=n.p[b+1]+c,S=n.mix(n.dot(n.grad3[n.p[_]%12],h,u,f),n.dot(n.grad3[n.p[y]%12],h-1,u,f),p),C=n.mix(n.dot(n.grad3[n.p[v]%12],h,u-1,f),n.dot(n.grad3[n.p[w]%12],h-1,u-1,f),p),Q=n.mix(n.dot(n.grad3[n.p[_+1]%12],h,u,f-1),n.dot(n.grad3[n.p[y+1]%12],h-1,u,f-1),p),M=n.mix(n.dot(n.grad3[n.p[v+1]%12],h,u-1,f-1),n.dot(n.grad3[n.p[w+1]%12],h-1,u-1,f-1),p),P=n.mix(S,C,g),E=n.mix(Q,M,g);i+=n.mix(P,E,m)*o,s+=o,o*=n.falloff,a*=2}return(i/s+1)/2}},Q5.modules.record=(e,t)=>{let r,n,i,a,o,s,l;function d(t={}){document.head.insertAdjacentHTML("beforeend","<style>\n.rec {\n\tdisplay: flex;\n\tz-index: 1000;\n\tgap: 6px;\n\tbackground: #1a1b1d;\n\tpadding: 6px 8px;\n\tborder-radius: 21px;\n\tbox-shadow: #0000001a 0px 4px 12px;\n\tborder: 2px solid transparent; \n\topacity: 0.6;\n\ttransition: all 0.3s;\n\twidth: 134px;\n\toverflow: hidden;\n}\n\n.rec:hover {\n\twidth: unset;\n\topacity: 0.96;\n}\n\n.rec.recording { border-color: #cc3e44; }\n\n.rec button,\n.rec select { cursor: pointer; }\n\n.rec button,\n.rec select,\n.rec input,\n.rec span {\n\tfont-family: sans-serif;\n\tfont-size: 14px;\n\tpadding: 2px 10px;\n\tborder-radius: 18px;\n\toutline: none;\n\tbackground: #232529;\n\tcolor: #d4dae6;\n\tbox-shadow: #0000001a 0px 4px 12px;\n\tborder: 1px solid #46494e;\n\tvertical-align: middle;\n\tline-height: 18px;\n\ttransition: all 0.3s;\n}\n\n.rec .audio-toggle {\n\tfont-size: 16px;\n\tpadding: 2px 10px;\n}\n\n.rec .bitrate input {\n\tborder-radius: 18px 0 0 18px;\n\tborder-right: 0;\n\twidth: 40px;\n\tpadding: 2px 5px 2px 10px;\n\ttext-align: right;\n}\n\n.rec .bitrate span {\n\tborder-radius: 0 18px 18px 0;\n\tborder-left: 0;\n\tpadding: 2px 10px 2px 5px;\n\tbackground: #333;\n}\n\n.rec .record-button { \n\tcolor: #cc3e44;\n\tfont-size: 18px;\n}\n\n.rec select:hover,\n.rec button:hover { background: #32343b; }\n\n.rec button:disabled {\n\topacity: 0.5;\n\tcolor: #969ba5;\n\tcursor: not-allowed;\n}\n</style>"),r=e.createEl("div"),r.className="rec",r.innerHTML='\n<button class="record-button"></button>\n<span class="record-timer"></span>\n<button></button>\n',[n,a,i]=r.children,r.x=r.y=8,r.resetTimer=()=>r.time={hours:0,minutes:0,seconds:0,frames:0},r.resetTimer();let d="video/mp4; codecs=";r.formats={"H.264":d+'"avc1.42E01E"',VP9:d+"vp9"};let u=d+'"avc1.640034"';e.canvas.width*e.canvas.height>32e5&&MediaRecorder.isTypeSupported(u)&&(r.formats["H.264"]=u),Object.assign(r.formats,t.formats),o=e.createSelect("format");for(const e in r.formats)o.option(e,r.formats[e]);o.title="Video Format",r.append(o);let g=e.createEl("div");g.className="bitrate",g.style.display="flex",r.append(g),s=e.createInput();let m=document.createElement("span");function x(){r.encoderSettings.mimeType=o.value}function _(){r.encoderSettings.videoBitsPerSecond=1e6*s.value}m.textContent="mbps",s.title=m.title="Video Bitrate",g.append(s),g.append(m),l=e.createEl("button"),l.className="audio-toggle active",l.textContent="🔊",l.title="Toggle Audio Recording",r.append(l),r.captureAudio=!0,l.addEventListener("click",(()=>{r.captureAudio=!r.captureAudio,l.textContent=r.captureAudio?"🔊":"🔇",l.classList.toggle("active",r.captureAudio)})),r.encoderSettings={},o.addEventListener("change",x),s.addEventListener("change",_),Object.defineProperty(r,"bitrate",{get:()=>s.value,set:e=>{s.value=e,_()}}),Object.defineProperty(r,"format",{get:()=>o.selected,set:e=>{e=e.toUpperCase(),r.formats[e]&&(o.selected=e,x())}}),r.format="H.264";let v=e.canvas.height;r.bitrate=v>=4320?96:v>=2160?64:v>=1440?48:v>=1080?32:v>=720?26:16,n.addEventListener("click",(()=>{e.recording?r.paused?h():e.pauseRecording():c()})),i.addEventListener("click",(()=>{r.paused?e.saveRecording():e.deleteRecording()})),f(),e.registerMethod("post",p)}function c(){if(!e.recording){if(e.userStartAudio(),!r.stream){r.frameRate??=e.getTargetFrameRate();let t=e.canvas.captureStream(r.frameRate);if(r.videoTrack=t.getVideoTracks()[0],r.captureAudio&&e.getAudioContext){let t=e.getAudioContext(),n=t.createMediaStreamDestination();t.destination.input?t.destination.input.connect(n):Q5.soundOut.connect(n),r.audioTrack=n.stream.getAudioTracks()[0],r.stream=new MediaStream([r.videoTrack,r.audioTrack])}else r.stream=t}r.mediaRecorder=new MediaRecorder(r.stream,r.encoderSettings),r.chunks=[],r.mediaRecorder.addEventListener("dataavailable",(e=>{e.data.size>0&&r.chunks.push(e.data)})),r.mediaRecorder.start(),t.recording=!0,r.paused=!1,r.classList.add("recording"),r.resetTimer(),f(!0)}}function h(){e.recording&&r.paused&&(r.mediaRecorder.resume(),r.paused=!1,f(!0))}function u(){e.recording&&(r.resetTimer(),r.mediaRecorder.stop(),t.recording=!1,r.paused=!1,r.classList.remove("recording"))}function f(e){n.textContent=e?"⏸":"⏺",n.title=(e?"Pause":"Start")+" Recording",i.textContent=e?"🗑️":"💾",i.title=(e?"Delete":"Save")+" Recording",i.disabled=!e}function p(){if(e.recording&&!r.paused){r.time.frames++;let t=e.getTargetFrameRate();r.time.frames>=t&&(r.time.seconds+=Math.floor(r.time.frames/t),r.time.frames%=t,r.time.seconds>=60&&(r.time.minutes+=Math.floor(r.time.seconds/60),r.time.seconds%=60,r.time.minutes>=60&&(r.time.hours+=Math.floor(r.time.minutes/60),r.time.minutes%=60)))}a.textContent=function(){let{hours:e,minutes:t,seconds:n,frames:i}=r.time;return`${String(e).padStart(2,"0")}:${String(t).padStart(2,"0")}:${String(n).padStart(2,"0")}:${String(i).padStart(2,"0")}`}()}e.recording=!1,e.createRecorder=e=>(r||d(e),r),e.record=t=>{r||(d(t),r.hide()),e.recording?r.paused&&h():c()},e.pauseRecording=()=>{e.recording&&!r.paused&&(r.mediaRecorder.pause(),r.paused=!0,f(),n.title="Resume Recording",i.disabled=!1)},e.deleteRecording=()=>{u(),f(),t.recording=!1},e.saveRecording=async n=>{if(!e.recording)return;await new Promise((e=>{r.mediaRecorder.onstop=e,u()}));let i=r.encoderSettings.mimeType,a=i.slice(6,i.indexOf(";")),o=URL.createObjectURL(new Blob(r.chunks,{type:i})),s=document.createElement("iframe"),l=document.createElement("a");s.style.display="none",s.name="download_"+Date.now(),document.body.append(s),l.target=s.name,l.href=o,n??=document.title+" "+(new Date).toLocaleString(void 0,{hour12:!1}).replace(","," at").replaceAll("/","-").replaceAll(":","_"),l.download=`${n}.${a}`,await new Promise((e=>{s.onload=()=>{document.body.removeChild(s),e()},l.click()})),setTimeout((()=>URL.revokeObjectURL(o)),1e3),f(),t.recording=!1}},Q5.modules.sound=(e,t)=>{e.Sound=Q5.Sound;let r=[];e.loadSound=(t,n)=>{let i=new Q5.Sound;return r.push(i),i.promise=(async()=>{let e;i._usedAwait&&(r.splice(r.indexOf(i),1),i=new Q5.Sound,r.push(i));try{await i.load(t)}catch(t){e=t}if(delete i.then,e)throw e;return n&&n(i),i})(),e._loaders.push(i.promise),i.then=(e,t)=>(i._usedAwait=!0,i.promise.then(e,t)),i},e.loadAudio=(t,r)=>{let n=new Audio(t);return n._isAudio=!0,n.crossOrigin="Anonymous",n.promise=new Promise(((e,i)=>{function a(){n.loaded||(delete n.then,n._usedAwait&&(n=new Audio(t),n._isAudio=!0,n.crossOrigin="Anonymous"),n.loaded=!0,r&&r(n),e(n))}n.addEventListener("canplay",a),n.addEventListener("suspend",a),n.addEventListener("error",i)})),e._loaders.push(n.promise),n.then=(e,t)=>(n._usedAwait=!0,n.promise.then(e,t)),n},e.getAudioContext=()=>Q5.aud,e.userStartAudio=()=>{if(window.AudioContext){if(Q5._offlineAudio){Q5._offlineAudio=!1,Q5.aud=new window.AudioContext,Q5.soundOut=Q5.aud.createGain(),Q5.soundOut.connect(Q5.aud.destination);for(let e of Q5.instances)e._userAudioStarted()}return Q5.aud.resume()}},e._userAudioStarted=()=>{for(let e of r)e.init()},e.outputVolume=e=>{Q5.soundOut&&(Q5.soundOut.gain.value=e)}},window.OfflineAudioContext&&(Q5.aud=new window.OfflineAudioContext(2,1,44100),Q5._offlineAudio=!0,Q5.soundOut=Q5.aud.createGain(),Q5.soundOut.connect(Q5.aud.destination)),Q5.Sound=class{constructor(){this._isSound=!0,this.sources=new Set,this.loaded=this.paused=!1}async load(e){this.url=e;let t=await fetch(e);this.buffer=await t.arrayBuffer(),this.buffer=await Q5.aud.decodeAudioData(this.buffer),Q5.aud&&this.init()}init(){this.buffer.length&&(this.gainNode=Q5.aud.createGain(),this.pannerNode=Q5.aud.createStereoPanner(),this.gainNode.connect(this.pannerNode),this.pannerNode.connect(Q5.soundOut),this.loaded=!0,this._volume&&(this.volume=this._volume),this._pan&&(this.pan=this._pan))}_newSource(e,t){let r=Q5.aud.createBufferSource();r.buffer=this.buffer,r.connect(this.gainNode),r.loop=this._loop,r._startedAt=Q5.aud.currentTime,r._offset=e,r._duration=t,r.start(0,r._offset,r._duration),this.sources.add(r),r.onended=()=>{this.paused||(this.ended=!0,this._onended&&this._onended(),this.sources.delete(r))}}play(e=0,t){if(this.loaded){if(this.paused){let e=[];for(let t of this.sources)e.push(t._offset,t._duration),this.sources.delete(t);for(let t=0;t<e.length;t+=2)this._newSource(e[t],e[t+1])}else this._newSource(e,t);this.paused=this.ended=!1}}pause(){if(this.isPlaying()){for(let e of this.sources){e.stop();let t=Q5.aud.currentTime-e._startedAt;e._offset+=t,e._duration&&(e._duration-=t)}this.paused=!0}}stop(){for(let e of this.sources)e.stop(),this.sources.delete(e);this.paused=!1,this.ended=!0}get volume(){return this._volume}set volume(e){this.loaded&&(this.gainNode.gain.value=e),this._volume=e}get pan(){return this._pan}set pan(e){this.loaded&&(this.pannerNode.pan.value=e),this._pan=e}get loop(){return this._loop}set loop(e){this.sources.forEach((t=>t.loop=e)),this._loop=e}get playing(){return!this.paused&&this.sources.size>0}setVolume(e){this.volume=e}setPan(e){this.pan=e}setLoop(e){this.loop=e}isLoaded(){return this.loaded}isPlaying(){return this.playing}isPaused(){return this.paused}isLooping(){return this._loop}onended(e){this._onended=e}},Q5.modules.util=(e,t)=>{e._loadFile=(t,r,n)=>{let i={};return i.promise=fetch(t).then((e=>e.ok?"json"==n?e.json():e.text():(reject("error loading file"),null))).then((e=>("csv"==n&&(e=Q5.CSV.parse(e)),"string"==typeof e?i.text=e:Object.assign(i,e),delete i.then,r&&r(e),e))),e._loaders.push(i.promise),i.then=(e,t)=>i.promise.then(e,t),i},e.loadText=(t,r)=>e._loadFile(t,r,"text"),e.loadJSON=(t,r)=>e._loadFile(t,r,"json"),e.loadCSV=(t,r)=>e._loadFile(t,r,"csv"),e.loadXML=(t,r)=>{let n={};return n.promise=fetch(t).then((e=>e.text())).then((e=>{let t=(new DOMParser).parseFromString(e,"application/xml");return n.DOM=t,delete n.then,r&&r(t),t})),e._loaders.push(n.promise),n.then=(e,t)=>n.promise.then(e,t),n};const r=/(jpe?g|png|gif|webp|avif|svg)/i,n=/(ttf|otf|woff2?|eot|json)/i,i=/(serif|sans-serif|monospace|cursive|fantasy)/i,a=/(wav|flac|mp3|ogg|m4a|aac|aiff|weba)/i;async function o(e,t,n){let i;if(t=t||"untitled",n=n||"png",r.test(n)){let t=e.canvas||e;i=await t.convertToBlob({type:"image/"+n})}else{let t="text/plain";"json"==n&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),i=new Blob([e],{type:t})}let a=document.createElement("a");a.href=URL.createObjectURL(i),a.download=t+"."+n,a.click(),setTimeout((()=>URL.revokeObjectURL(a.href)),1e3)}e.load=function(...t){Array.isArray(t[0])&&(t=t[0]);let o=[];for(let s of t){let t,l=s.split(".").pop().toLowerCase();t="json"!=l||s.includes("-msdf.")?"csv"==l?e.loadCSV(s):r.test(l)?e.loadImage(s):n.test(l)||i.test(s)?e.loadFont(s):a.test(l)?e.loadSound(s):"xml"==l?e.loadXML(s):e.loadText(s):e.loadJSON(s),o.push(t)}return 1==t.length?o[0]:Promise.all(o)},e.save=(t,r,n)=>{if((!t||"string"==typeof t&&(!r||!n&&r.length<5))&&(n=r,r=t,t=e),n)o(t,r,n);else if(r){let e=r.lastIndexOf(".");o(t,r.slice(0,e),r.slice(e+1))}else o(t)},e.canvas&&!Q5._createServerCanvas&&(e.canvas.save=e.saveCanvas=e.save),"object"==typeof localStorage&&(e.storeItem=(e,t)=>localStorage.setItem(e,t),e.getItem=e=>localStorage.getItem(e),e.removeItem=e=>localStorage.removeItem(e),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(),e.nf=(e,t,r)=>{let n=e<0,i=(e=Math.abs(e)).toFixed(r).split(".");i[0]=i[0].padStart(t,"0");let a=i.join(".");return n&&(a="-"+a),a},e.shuffle=(t,r)=>{r||(t=[...t]);for(let r=t.length-1;r>0;r--){let n=Math.floor(e.random()*(r+1));[t[r],t[n]]=[t[n],t[r]]}return t}},Q5.CSV={},Q5.CSV.parse=(e,t=",",r="\n")=>{if(!e.length)return[];let n=[],i=e.split(r),a=i[0].split(t).map((e=>e.replaceAll('"',"")));for(let e=1;e<i.length;e++){let r={},o=i[e].split(t);a.forEach(((e,t)=>r[e]=JSON.parse(o[t]))),n.push(r)}return n},Q5.modules.vector=e=>{e.Vector=Q5.Vector,e.createVector=(t,r,n)=>new e.Vector(t,r,n,e)},Q5.Vector=class{constructor(e,t,r,n){this.x=e||0,this.y=t||0,this.z=r||0,this._isVector=!0,this._$=n||window,this._useCache=!1,this._mag=0,this._magCached=!1,this._direction=0,this._directionCached=!1}set(e,t,r){return this.x=e?.x||e||0,this.y=e?.y||t||0,this.z=e?.z||r||0,this}copy(){return new Q5.Vector(this.x,this.y,this.z)}_arg2v(e,t,r){return void 0!==e?.x?e:void 0!==t?{x:e,y:t,z:r||0}:{x:e,y:e,z:e}}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}_calcMag(){const e=this.x,t=this.y,r=this.z;this._mag=Math.sqrt(e*e+t*t+r*r),this._magCached=this._useCache}mag(){return this._magCached||this._calcMag(),this._mag}magSq(){if(this._magCached)return this._mag*this._mag;const e=this.x,t=this.y,r=this.z;return e*e+t*t+r*r}setMag(e){this._magCached||this._calcMag();let t=this._mag;if(0==t){const t=this.direction();this.x=e*this._$.cos(t),this.y=e*this._$.sin(t)}else{let r=e/t;this.x*=r,this.y*=r,this.z*=r}return this._mag=e,this._magCached=this._useCache,this}direction(){if(!this._directionCached){const e=this.x,t=this.y;(e||t)&&(this._direction=this._$.atan2(this.y,this.x)),this._directionCached=this._useCache}return this._direction}setDirection(e){let t=this.mag();return t&&(this.x=t*this._$.cos(e),this.y=t*this._$.sin(e)),this._direction=e,this._directionCached=this._useCache,this}heading(){return this.direction()}setHeading(e){return this.setDirection(e)}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,r=this.y-e.y,n=this.z-e.z;return Math.sqrt(t*t+r*r+n*n)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,r=this.z*e.x-this.x*e.z,n=this.x*e.y-this.y*e.x;return this.x=t,this.y=r,this.z=n,this}normalize(){this._magCached||this._calcMag();let e=this._mag;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._mag=1,this._magCached=this._useCache,this}limit(e){this._magCached||this._calcMag();let t=this._mag;if(t>e){let r=e/t;this.x*=r,this.y*=r,this.z*=r,this._mag=e,this._magCached=this._useCache}return this}rotate(e){let t=this._$.cos(e),r=this._$.sin(e),n=this.x*t-this.y*r,i=this.x*r+this.y*t;return this.x=n,this.y=i,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=e.at(-1);if(0==t)return this;let r=this._arg2v(...e.slice(0,-1));return this.x+=(r.x-this.x)*t,this.y+=(r.y-this.y)*t,this.z+=(r.z-this.z)*t,this}slerp(){let e=[...arguments],t=e.at(-1);if(0==t)return this;let r=this._arg2v(...e.slice(0,-1));if(1==t)return this.set(r);let n=this.mag(),i=r.mag();if(0==n||0==i)return this.mult(1-t).add(r.mult(t));let a=Q5.Vector.cross(this,r),o=a.mag(),s=Math.atan2(o,this.dot(r));if(o>0)a.div(o);else{if(s<this._$.HALF_PI)return this.mult(1-t).add(r.mult(t));0==this.z&&0==r.z?a.set(0,0,1):0!=this.x?a.set(this.y,-this.x,0).normalize():a.set(1,0,0)}let l=a.cross(this),d=1-t+t*i/n,c=d*Math.cos(t*s),h=d*Math.sin(t*s);return this.x=this.x*c+l.x*h,this.y=this.y*c+l.y*h,this.z=this.z*c+l.z*h,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._mag=t,this._magCached=this._useCache,this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this.z=0,this}fromAngles(e,t,r){void 0===r&&(r=1),this._mag=r,this._magCached=this._useCache;const n=this._$.cos(t),i=this._$.sin(t),a=this._$.cos(e),o=this._$.sin(e);return this.x=r*o*i,this.y=-r*a,this.z=r*o*n,this}random2D(){return this._mag=1,this._magCached=this._useCache,this.fromAngle(Math.random()*Math.PI*2)}random3D(){return this._mag=1,this._magCached=this._useCache,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,r)=>e.equals(t,r),Q5.Vector.lerp=(e,t,r)=>e.copy().lerp(t,r),Q5.Vector.slerp=(e,t,r)=>e.copy().slerp(t,r),Q5.Vector.limit=(e,t)=>e.copy().limit(t),Q5.Vector.direction=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),Q5.Vector.reflect=(e,t)=>e.copy().reflect(t),Q5.Vector.random2D=()=>(new Q5.Vector).random2D(),Q5.Vector.random3D=()=>(new Q5.Vector).random3D(),Q5.Vector.fromAngle=(e,t)=>(new Q5.Vector).fromAngle(e,t),Q5.Vector.fromAngles=(e,t,r)=>(new Q5.Vector).fromAngles(e,t,r),Q5.renderers.webgpu={},Q5.renderers.webgpu.canvas=(e,t)=>{const r=e.canvas;e.colorMode&&e.colorMode("rgb",1),e._baseShaderCode="\nstruct Q5 {\n\twidth: f32,\n\theight: f32,\n\thalfWidth: f32,\n\thalfHeight: f32,\n\tpixelDensity: f32,\n\tframeCount: f32,\n\ttime: f32,\n\tdeltaTime: f32,\n\tmouseX: f32,\n\tmouseY: f32,\n\tmouseIsPressed: f32,\n\tkeyCode: f32,\n\tkeyIsPressed: f32\n}",e._g=e.createGraphics(1,1,"c2d"),e._g.colorMode&&e._g.colorMode(e.RGB,1);let n,i,a,o,s,l,d,c,h,u,f=2,p=12,g=0,m=0;e._pipelineConfigs=[],e._pipelines=[],e._buffers=[];let x=[],_=new Float32Array(1e6);_.set([0,0,0,0,0,0,0,1,1,1,1,1]);let v=Q5.device.createBindGroupLayout({label:"mainLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}}]});e._bindGroupLayouts=[v];let b=Q5.device.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),y=()=>{let t=[e.canvas.width,e.canvas.height],r="bgra8unorm";a=Q5.device.createTexture({size:t,sampleCount:4,format:r,usage:GPUTextureUsage.RENDER_ATTACHMENT}).createView();let n=GPUTextureUsage.COPY_SRC|GPUTextureUsage.COPY_DST|GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT;e._frameA=s=Q5.device.createTexture({label:"frameA",size:t,format:r,usage:n}),e._frameB=o=Q5.device.createTexture({label:"frameB",size:t,format:r,usage:n}),e._frameShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex: u32\n}\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) texCoord: vec2f\n}\n\nconst ndc = array(vec2f(-1,-1), vec2f(1,-1), vec2f(-1,1), vec2f(1,1));\nconst quad = array(vec2f(0,1), vec2f(1,1), vec2f(0,0), vec2f(1,0));\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var samp: sampler;\n@group(0) @binding(2) var tex: texture_2d<f32>;\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tvar f: FragParams;\n\tf.position = vec4f(ndc[v.vertexIndex], 0.0, 1.0);\n\tf.texCoord = quad[v.vertexIndex];\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams ) -> @location(0) vec4f {\n\treturn textureSample(tex, samp, f.texCoord);\n}";let i=Q5.device.createShaderModule({label:"frameShader",code:e._frameShaderCode});d=Q5.device.createSampler({magFilter:"linear",minFilter:"linear"}),l=Q5.device.createBindGroupLayout({label:"frameLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]});let c=Q5.device.createPipelineLayout({bindGroupLayouts:[l]});e._pipelineConfigs[0]={layout:c,vertex:{module:i,entryPoint:"vertexMain"},fragment:{module:i,entryPoint:"fragMain",targets:[{format:r}]},primitive:{topology:"triangle-strip"},multisample:{count:4}},e._pipelines[0]=Q5.device.createRenderPipeline(e._pipelineConfigs[0]),h=Q5.device.createBindGroup({layout:l,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:d},{binding:2,resource:o.createView()}]}),u=Q5.device.createBindGroup({layout:l,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:d},{binding:2,resource:s.createView()}]})};e._createCanvas=(n,i,a)=>(t.ctx=t.drawingContext=r.getContext("webgpu"),a.format??=navigator.gpu.getPreferredCanvasFormat(),a.device??=Q5.device,a.alpha&&(a.alphaMode="premultiplied"),e.ctx.configure(a),y(),r),e._resizeCanvas=(t,r)=>{e._setCanvasSize(t,r),y()};let w=!0,S="rgb",C=1;if(e.colorMode){let t=e.colorMode;e.colorMode=function(){t(...arguments),S=e._colorMode,w="rgb"==S,C=e._colorFormat}}const Q=(t,r,n,i)=>{if(!1===w||void 0===r&&!t._isColor&&"number"!=typeof t?!1!==w&&"string"!=typeof t&&Array.isArray(t)?[t,r,n,i]=t:t=e.color(t,r,n,i):void 0===n&&(i=r??C,r=n=t),i??=C,t._isColor){let e=t;w?({r:t,g:r,b:n,a:i}=e):(i=e.a,e=null!=e.c?Q5.OKLCHtoRGB(e.l,e.c,e.h):null!=e.l?Q5.HSLtoRGB(e.h,e.s,e.l):Q5.HSLtoRGB(...Q5.HSBtoHSL(e.h,e.s,e.b)),[t,r,n]=e)}255===C&&(t/=255,r/=255,n/=255,i/=255);let a=_,o=p;a[o++]=t,a[o++]=r,a[o++]=n,a[o++]=i,p=o,f++};let M=!0,P=!0,E=!1,I=!1,R=1,A=2,T=2,k=1,O=1,G=.5,D=.25,B=.5;e.fill=(e,t,r,n)=>{Q(e,t,r,n),M=E=!0,A=f},e.stroke=(e,t,r,n)=>{Q(e,t,r,n),P=I=!0,R=f},e.tint=(e,t,r,n)=>{Q(e,t,r,n),T=f},e.opacity=e=>k=e,e.noFill=()=>M=!1,e.noStroke=()=>P=!1,e.noTint=()=>T=2,e.strokeWeight=e=>{if(void 0===e)return O;e?(e=Math.abs(e),O=e,G=e/2,D=e/4,B=G*W):P=!1},e._getStrokeWeight=()=>[O,G,D,B],e._setStrokeWeight=e=>{[O,G,D,B]=e},e._getFillIdx=()=>A,e._setFillIdx=e=>A=e,e._doFill=()=>M=!0,e._getStrokeIdx=()=>R,e._setStrokeIdx=e=>R=e,e._doStroke=()=>P=!0;const L=e._isGraphics?1e3:Q5.MAX_TRANSFORMS,F=16*L*4,z=new Float32Array(16*L);let U,N=[],V=[],H=0,q=!1;N.push([1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1]),z.set(N[0]),e.translate=(e,t)=>{if(!e&&!t)return;let r=U;r[12]+=e*r[0]+t*r[4],r[13]+=e*r[1]+t*r[5],q=!0},e.rotate=e.rotateZ=(t,r)=>{if(!t)return;let n,i;void 0===r?(e._angleMode&&(t*=e._DEGTORAD),n=Math.cos(t),i=Math.sin(t)):(n=t,i=r);let a=U,o=a[0],s=a[1],l=a[4],d=a[5];1!=o||s||l||1!=d?(a[0]=o*n+s*i,a[1]=s*n-o*i,a[4]=l*n+d*i,a[5]=d*n-l*i):(a[0]=n,a[1]=-i,a[4]=i,a[5]=n),q=!0};let W=1;e.scale=(e=1,t,r=1)=>{t??=e,W=Math.max(Math.abs(e),Math.abs(t)),B=G*W;let n=U;n[0]*=e,n[1]*=e,n[2]*=e,n[3]*=e,n[4]*=t,n[5]*=t,n[6]*=t,n[7]*=t,n[8]*=r,n[9]*=r,n[10]*=r,n[11]*=r,q=!0},e.shearX=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),n=U,i=n[0],a=n[1],o=n[4],s=n[5];n[4]=o+i*r,n[5]=s+a*r,q=!0},e.shearY=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),n=U,i=n[0],a=n[1],o=n[4],s=n[5];n[0]=i+o*r,n[1]=a+s*r,q=!0},e.applyMatrix=(...e)=>{let t;if(t=1==e.length?e[0]:e,t.length<=6){t=[t[0],t[1],0,t[2],t[3],0,t[4]||0,t[5]||0,1]}if(t.length<=9)t=[t[0],t[1],0,t[2],t[3],t[4],0,t[5],0,0,1,0,t[6],t[7],0,t[8]];else if(16!=t.length)throw new Error("Matrix must be a 3x3 or 4x4 array.");U=t.slice(),q=!0};const $=()=>{z.set(U,16*N.length),H=N.length,N.push(U.slice()),q=!1};let j=[];e.pushMatrix=()=>{q&&$(),V.push(H),j.push(W)},e.popMatrix=()=>{if(!V.length)return console.warn("Matrix index stack is empty!");let e=V.pop();U=N[e].slice(),H=e,q=!1,W=j.pop(),B=G*W},e.resetMatrix=()=>{U=N[0].slice(),H=0,W=1,B=G},e.resetMatrix();let X=[];e.pushStyles=()=>{X.push([A,R,O,G,W,B,M,P,E,I,k,T,Et,It,Rt,mt,Fe,Ke,w,S,C,e.Color])},e.popStyles=()=>{let t=X.pop();[A,R,O,G,W,B,M,P,E,I,k,T,Et,It,Rt,mt,Fe,Ke,w,S,C]=t,e._colorFormat=C,e._colorMode=S,e.Color=t.at(-1)},e.push=()=>{e.pushMatrix(),e.pushStyles()},e.pop=()=>{e.popMatrix(),e.popStyles()};let Y=[0,0,0,0];const J=(e,t,r,n,i)=>{let a,o,s,l;if(i&&"corner"!=i)if("center"==i){let i=r/2,d=n/2;a=e-i,o=e+i,s=t-d,l=t+d}else a=e,o=r,s=t,l=n;else a=e,o=e+r,s=t,l=t+n;return Y[0]=a,Y[1]=o,Y[2]=s,Y[3]=l,Y};let K=["zero","one","src-alpha","one-minus-src-alpha","dst","dst-alpha","one-minus-dst-alpha","one-minus-src"],Z=["add","subtract","reverse-subtract","min","max"];const ee={"source-over":[2,3,0,2,3,0],"destination-over":[6,1,0,6,1,0],"source-in":[5,0,0,5,0,0],"destination-in":[0,2,0,0,2,0],"source-out":[6,0,0,6,0,0],"destination-out":[0,3,0,0,3,0],"source-atop":[5,3,0,5,3,0],"destination-atop":[6,2,0,6,2,0],lighter:[1,1,0,1,1,0],darken:[1,1,3,3,5,0],lighten:[1,1,4,3,5,0],replace:[1,0,0,1,0,0]};let te=Object.keys(ee);e.blendConfigs={};for(const[t,r]of Object.entries(ee))e.blendConfigs[t]={color:{srcFactor:K[r[0]],dstFactor:K[r[1]],operation:Z[r[2]]},alpha:{srcFactor:K[r[3]],dstFactor:K[r[4]],operation:Z[r[5]]}};let re,ne,ie,ae,oe,se,le,de,ce,he,ue="source-over";e.blendMode=e=>{if(e==ue)return;ue=e;let t=te.indexOf(e);-1!=t?x.push(0,t):console.error(`Blend mode "${e}" not supported in q5.js WebGPU.`)},e.clear=()=>{re=!0},e.background=(t,n,i,a)=>{if(t.canvas){e.push(),e.resetMatrix();let n=t;mt="corner",e.image(n,-r.hw,-r.hh,r.w,r.h),e.pop()}else{Q(t,n,i,a);let e=-r.hw,o=r.hw,s=-r.hh,l=r.hh;Pe(e,s,o,s,o,l,e,l,f,0)}},e._beginRender=()=>{const t=o;o=s,s=t;const r=h;h=u,u=r,n=Q5.device.createCommandEncoder(),e._pass=i=n.beginRenderPass({label:"q5-webgpu",colorAttachments:[{view:a,resolveTarget:o.createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]}),c=u,re||(i.setPipeline(e._pipelines[g]),i.setBindGroup(0,c),i.draw(4)),re=!1},e._render=()=>{let t=16*N.length*4;(!ne||ne.size<t)&&(ne&&ne.destroy(),ne=Q5.device.createBuffer({size:Math.min(2*t,F),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ne,0,z.subarray(0,16*N.length));let r=4*p;(!ie||ie.size<r)&&(ie&&ie.destroy(),ie=Q5.device.createBuffer({size:2*r,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ie,0,_.subarray(0,p)),e._uniforms[0]=e.width,e._uniforms[1]=e.height,e._uniforms[2]=e.halfWidth,e._uniforms[3]=e.halfHeight,e._uniforms[4]=e._pixelDensity,e._uniforms[5]=e.frameCount,e._uniforms[6]=performance.now(),e._uniforms[7]=e.deltaTime,e._uniforms[8]=e.mouseX,e._uniforms[9]=e.mouseY,e._uniforms[10]=e.mouseIsPressed?1:0,e._uniforms[11]=e.keyCode,e._uniforms[12]=e.keyIsPressed?1:0,Q5.device.queue.writeBuffer(b,0,e._uniforms),de&&ce===ne&&he===ie||(de=Q5.device.createBindGroup({layout:v,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:{buffer:ne}},{binding:2,resource:{buffer:ie}}]}),ce=ne,he=ie),i.setBindGroup(0,de),e._pass.setPipeline(e._pipelines[1]);let n=4*me;if((!ae||ae.size<n)&&(ae&&ae.destroy(),ae=Q5.device.createBuffer({size:2*n,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ae,0,ge.subarray(0,me)),e._pass.setVertexBuffer(0,ae),ot){e._pass.setPipeline(e._pipelines[2]);let t=4*ot;(!oe||oe.size<t)&&(oe&&oe.destroy(),oe=Q5.device.createBuffer({size:2*t,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(oe,0,at.subarray(0,ot)),e._pass.setVertexBuffer(1,oe),pt&&(e._pass.setPipeline(e._pipelines[3]),e._pass.setVertexBuffer(1,oe))}if(Lt.length){let t=0;for(let e of Lt)Ut.set(e,t),t+=e.length;let r=4*t;(!se||se.size<r)&&(se&&se.destroy(),se=Q5.device.createBuffer({size:2*r,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(se,0,Ut.buffer,0,r);let n=0;for(let e of Ft)Nt.set(e,n),n+=e.length;let i=4*n;(!le||le.size<i)&&(le&&le.destroy(),le=Q5.device.createBuffer({label:"textBuffer",size:2*i,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(le,0,Nt.buffer,0,i),e._textBindGroup=Q5.device.createBindGroup({label:"textBindGroup",layout:bt,entries:[{binding:0,resource:{buffer:se}},{binding:1,resource:{buffer:le}}]})}Q5.device.queue.writeBuffer(De,0,Oe.buffer,Oe.byteOffset,4*Ge),Q5.device.queue.writeBuffer(Xe,0,$e.buffer,$e.byteOffset,4*je);let a=0,o=0,s=0,l=0,d=0,c=-1;for(let t=0;t<x.length;t+=2){let r=x[t+1];if(x[t]!=c){if(0==x[t]){let t=te[r];for(let r=1;r<e._pipelines.length;r++)e._pipelineConfigs[r].fragment.targets[0].blend=e.blendConfigs[t],e._pipelines[r]=Q5.device.createRenderPipeline(e._pipelineConfigs[r]);continue}c=x[t],i.setPipeline(e._pipelines[c]),5==c?(i.setIndexBuffer(Ae,"uint16"),i.setBindGroup(1,Be)):6==c&&(i.setIndexBuffer(He,"uint16"),i.setBindGroup(1,Ye))}if(6==c)i.drawIndexed(18,r,0,0,d),d+=r;else if(5==c)i.drawIndexed(6,r,0,0,l),l+=r;else if(4==c||c>=4e3){let n=x[t+2];i.setBindGroup(1,Mt[n].bindGroup),i.setBindGroup(2,e._textBindGroup),i.draw(4,r,0,s),s+=r,t++}else 2==c||3==c||c>=2e3?(i.setBindGroup(1,e._textureBindGroups[r]),i.draw(4,1,o),o+=4):(i.draw(r,1,a),a+=r)}},e._finishRender=()=>{i.end(),i=n.beginRenderPass({colorAttachments:[{view:a,resolveTarget:e.ctx.getCurrentTexture().createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]}),c=h,i.setPipeline(e._pipelines[m]),i.setBindGroup(0,c),i.draw(4),i.end(),Q5.device.queue.submit([n.finish()]),e._pass=i=n=null,x.length=0,f=2,p=12,N.length=1,V.length=0,e._texture=o,me=0,ot=0,pt>0&&(e._textureBindGroups.length=ft),pt=0,Lt.length=0,Ft.length=0,Ge=0,je=0,Q5.device.queue.onSubmittedWorkDone().then((()=>{for(let t of e._buffers)t.destroy();e._buffers=[]}))};let fe=1;e._shapesShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex : u32,\n\t@location(0) pos: vec2f,\n\t@location(1) colorIndex: f32,\n\t@location(2) matrixIndex: f32\n}\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) color: vec4f\n}\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tvar vert = transformVertex(v.pos, v.matrixIndex);\n\n\tvar f: FragParams;\n\tf.position = vert;\n\tf.color = colors[i32(v.colorIndex)];\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\treturn f.color;\n}\n";let pe=Q5.device.createShaderModule({label:"shapesShader",code:e._shapesShaderCode}),ge=new Float32Array(e._isGraphics?1e3:1e7),me=0;const xe=2*Math.PI;Math.PI;let _e=Q5.device.createPipelineLayout({label:"shapesPipelineLayout",bindGroupLayouts:e._bindGroupLayouts});e._pipelineConfigs[1]={label:"shapesPipeline",layout:_e,vertex:{module:pe,entryPoint:"vertexMain",buffers:[{arrayStride:16,attributes:[{format:"float32x2",offset:0,shaderLocation:0},{format:"float32",offset:8,shaderLocation:1},{format:"float32",offset:12,shaderLocation:2}]}]},fragment:{module:pe,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[1]=Q5.device.createRenderPipeline(e._pipelineConfigs[1]);const ve=(e,t,r,n)=>{let i=ge,a=me;i[a++]=e,i[a++]=t,i[a++]=r,i[a++]=n,me=a};let be="round",ye="round";e.strokeCap=e=>be=e,e.strokeJoin=e=>ye=e,e.lineMode=()=>{be="square",ye="none"};let we=20;e.curveDetail=e=>we=e;let Se,Ce=20;e.bezierDetail=e=>Ce=e;let Qe=[],Me=[];function Pe(e,t,r,n,i,a,o,s,l,d){ve(e,t,l,d),ve(r,n,l,d),ve(o,s,l,d),ve(i,a,l,d),x.push(fe,4)}e.beginShape=()=>{Se=0,Qe=[],Me=[]},e.vertex=(e,t)=>{q&&$(),Qe.push(e,t,A,H),Se++},e.curveVertex=(e,t)=>{q&&$(),Me.push({x:e,y:t})},e.bezierVertex=function(e,t,r,n,i,a){if(0===Se)throw new Error("Shape needs a vertex()");q&&$();let o,s,l=4*(Se-1),d=Qe[l],c=Qe[l+1],h=1/Ce,u=4==arguments.length;u&&(i=r,a=n);let f=1+h;for(let l=h;l<=f;l+=h){let h=l*l,f=1-l,p=f*f;if(u)o=p*d+2*f*l*e+h*i,s=p*c+2*f*l*t+h*a;else{let u=h*l,g=p*f;o=g*d+3*p*l*e+3*f*h*r+u*i,s=g*c+3*p*l*t+3*f*h*n+u*a}Qe.push(o,s,A,H),Se++}},e.quadraticVertex=(t,r,n,i)=>e.bezierVertex(t,r,n,i),e.endShape=t=>{if(Me.length>0){let e=[...Me];if(e.length<4)for(;e.length<4;)e.unshift(e[0]),e.push(e[e.length-1]);let t=1/we;for(let r=0;r<e.length-3;r++){let n=e[r],i=e[r+1],a=e[r+2],o=e[r+3];for(let e=0;e<=1;e+=t){let t=e*e,r=t*e,s=.5*(2*i.x+(-n.x+a.x)*e+(2*n.x-5*i.x+4*a.x-o.x)*t+(-n.x+3*i.x-3*a.x+o.x)*r),l=.5*(2*i.y+(-n.y+a.y)*e+(2*n.y-5*i.y+4*a.y-o.y)*t+(-n.y+3*i.y-3*a.y+o.y)*r);Qe.push(s,l,A,H),Se++}}}if(Se){if(1==Se)return e.point(Qe[0],Qe[1]);if(2==Se)return e.line(Qe[0],Qe[1],Qe[4],Qe[5]);if(t){let e=0,t=4*(Se-1),r=Qe[e],n=Qe[e+1],i=Qe[t],a=Qe[t+1];r===i&&n===a||(Qe.push(r,n,Qe[e+2],Qe[e+3]),Se++)}if(M)if(5==Se)ve(Qe[0],Qe[1],Qe[2],Qe[3]),ve(Qe[4],Qe[5],Qe[6],Qe[7]),ve(Qe[12],Qe[13],Qe[14],Qe[15]),ve(Qe[8],Qe[9],Qe[10],Qe[11]),x.push(fe,4);else{for(let e=1;e<Se-1;e++){let t=0,r=4*e,n=4*(e+1);ve(Qe[t],Qe[t+1],Qe[t+2],Qe[t+3]),ve(Qe[r],Qe[r+1],Qe[r+2],Qe[r+3]),ve(Qe[n],Qe[n+1],Qe[n+2],Qe[n+3])}x.push(fe,3*(Se-2))}if(P){for(let t=0;t<Se-1;t++){let r=4*t,n=4*(t+1);e.line(Qe[r],Qe[r+1],Qe[n],Qe[n+1])}let r=4*(Se-1),n=0;t&&e.line(Qe[r],Qe[r+1],Qe[n],Qe[n+1])}Se=0,Qe=[],Me=[]}},e.curve=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(n,i),e.curveVertex(a,o),e.curveVertex(s,l),e.endShape()},e.bezier=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(n,i,a,o,s,l),e.endShape()},e.triangle=(t,r,n,i,a,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.endShape(!0)},e.quad=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.vertex(s,l),e.endShape(!0)},e.plane=(e,t,r,n)=>{n??=r;let[i,a,o,s]=J(e,t,r,n,"center");q&&$(),Pe(i,o,a,o,a,s,i,s,A,H)};let Ee=5;e._rectShaderCode=e._baseShaderCode+"\nstruct Rect {\n\tcenter: vec2f,\n\textents: vec2f,\n\troundedRadius: f32,\n\tstrokeWeight: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tmatrixIndex: f32,\n\tpadding0: f32, // can't use vec3f for alignment\n\tpadding1: vec2f,\n\tpadding2: vec4f\n};\n\nstruct VertexParams {\n\t@builtin(vertex_index) vertIndex: u32,\n\t@builtin(instance_index) instIndex: u32\n};\n\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) local: vec2f,\n\t@location(1) extents: vec2f,\n\t@location(2) roundedRadius: f32,\n\t@location(3) strokeWeight: f32,\n\t@location(4) fill: vec4f,\n\t@location(5) stroke: vec4f,\n\t@location(6) blend: vec4f\n};\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var<storage, read> rects: array<Rect>;\n\nconst quad = array(\n\tvec2f(-1.0, -1.0),\n\tvec2f( 1.0, -1.0),\n\tvec2f(-1.0, 1.0),\n\tvec2f( 1.0, 1.0)\n);\nconst transparent = vec4f(0.0);\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tlet rect = rects[v.instIndex];\n\n\tlet halfStrokeSize = vec2f(rect.strokeWeight * 0.5);\n\tlet quadSize = rect.extents + halfStrokeSize;\n\tlet pos = (quad[v.vertIndex] * quadSize) + rect.center;\n\n\tlet local = pos - rect.center;\n\n\tvar f: FragParams;\n\tf.position = transformVertex(pos, rect.matrixIndex);\n\n\tf.local = local;\n\tf.extents = rect.extents;\n\tf.roundedRadius = rect.roundedRadius;\n\tf.strokeWeight = rect.strokeWeight;\n\n\tlet fill = colors[i32(rect.fillIndex)];\n\tlet stroke = colors[i32(rect.strokeIndex)];\n\tf.fill = fill;\n\tf.stroke = stroke;\n\n\t// Source-over blend: stroke over fill (pre-multiplied alpha)\n\tif (fill.a != 0.0 && stroke.a != 1.0) {\n\t\tlet outAlpha = stroke.a + fill.a * (1.0 - stroke.a);\n\t\tlet outColor = stroke.rgb * stroke.a + fill.rgb * fill.a * (1.0 - stroke.a);\n\t\tf.blend = vec4f(outColor / max(outAlpha, 1e-5), outAlpha);\n\t}\n\treturn f;\n}\n\nfn sdRoundRect(p: vec2f, extents: vec2f, radius: f32) -> f32 {\n\tlet q = abs(p) - extents + vec2f(radius);\n\treturn length(max(q, vec2f(0.0))) - radius + min(max(q.x, q.y), 0.0);\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\tlet dist = select(\n\t\tmax(abs(f.local.x) - f.extents.x, abs(f.local.y) - f.extents.y), // sharp\n\t\tsdRoundRect(f.local, f.extents, f.roundedRadius), // rounded\n\t\tf.roundedRadius > 0.0\n\t);\n\n\t// fill only\n\tif (f.fill.a != 0.0 && f.strokeWeight == 0.0) {\n\t\tif (dist <= 0.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\treturn transparent;\n\t}\n\n\tlet halfStroke = f.strokeWeight * 0.5;\n\tlet inner = dist + halfStroke;\n\n\tif (f.fill.a != 0.0) {\n\t\tif (inner <= 0.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\tif (dist <= 0.0 && f.stroke.a != 1.0) {\n\t\t\treturn f.blend;\n\t\t}\n\t}\n\n\tlet outer = dist - halfStroke;\n\n\tif (outer <= 0.0 && inner >= 0.0) {\n\t\treturn f.stroke;\n\t}\n\n\treturn transparent;\n}\n\t";let Ie=Q5.device.createShaderModule({label:"rectShader",code:e._rectShaderCode}),Re=new Uint16Array([0,1,2,2,1,3]),Ae=Q5.device.createBuffer({size:Re.byteLength,usage:GPUBufferUsage.INDEX,mappedAtCreation:!0});new Uint16Array(Ae.getMappedRange()).set(Re),Ae.unmap();let Te=Q5.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),ke=Q5.device.createPipelineLayout({label:"rectPipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,Te]});e._pipelineConfigs[5]={label:"rectPipeline",layout:ke,vertex:{module:Ie,entryPoint:"vertexMain",buffers:[]},fragment:{module:Ie,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-list"},multisample:{count:4}},e._pipelines[5]=Q5.device.createRenderPipeline(e._pipelineConfigs[5]);let Oe=new Float32Array(16*Q5.MAX_RECTS),Ge=0,De=Q5.device.createBuffer({size:Oe.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),Be=Q5.device.createBindGroup({layout:Te,entries:[{binding:0,resource:{buffer:De}}]});function Le(e,t,r,n,i,a,o){let s=Oe,l=Ge;s[l]=e,s[l+1]=t,s[l+2]=r,s[l+3]=n,s[l+4]=i,s[l+5]=a,s[l+6]=o,s[l+7]=R,s[l+8]=H,Ge+=16,x.push(Ee,1)}let Fe="corner";e.rectMode=e=>Fe=e,e._getRectMode=()=>Fe;let ze=[0,0,0,0];function Ue(t,r,n,i,a,o,s){let l=n-t,d=i-r,c=Math.hypot(l,d);if(0===c)return;let h=Math.atan2(d,l),u=(t+n)/2,f=(r+i)/2;e._angleMode&&(h*=e._RADTODEG),e.pushMatrix(),e.translate(u,f),e.rotate(h),q&&$(),Le(0,0,c/2+a,a,a,o,s),e.popMatrix()}e.rect=(e,t,r,n,i=0)=>{let a,o;q&&$(),[e,t,a,o]=function(e,t,r,n){let i=r/2,a=n/2;return"center"!=Fe&&("corner"==Fe?(e+=i,t+=a):"radius"==Fe?(i=r,a=n):"corners"==Fe&&(i=Math.abs((r-e)/2),a=Math.abs((n-t)/2),e=(e+r)/2,t=(t+n)/2)),ze[0]=e,ze[1]=t,ze[2]=i,ze[3]=a,ze}(e,t,r,n),Le(e,t,a,o,i,P?O:0,M?A:0)},e.square=(t,r,n,i)=>e.rect(t,r,n,n,i),e.capsule=(e,t,r,n,i)=>{Ue(e,t,r,n,i,P?O:0,M?A:0)},e.line=(e,t,r,n)=>{P&&Ue(e,t,r,n,D,G,0)};e._ellipseShaderCode=e._baseShaderCode+"\nstruct Ellipse {\n\tcenter: vec2f,\n\tsize: vec2f,\n\tstartAngle: f32,\n\tendAngle: f32,\n\tstrokeWeight: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tmatrixIndex: f32,\n\tpadding0: vec2f,\n\tpadding1: vec4f\n};\n\nstruct VertexParams {\n\t@builtin(vertex_index) vertIndex: u32,\n\t@builtin(instance_index) instIndex: u32\n};\n\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) outerEdge: vec2f,\n\t@location(1) fillEdge: vec2f,\n\t@location(2) innerEdge: vec2f,\n\t@location(3) strokeWeight: f32,\n\t@location(4) fill: vec4f,\n\t@location(5) stroke: vec4f,\n\t@location(6) blend: vec4f\n};\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var<storage, read> ellipses: array<Ellipse>;\n\nconst PI = 3.141592653589793;\nconst segments = 6.0;\nconst expansion = 1.0 / cos(PI / segments);\nconst antiAlias = 0.015625; // 1/64\nconst transparent = vec4f(0.0);\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tlet ellipse = ellipses[v.instIndex];\n\tvar pos = ellipse.center;\n\tvar local = vec2f(0.0);\n\tlet start = ellipse.startAngle;\n\tlet end = ellipse.endAngle;\n\tlet arc = end - start;\n\tlet halfStrokeSize = vec2f(ellipse.strokeWeight * 0.5);\n\n\tlet fanSize = (ellipse.size + halfStrokeSize) * expansion;\n\n\tif (v.vertIndex != 0) {\n\t\tlet theta = start + (f32(v.vertIndex - 1) / segments) * arc;\n\t\tlocal = vec2f(cos(theta), sin(theta));\n\t\tpos = ellipse.center + local * fanSize;\n\t}\n\n\tlet dist = pos - ellipse.center;\n\n\tvar f: FragParams;\n\tf.position = transformVertex(pos, ellipse.matrixIndex);\n\tf.outerEdge = dist / (ellipse.size + halfStrokeSize);\n\tf.fillEdge = dist / ellipse.size;\n\tf.innerEdge = dist / (ellipse.size - halfStrokeSize);\n\tf.strokeWeight = ellipse.strokeWeight;\n\n\tlet fill = colors[i32(ellipse.fillIndex)];\n\tlet stroke = colors[i32(ellipse.strokeIndex)];\n\tf.fill = fill;\n\tf.stroke = stroke;\n\n\t// Source-over blend: stroke over fill (pre-multiplied alpha)\n\tif (fill.a != 0.0 && stroke.a != 1.0) {\n\t\tlet outAlpha = stroke.a + fill.a * (1.0 - stroke.a);\n\t\tlet outColor = stroke.rgb * stroke.a + fill.rgb * fill.a * (1.0 - stroke.a);\n\t\tf.blend = vec4f(outColor / max(outAlpha, 1e-5), outAlpha);\n\t}\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\tlet fillEdge = length(f.fillEdge);\n\n\t// disable AA for very thin strokes\n\tlet aa = select(antiAlias, 0.0, f.strokeWeight <= 1.0);\n\n\tif (f.fill.a != 0.0 && f.strokeWeight == 0.0) {\n\t\tif (fillEdge > 1.0) {\n\t\t\treturn transparent;\n\t\t}\n\t\tlet fillAlpha = 1.0 - smoothstep(1.0 - aa, 1.0, fillEdge);\n\t\treturn vec4f(f.fill.rgb, f.fill.a * fillAlpha);\n\t}\n\n\tlet innerEdge = length(f.innerEdge);\n\t\n\tif (f.fill.a != 0.0 && fillEdge < 1.0) {\n\t\tif (innerEdge < 1.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\tlet tInner = smoothstep(1.0, 1.0 + aa, innerEdge);\n\t\tlet tOuter = smoothstep(1.0 - aa, 1.0, fillEdge);\n\t\tif (f.stroke.a != 1.0) {\n\t\t\tlet fillBlend = mix(f.fill, f.blend, tInner);\n\t\t\treturn mix(fillBlend, f.stroke, tOuter);\n\t\t} else {\n\t\t\tlet fillBlend = mix(f.fill, f.stroke, tInner);\n\t\t\treturn mix(fillBlend, f.stroke, tOuter);\n\t\t}\n\t}\n\t\n\tif (innerEdge < 1.0) {\n\t\treturn transparent;\n\t}\n\n\tlet outerEdge = length(f.outerEdge);\n\tlet outerAlpha = 1.0 - smoothstep(1.0 - aa, 1.0, outerEdge);\n\tlet innerAlpha = smoothstep(1.0, 1.0 + aa, innerEdge);\n\tlet strokeAlpha = innerAlpha * outerAlpha;\n\treturn vec4f(f.stroke.rgb, f.stroke.a * strokeAlpha);\n}\n\t\t";let Ne=Q5.device.createShaderModule({label:"ellipseShader",code:e._ellipseShaderCode}),Ve=new Uint16Array([0,1,2,0,2,3,0,3,4,0,4,5,0,5,6,0,6,7]),He=Q5.device.createBuffer({size:Ve.byteLength,usage:GPUBufferUsage.INDEX,mappedAtCreation:!0});new Uint16Array(He.getMappedRange()).set(Ve),He.unmap();let qe=Q5.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),We=Q5.device.createPipelineLayout({label:"ellipsePipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,qe]});e._pipelineConfigs[6]={label:"ellipsePipeline",layout:We,vertex:{module:Ne,entryPoint:"vertexMain",buffers:[]},fragment:{module:Ne,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-list"},multisample:{count:4}},e._pipelines[6]=Q5.device.createRenderPipeline(e._pipelineConfigs[6]);let $e=new Float32Array(16*Q5.MAX_ELLIPSES),je=0,Xe=Q5.device.createBuffer({size:$e.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),Ye=Q5.device.createBindGroup({layout:qe,entries:[{binding:0,resource:{buffer:Xe}}]});function Je(e,t,r,n,i,a,o,s){let l=$e,d=je;l[d]=e,l[d+1]=t,l[d+2]=r,l[d+3]=n,l[d+4]=i,l[d+5]=a,l[d+6]=o,l[d+7]=s?A:0,l[d+8]=R,l[d+9]=H,je+=16,x.push(6,1)}let Ke="center";e.ellipseMode=e=>Ke=e,e._getEllipseMode=()=>Ke;let Ze=[0,0,0,0];function et(e,t,r,n){let i,a;return n??=r,"center"==Ke?(i=r/2,a=n/2):"radius"==Ke?(i=r,a=n):"corner"==Ke?(e+=r/2,t+=n/2,i=r/2,a=n/2):"corners"==Ke&&(i=r-(e=(e+r)/2),a=n-(t=(t+n)/2)),Ze[0]=e,Ze[1]=t,Ze[2]=i,Ze[3]=a,Ze}e.ellipse=(e,t,r,n)=>{let i,a;[e,t,i,a]=et(e,t,r,n),q&&$(),Je(e,t,i,a,0,xe,P?O:0,M)},e.circle=(t,r,n)=>e.ellipse(t,r,n,n),e.arc=(t,r,n,i,a,o)=>{if(a===o)return e.ellipse(t,r,n,i);if(e._angleMode&&(a=e.radians(a),o=e.radians(o)),(a%=xe)<0&&(a+=xe),(o%=xe)<0&&(o+=xe),a>o&&(o+=xe),a==o)return e.ellipse(t,r,n,i);let s,l;[t,r,s,l]=et(t,r,n,i),q&&$(),Je(t,r,s,l,a,o,P?O:0,M)},e.point=(e,t)=>{q&&$(),B<=.5?Le(e,t,G,G,0,O,0):Je(e,t,G,G,0,xe,O,0)};let tt=2,rt=3;e._imageShaderCode=e._baseShaderCode+"\n\tstruct VertexParams {\n\t\t@builtin(vertex_index) vertexIndex : u32,\n\t\t@location(0) pos: vec2f,\n\t\t@location(1) texCoord: vec2f,\n\t\t@location(2) tintIndex: f32,\n\t\t@location(3) matrixIndex: f32,\n\t\t@location(4) imageAlpha: f32\n\t}\n\tstruct FragParams {\n\t\t@builtin(position) position: vec4f,\n\t\t@location(0) texCoord: vec2f,\n\t\t@location(1) tintColor: vec4f,\n\t\t@location(2) imageAlpha: f32\n\t}\n\t\n\t@group(0) @binding(0) var<uniform> q: Q5;\n\t@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n\t@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\t\n\t@group(1) @binding(0) var samp: sampler;\n\t@group(1) @binding(1) var tex: texture_2d<f32>;\n\t\n\tfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\t\tvar vert = vec4f(pos, 0f, 1f);\n\t\tvert = transforms[i32(matrixIndex)] * vert;\n\t\tvert.x /= q.halfWidth;\n\t\tvert.y /= q.halfHeight;\n\t\treturn vert;\n\t}\n\t\n\tfn applyTint(texColor: vec4f, tintColor: vec4f) -> vec4f {\n\t\t// apply the tint color to the sampled texture color at full strength\n\t\tlet tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);\n\t\t// mix in the tint using the tint alpha as the blend strength\n\t\treturn mix(texColor, tinted, tintColor.a);\n\t}\n\t\n\t@vertex\n\tfn vertexMain(v: VertexParams) -> FragParams {\n\t\tvar vert = transformVertex(v.pos, v.matrixIndex);\n\t\n\t\tvar f: FragParams;\n\t\tf.position = vert;\n\t\tf.texCoord = v.texCoord;\n\t\tf.tintColor = colors[i32(v.tintIndex)];\n\t\tf.imageAlpha = v.imageAlpha;\n\t\treturn f;\n\t}\n\t\n\t@fragment\n\tfn fragMain(f: FragParams) -> @location(0) vec4f {\n\t\tvar texColor = textureSample(tex, samp, f.texCoord);\n\t\ttexColor.a *= f.imageAlpha;\n\t\treturn applyTint(texColor, f.tintColor);\n\t}\n\t";let nt=Q5.device.createShaderModule({label:"imageShader",code:e._imageShaderCode});e._videoShaderCode=e._imageShaderCode.replace("texture_2d<f32>","texture_external").replace("textureSample","textureSampleBaseClampToEdge");let it=Q5.device.createShaderModule({label:"videoShader",code:e._videoShaderCode}),at=new Float32Array(e._isGraphics?1e3:1e7),ot=0,st={arrayStride:28,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"},{shaderLocation:2,offset:16,format:"float32"},{shaderLocation:3,offset:20,format:"float32"},{shaderLocation:4,offset:24,format:"float32"}]},lt=Q5.device.createBindGroupLayout({label:"textureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]}),dt=Q5.device.createBindGroupLayout({label:"videoTextureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,externalTexture:{}}]}),ct=Q5.device.createPipelineLayout({label:"imagePipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,lt]}),ht=Q5.device.createPipelineLayout({label:"videoPipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,dt]});e._pipelineConfigs[2]={label:"imagePipeline",layout:ct,vertex:{module:nt,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},st]},fragment:{module:nt,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[2]=Q5.device.createRenderPipeline(e._pipelineConfigs[2]),e._pipelineConfigs[3]={label:"videoPipeline",layout:ht,vertex:{module:it,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},st]},fragment:{module:it,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[3]=Q5.device.createRenderPipeline(e._pipelineConfigs[3]),e._textureBindGroups=[],r&&(r.convertToBlob=async t=>{let r=e._drawStack?.length;r&&(e._render(),e._finishRender());let n=e._texture;r&&e._beginRender();let i=n.width,a=n.height,o=256*Math.ceil(4*i/256),s=Q5.device.createBuffer({size:o*a,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),l=Q5.device.createCommandEncoder();l.copyTextureToBuffer({texture:n},{buffer:s,bytesPerRow:o,rowsPerImage:a},{width:i,height:a}),Q5.device.queue.submit([l.finish()]),await s.mapAsync(GPUMapMode.READ);let d=new Uint8Array(s.getMappedRange()),c=new Uint8Array(i*a*4);for(let e=0;e<a;e++){const t=e*o,r=e*i*4;for(let e=0;e<i;e++){const n=t+4*e,i=r+4*e;c[i+0]=d[n+2],c[i+1]=d[n+1],c[i+2]=d[n+0],c[i+3]=d[n+3]}}s.unmap();let h=e.canvas.colorSpace;c=new Uint8ClampedArray(c.buffer),c=new ImageData(c,i,a,{colorSpace:h});let u=new OffscreenCanvas(i,a);return u.getContext("2d",{colorSpace:h}).putImageData(c,0,0),e._buffers.push(s),await u.convertToBlob(t)});let ut=t=>{e._imageSampler=Q5.device.createSampler({magFilter:t,minFilter:t})};e.smooth=()=>ut("linear"),e.noSmooth=()=>ut("nearest"),e.smooth();let ft=0,pt=0;e._addTexture=(t,r)=>{let n=t.canvas||t;if(!r){if(t._texture)return;let i=[n.width,n.height,1];r=Q5.device.createTexture({size:i,format:"bgra8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_SRC|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),Q5.device.queue.copyExternalImageToTexture({source:n},{texture:r,colorSpace:e.canvas.colorSpace},i)}r.index=ft+pt,t._texture=r,e._textureBindGroups[r.index]=Q5.device.createBindGroup({label:t.src||r.label||"canvas",layout:lt,entries:[{binding:0,resource:e._imageSampler},{binding:1,resource:r.createView()}]}),ft++},e.loadImage=(t,r)=>e._g.loadImage(t,(t=>{e._makeDrawable(t),r&&r(t)})),e._makeDrawable=t=>{e._addTexture(t),t._webgpuInst=e},e.createImage=(t,r,n)=>{let i=e._g.createImage(t,r,n);return e._makeDrawable(i),i.modified=!0,i};let gt=e.createGraphics;e.createGraphics=(t,r,n={})=>{if(!Q5.experimental)throw new Error("createGraphics is disabled by default in q5 WebGPU. See issue https://github.com/q5js/q5.js/issues/104 for details.");"string"==typeof n&&(n={renderer:n}),n.renderer??="c2d";let i=gt(t,r,n);return i.canvas.webgpu?(e._addTexture(i,i._frameA),e._addTexture(i,i._frameB),i._beginRender()):(e._makeDrawable(i),i.modified=!0),i};let mt="corner";e.imageMode=e=>mt=e,e._getImageMode=()=>mt,e._uniforms=new Float32Array(13);const xt=(e,t,r,n,i,a,o)=>{let s=at,l=ot;s[l++]=e,s[l++]=t,s[l++]=r,s[l++]=n,s[l++]=i,s[l++]=a,s[l++]=o,ot=l};e.image=(t,r=0,n=0,i,a,o=0,s=0,l,d)=>{if(!t)return;let c;if(null==t._texture){if(c="VIDEO"==t.tagName,!t.width||c&&!t.currentTime)return;t.flipped&&e.scale(-1,1)}q&&$();let h=t.canvas||t,u=h.width,f=h.height,p=t._pixelDensity||1,g=t._isGraphics&&t._drawStack?.length;g&&(t._render(),t._finishRender()),t.modified&&(Q5.device.queue.copyExternalImageToTexture({source:h},{texture:t._texture,colorSpace:e.canvas.colorSpace},[u,f,1]),t.frameCount++,t.modified=!1),i??=t.defaultWidth||t.videoWidth,a??=t.defaultHeight||t.videoHeight,l??=u,d??=f,o*=p,s*=p;let[m,_,v,b]=J(r,n,i,a,mt),y=o/u,w=s/f,S=(o+l)/u,C=(s+d)/f,Q=H,M=T,P=k;if(xt(m,v,y,w,M,Q,P),xt(_,v,S,w,M,Q,P),xt(m,b,y,C,M,Q,P),xt(_,b,S,C,M,Q,P),c){let r=Q5.device.importExternalTexture({source:t});e._textureBindGroups.push(Q5.device.createBindGroup({layout:dt,entries:[{binding:0,resource:e._imageSampler},{binding:1,resource:r}]})),x.push(rt,e._textureBindGroups.length-1),t.flipped&&e.scale(-1,1)}else x.push(tt,t._texture.index),g&&(t.resetMatrix(),t._beginRender(),t.frameCount++)};let _t=4;e._textShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex : u32,\n\t@builtin(instance_index) instanceIndex : u32\n}\nstruct FragParams {\n\t@builtin(position) position : vec4f,\n\t@location(0) texCoord : vec2f,\n\t@location(1) fillColor : vec4f,\n\t@location(2) strokeColor : vec4f,\n\t@location(3) strokeWeight : f32,\n\t@location(4) edge : f32\n}\nstruct Char {\n\ttexOffset: vec2f,\n\ttexExtent: vec2f,\n\tsize: vec2f,\n\toffset: vec2f,\n}\nstruct Text {\n\tpos: vec2f,\n\tscale: f32,\n\tmatrixIndex: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tstrokeWeight: f32,\n\tedge: f32\n}\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var fontTexture: texture_2d<f32>;\n@group(1) @binding(1) var fontSampler: sampler;\n@group(1) @binding(2) var<storage> fontChars: array<Char>;\n\n@group(2) @binding(0) var<storage> textChars: array<vec4f>;\n@group(2) @binding(1) var<storage> textMetadata: array<Text>;\n\nconst quad = array(vec2f(0, 1), vec2f(1, 1), vec2f(0, 0), vec2f(1, 0));\nconst uvs = array(vec2f(0, 1), vec2f(1, 1), vec2f(0, 0), vec2f(1, 0));\n\nfn calcPos(i: u32, char: vec4f, fontChar: Char, text: Text) -> vec2f {\n\treturn ((quad[i] * fontChar.size + char.xy + fontChar.offset) *\n\t\ttext.scale) + text.pos;\n}\n\nfn calcUV(i: u32, fontChar: Char) -> vec2f {\n\treturn uvs[i] * fontChar.texExtent + fontChar.texOffset;\n}\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\nfn calcDist(texCoord: vec2f, edgeWidth: f32) -> f32 {\n\tlet c = textureSample(fontTexture, fontSampler, texCoord);\n\tlet sigDist = max(min(c.r, c.g), min(max(c.r, c.g), c.b)) - edgeWidth;\n\n\tlet pxRange = 4.0;\n\tlet sz = vec2f(textureDimensions(fontTexture, 0));\n\tlet dx = sz.x * length(vec2f(dpdxFine(texCoord.x), dpdyFine(texCoord.x)));\n\tlet dy = sz.y * length(vec2f(dpdxFine(texCoord.y), dpdyFine(texCoord.y)));\n\tlet toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);\n\treturn sigDist * toPixels;\n}\n\n@vertex\nfn vertexMain(v : VertexParams) -> FragParams {\n\tlet char = textChars[v.instanceIndex];\n\tlet text = textMetadata[i32(char.w)];\n\tlet fontChar = fontChars[i32(char.z)];\n\tlet pos = calcPos(v.vertexIndex, char, fontChar, text);\n\n\tvar vert = transformVertex(pos, text.matrixIndex);\n\n\tvar f : FragParams;\n\tf.position = vert;\n\tf.texCoord = calcUV(v.vertexIndex, fontChar);\n\tf.fillColor = colors[i32(text.fillIndex)];\n\tf.strokeColor = colors[i32(text.strokeIndex)];\n\tf.strokeWeight = text.strokeWeight;\n\tf.edge = text.edge;\n\treturn f;\n}\n\n@fragment\nfn fragMain(f : FragParams) -> @location(0) vec4f {\n\tlet edge = f.edge;\n\tlet dist = calcDist(f.texCoord, edge);\n\n\tif (f.strokeWeight == 0.0) {\n\t\tlet fillAlpha = smoothstep(-edge, edge, dist);\n\t\tlet color = vec4f(f.fillColor.rgb, f.fillColor.a * fillAlpha);\n\t\tif (color.a < 0.01) {\n\t\t\tdiscard;\n\t\t}\n\t\treturn color;\n\t}\n\n\tlet halfStroke = f.strokeWeight / 2.0;\n\tlet fillAlpha = smoothstep(-edge, edge, dist - halfStroke);\n\tlet strokeAlpha = smoothstep(-edge, edge, dist + halfStroke);\n\tvar color = mix(f.strokeColor, f.fillColor, fillAlpha);\n\tcolor = vec4f(color.rgb, color.a * strokeAlpha);\n\tif (color.a < 0.01) {\n\t\tdiscard;\n\t}\n\treturn color;\n}\n";let vt=Q5.device.createShaderModule({label:"textShader",code:e._textShaderCode}),bt=Q5.device.createBindGroupLayout({label:"textBindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}}]}),yt=Q5.device.createSampler({minFilter:"linear",magFilter:"linear",mipmapFilter:"linear",maxAnisotropy:16}),wt=Q5.device.createBindGroupLayout({label:"fontBindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:2,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),St=Q5.device.createPipelineLayout({bindGroupLayouts:[...e._bindGroupLayouts,wt,bt]});e._pipelineConfigs[4]={label:"textPipeline",layout:St,vertex:{module:vt,entryPoint:"vertexMain"},fragment:{module:vt,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[4]=Q5.device.createRenderPipeline(e._pipelineConfigs[4]);class Ct{constructor(e,t,r,n){this.bindGroup=e,this.lineHeight=t,this.chars=r,this.kernings=n;let i=Object.values(r);this.charCount=i.length,this.defaultChar=i[0]}getChar(e){return this.chars[e]??this.defaultChar}getXAdvance(e,t=-1){let r=this.getChar(e);if(t>=0){let n=this.kernings.get(e);if(n)return r.xadvance+(n.get(t)??0)}return r.xadvance}}let Qt,Mt=[],Pt={};e.loadFont=(t="sans-serif",r)=>{if(Qt=!0,t.startsWith("https://fonts.googleapis.com/css"))return e._g.loadFont(t,r);let n=t.slice(t.lastIndexOf(".")+1);if(t==n){let e=t;Pt[e]=null,t=`https://q5js.org/fonts/${e}-msdf.json`,0!=Q5.online&&navigator.onLine||(t=`/node_modules/q5/builtinFonts/${e}-msdf.json`),n="json"}if("json"!=n)return e._g.loadFont(t,r);let i=t.slice(t.lastIndexOf("/")+1,t.lastIndexOf("-")),a={family:i};return a.promise=async function(t,r,n){let i,a,o=t.substring(0,t.lastIndexOf("-"));try{[i,a]=await Promise.all([fetch(t).then((e=>{if(404==e.status)throw new Error("404");return e.json()})),fetch(o+".png").then((e=>e.blob())).then((e=>createImageBitmap(e)))])}catch(e){return console.error("Error loading font:",e),""}let s=[a.width,a.height,1],l=Q5.device.createTexture({label:`MSDF ${r}`,size:s,format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:a},{texture:l},s),"string"==typeof i.chars&&(i.chars=Q5.CSV.parse(i.chars," "),i.kernings=Q5.CSV.parse(i.kernings," "));let d=i.chars.length,c=Q5.device.createBuffer({size:32*d,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),h=new Float32Array(c.getMappedRange()),u=1/i.common.scaleW,f=1/i.common.scaleH,p={},g=0;for(let[e,t]of i.chars.entries())p[t.id]=t,p[t.id].charIndex=e,h[g]=t.x*u,h[g+1]=t.y*f,h[g+2]=t.width*u,h[g+3]=t.height*f,h[g+4]=t.width,h[g+5]=t.height,h[g+6]=t.xoffset,h[g+7]=t.yoffset,g+=8;c.unmap();let m=Q5.device.createBindGroup({label:"fontBindGroup",layout:wt,entries:[{binding:0,resource:l.createView()},{binding:1,resource:yt},{binding:2,resource:{buffer:c}}]}),x=new Map;if(i.kernings)for(let e of i.kernings){let t=x.get(e.first);t||(t=new Map,x.set(e.first,t)),t.set(e.second,e.amount)}let _=new Ct(m,i.common.lineHeight,p,x);return _.index=Mt.length,Mt.push(_),Pt[r]=_,e._font=_,n&&n(r),{family:r}}(t,i,(()=>{delete a.then,a._usedAwait&&(a={family:i}),r&&r(a)})),e._loaders.push(a.promise),a.then=(e,t)=>(a._usedAwait=!0,a.promise.then(e,t)),a};let Et=18,It="left",Rt="alphabetic",At=!1,Tt=22.5,kt=4.5,Ot=1.25,Gt=["serif","sans-serif","monospace","cursive","fantasy","system-ui"];e.textFont=t=>{if(!t)return e._font;Qt=!0,"string"!=typeof t&&(t=t.family);let r=Pt[t];r?e._font=r:(Gt[t]||void 0===r)&&e._g.textFont(t)},e.textSize=e=>{if(null==e)return Et;Et=e,At||(Tt=e*Ot,kt=Tt-e)};let Dt={thin:100,extralight:200,light:300,normal:400,regular:400,medium:500,semibold:600,bold:700,bolder:800,extrabold:800,black:900,heavy:900},Bt=.5;e.textWeight=t=>{if(!t)return e._textWeight;if("string"==typeof t&&!(t=Dt[t.toLowerCase().replace(/[ _-]/g,"")]))throw new Error(`Invalid font weight: ${t}`);Bt=.6875-375e-6*t},e.textLeading=t=>{e._font.lineHeight=Tt=t,kt=Tt-Et,Ot=Tt/Et,At=!0},e.textAlign=(e,t)=>{It=e,t&&(Rt=t)};let Lt=[],Ft=[],zt=new Array(100),Ut=new Float32Array(4*Q5.MAX_CHARS),Nt=new Float32Array(8*Q5.MAX_TEXTS),Vt=(e,t,r)=>{let n=0,i=0,a=0,o=0,s=0,l=zt,d=t.charCodeAt(0);for(let c=0;c<t.length;++c){let h=d;switch(d=c<t.length-1?t.charCodeAt(c+1):-1,h){case 10:l.push(i),o++,n=Math.max(n,i),i=0,a-=e.lineHeight*Ot;break;case 13:break;case 32:i+=e.getXAdvance(h);break;case 9:i+=2*e.getXAdvance(h);break;default:r&&r(i,a,o,e.getChar(h)),i+=e.getXAdvance(h,d),s++}}l[o]=i,n=Math.max(n,i);let c=o+1;return{width:n,height:c*e.lineHeight*Ot,lineWidths:l,lineCount:c,printedCharCount:s}};e.text=(t,r,n,i,a)=>{if(Et<1)return;let o=typeof t;if("string"!=o)"object"==o?t=t.toString():t+="";else if(!t.length)return;if(!e._font){Qt||e.loadFont();let o=e.createTextImage(t,i,a);return e.textImage(o,r,n)}if(t.length>i){let e=[],r=0;for(;r<t.length&&e.length<a;){let n=r+i;if(n>=t.length){e.push(t.slice(r));break}let a=t.lastIndexOf(" ",n);(-1==a||a<r)&&(a=n),e.push(t.slice(r,a)),r=a+1}t=e.join("\n")}let s;for(let e=0;e<t.length;e++){switch(t[e]){case"\n":s=!0;case"\r":case"\t":case" ":0}}let l,d=[],c=It,h=Rt,u=Ft.length,f=0;if("left"!=c||s){l=Vt(e._font,t);let r=0;"alphabetic"==h?n-=Et:"center"==h?r=.5*l.height:"bottom"==h&&(r=l.height),Vt(e._font,t,((e,t,n,i)=>{let a=0;"center"==c?a=-.5*l.width- -.5*(l.width-l.lineWidths[n]):"right"==c&&(a=-l.lineWidths[n]),d[f]=e+a,d[f+1]=-(t+r),d[f+2]=i.charIndex,d[f+3]=u,f+=4}))}else l=Vt(e._font,t,((e,t,r,n)=>{d[f]=e,d[f+1]=-t,d[f+2]=n.charIndex,d[f+3]=u,f+=4})),"alphabetic"==h?n-=Et:"center"==h?n-=.5*Et:"bottom"==h&&(n-=Tt);Lt.push(d);let p=[];q&&$(),p[0]=r,p[1]=n,p[2]=Et/42,p[3]=H,p[4]=M&&E?A:1,p[5]=R,p[6]=P&&I?O:0,p[7]=Bt,Ft.push(p),x.push(_t,l.printedCharCount,e._font.index)},e.textWidth=t=>e._font?Vt(e._font,t).width:0,e.createTextImage=(t,r,n)=>{if(e._g.textSize(Et),M&&E){let t=4*A;e._g.fill(_.slice(t,t+4))}if(P&&I){let t=4*R;e._g.stroke(_.slice(t,t+4))}let i=e._g.createTextImage(t,r,n);return e._makeDrawable(i),i},e.textImage=(t,r,n)=>{"string"==typeof t&&(t=e.createTextImage(t));let i=mt;mt="corner";let a=It;"center"==a?r-=t.canvas.hw:"right"==a&&(r-=t.width);let o=Rt;"alphabetic"==o?n-=t._leading:"center"==o?n-=t._middle:"bottom"==o?n-=t._bottom:"top"==o&&(n-=t._top),e.image(t,r,n),mt=i};let Ht=["frame","shapes","image","video","text"],qt={frame:10,shapes:1e3,image:2e3,video:3e3,text:4e3};e._createShader=(t,r="shapes")=>{t=t.trim();let n=e["_"+r+"ShaderCode"],i=n.indexOf("@vertex"),a=n.indexOf("@fragment");t=t.includes("@fragment")?t.includes("@vertex")?n.slice(0,i)+t:n.slice(0,a)+t:n.slice(0,i)+t+"\n\n"+n.slice(a);let o=Q5.device.createShaderModule({label:r+"Shader",code:t});o.type=r;let s=Ht.indexOf(r),l=Object.assign({},e._pipelineConfigs[s]);l.vertex.module=l.fragment.module=o;let d=qt[r];return e._pipelines[d]=Q5.device.createRenderPipeline(l),e._pipelines[d].shader=o,o.pipelineIndex=d,qt[r]++,o},e.createShader=e.createShapesShader=e._createShader,e.createFrameShader=t=>e._createShader(t,"frame"),e.createImageShader=t=>e._createShader(t,"image"),e.createVideoShader=t=>e._createShader(t,"video"),e.createTextShader=t=>e._createShader(t,"text"),e.shader=e=>{let t=e.type,r=e.pipelineIndex;"frame"==t?e.applyBeforeDraw?g=r:m=r:"shapes"==t?fe=r:"image"==t?tt=r:"video"==t?rt=r:"text"==t&&(_t=r)},e.resetShader=e.resetShapesShader=()=>fe=1,e.resetFrameShader=()=>g=m=0,e.resetImageShader=()=>tt=2,e.resetVideoShader=()=>rt=3,e.resetTextShader=()=>_t=4,e.resetShaders=()=>{g=m=0,fe=1,tt=2,rt=3,_t=4}},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.MAX_TRANSFORMS=1e7,Q5.MAX_RECTS=200200,Q5.MAX_ELLIPSES=200200,Q5.MAX_CHARS=1e5,Q5.MAX_TEXTS=1e4,Q5.initWebGPU=async()=>{if(!navigator.gpu)return console.warn("q5 WebGPU not supported on this browser! Use Google Chrome or Edge."),!1;if(!Q5.requestedGPU){Q5.requestedGPU=!0;let e=await navigator.gpu.requestAdapter();if(!e)return console.warn("q5 WebGPU could not start! No appropriate GPUAdapter found, Vulkan may need to be enabled."),!1;Q5.device=await e.requestDevice(),Q5.device.lost.then((e=>{console.error("WebGPU crashed!"),console.error(e)}))}return!0},Q5.WebGPU=async function(e,t){let r;return e&&"global"!=e||(Q5._hasGlobal=!0),await Q5.initWebGPU()||(r=new Q5(e,t,"webgpu-fallback")),r=new Q5(e,t,"webgpu"),await r.ready,r};
9
+ function Q5(e,t,r){let n,i=this;i._isQ5=i._q5=!0,i._parent=t,i.ready=new Promise((e=>{n=e})),"webgpu-fallback"==r?(i._renderer="c2d",i._webgpu=i._webgpuFallback=!0):(i._renderer=r||"c2d",i["_"+i._renderer]=!0);let a,o="auto"==e;if(e??="global","auto"==e){if(!(window.setup||window.update||Q5.update||window.draw||Q5.draw))return;e="global"}"global"==e&&(Q5._hasGlobal=i._isGlobal=!0,a=Q5._esm?globalThis:Q5._server?global:window),"graphics"==e&&(i._isGraphics=!0),"image"==e&&(i._isImage=!0);let s=new Proxy(i,{set:(e,t,r)=>(i[t]=r,i._isGlobal&&(a[t]=r),!0)});i.canvas=i.ctx=i.drawingContext=null,i.pixels=[];let l=null,d=!0;async function c(e){for(let t of Q5.hooks[e])await t.call(i,s)}i.frameCount=0,i.deltaTime=16,i._targetFrameRate=0,i._targetFrameDuration=16.666666666666668,i._frameRate=i._fps=60,i._loop=!0;let h=0;i.millis=()=>performance.now()-h,i.noCanvas=()=>{i.canvas?.remove&&i.canvas.remove(),i.canvas=0,s.ctx=s.drawingContext=0},window&&(i.windowWidth=window.innerWidth,i.windowHeight=window.innerHeight,i.deviceOrientation=window.screen?.orientation?.type),i._loaders=[],i.loadAll=()=>{let e=[...i._loaders];return i._loaders=[],i._g&&(e=e.concat(i._g._loaders),i._g._loaders=[]),Promise.all(e)},i.isPreloadSupported=()=>!0,i.disablePreload=()=>i._disablePreload=!0;const u=[];async function f(e){let t=e||performance.now();if(i._didResize&&(i.windowResized(),i._didResize=!1),i._loop)if(d)l=g(f);else{let e=t+i._targetFrameDuration,r=e-performance.now();for(;r<0;)r+=i._targetFrameDuration;l=setTimeout((()=>f(e)),r)}else if(i.frameCount&&!i._redraw)return;if(i.frameCount&&d&&!i._redraw){if(t-i._lastFrameTime<i._targetFrameDuration-4)return}s.deltaTime=t-i._lastFrameTime,i._frameRate=1e3/i.deltaTime,s.frameCount++;let r=performance.now();i.resetMatrix(),i._beginRender&&i._beginRender(),await c("predraw");try{await i.draw()}catch(e){throw Q5.errorTolerant||i.noLoop(),i._fes&&i._fes(e),e}await c("postdraw"),await i.postProcess(),i._render&&i._render(),i._finishRender&&i._finishRender(),s.pmouseX=i.mouseX,s.pmouseY=i.mouseY,s.moveX=s.moveY=0,i._lastFrameTime=t;let n=performance.now();i._fps=Math.round(1e3/(n-r))}i._incrementPreload=()=>{i._loaders.push(new Promise((e=>u.push(e))))},i._decrementPreload=()=>{u.length&&u.pop()()},i.noLoop=()=>{i._loop=!1,null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l)),l=null},i.loop=()=>{i._loop=!0,i._setupDone&&null==l&&f()},i.isLooping=()=>i._loop,i.redraw=async(e=1)=>{i._redraw=!0;for(let t=0;t<e;t++)await f();i._redraw=!1},i.remove=async()=>{i.noLoop(),i.canvas.remove(),await c("remove")},i.frameRate=e=>(e&&e!=i._targetFrameRate&&(i._targetFrameRate=e,i._targetFrameDuration=1e3/e,i._loop&&null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l),l=null),d=e<=60,i._setupDone&&(l=d?g(f):setTimeout((()=>f()),i._targetFrameDuration))),i._frameRate),i.getTargetFrameRate=()=>i._targetFrameRate||60,i.getFPS=()=>i._fps,i.Element=function(e){this.elt=e},i._elements=[],i.describe=()=>{},i.log=i.print=console.log;for(let e in Q5.modules)Q5.modules[e](i,s);let p=Q5.renderers[i._renderer];for(let e in p)p[e](i,s);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(i[e]=Q5[e]);if(i._isGraphics)return;if(i._isGlobal){let e=Object.assign({},i);delete e.Color,Object.assign(Q5,e),delete Q5.Q5}for(let e of Q5.hooks.init)e.call(i,s);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof i[e]&&(i[e]=t.bind(i));for(let[e,t]of Object.entries(Q5.preloadMethods))i[e]=function(){return i._incrementPreload(),t.apply(i,arguments)};if(i._isGlobal){let e=Object.getOwnPropertyNames(i);for(let t of e)"_"!=t[0]&&(a[t]=i[t]);for(let e of["_incrementPreload","_decrementPreload"])a[e]=i[e]}"function"==typeof e&&e(i),Q5._instanceCount++;let g=window.requestAnimationFrame||function(e){const t=i._lastFrameTime+i._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},m=a||i,x=["postProcess","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","doubleClicked","mouseWheel","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized","preload"];for(let e of x)i[e]??=()=>{};x.pop();let _=["update","draw","drawFrame",...x];if(i._isGlobal)for(let e of _)Q5[e]?i[e]=Q5[e]:Object.defineProperty(Q5,e,{get:()=>i[e],set:t=>i[e]=t});function v(e){const t=m[e]||i[e];i[e]=e=>{try{return t(e)}catch(e){throw i._fes&&i._fes(e),e}}}async function b(){await c("presetup"),n(),v("preload"),i.preload(),await Promise.race([new Promise((e=>{!function t(){i.setup||i.update||i.draw||m.setup||m.update||m.draw?e():i._setupDone||(i.canvas?.ready&&i._render&&(i._beginRender(),i._render(),i._finishRender()),g(t))}()})),new Promise((e=>{setTimeout((()=>{i._loaders.length||e()}),500)}))]),i._disablePreload||await i.loadAll(),i.setup??=m.setup||(()=>{}),v("setup");for(let e of x)v(e);i.draw??=m.draw||(()=>{}),h=performance.now(),await i.setup(),i._setupDone=!0,null===i.ctx&&i.createCanvas(200,200),await c("postsetup"),i.frameCount||(i._lastFrameTime=performance.now()-15,g(f))}Q5.instances.push(i),o||Q5._esm?b():setTimeout(b,32)}function createCanvas(e,t,r){if(Q5._hasGlobal)return;if("c2d"==e||"c2d"==t||"c2d"==r||"c2d"==r?.renderer||!Q5._esm){let n=new Q5,i=n.createCanvas(e,t,r);return n.ready.then((()=>i))}return Q5.WebGPU().then((n=>n.createCanvas(e,t,r)))}Q5.renderers={},Q5.modules={},Q5._server="object"==typeof process,Q5._esm=void 0===this,Q5._instanceCount=0,Q5.instances=[],Q5._friendlyError=(e,t)=>{Q5.disableFriendlyErrors||console.error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.hooks={init:[],presetup:[],postsetup:[],predraw:[],postdraw:[],remove:[]},Q5.addHook=(e,t)=>Q5.hooks[e].push(t),Q5.registerAddon=e=>{let t={};e(Q5,Q5.prototype,t);for(let e in t)Q5.hooks[e].push(t[e])},Q5.prototype.registerMethod=(e,t)=>{("beforeSetup"==e||e.includes("Preload"))&&(e="presetup"),"afterSetup"==e&&(e="postsetup"),"pre"==e&&(e="predraw"),"post"==e&&(e="postdraw"),Q5.hooks[e].push(t)},Q5.preloadMethods={},Q5.prototype.registerPreloadMethod=(e,t)=>Q5.preloadMethods[e]=t[e],Q5._server&&(global.q5=global.Q5=Q5,global.p5??=Q5),"object"==typeof window?(window.q5=window.Q5=Q5,window.p5??=Q5,window.createCanvas=createCanvas,window.C2D="c2d",window.WEBGPU="webgpu"):global.window=0,Q5.version=Q5.VERSION="3.6","object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||(Q5.update||Q5.draw?Q5.WebGPU():new Q5("auto"))})),Q5.modules.canvas=(e,t)=>{e._Canvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._server?Q5._createServerCanvas&&(t.canvas=Q5._createServerCanvas(200,200)):(e._isImage||e._isGraphics)&&(t.canvas=new e._Canvas(200,200)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas()),e.displayDensity=()=>window.devicePixelRatio||1,e.width=200,e.height=200,e._pixelDensity=1;let r=e.canvas;if(r&&(r.width=200,r.height=200,r.colorSpace=Q5.canvasOptions.colorSpace,e._isImage||(r.renderer=e._renderer,r[e._renderer]=!0,e._pixelDensity=Math.ceil(e.displayDensity()))),e._adjustDisplay=e=>{let t=r.style;t&&e&&(t.width=r.w+"px",t.height=r.h+"px")},e.createCanvas=function(t,i,a){(isNaN(t)||"string"==typeof t&&!t.includes(":"))&&(a=t,t=null),"number"!=typeof i&&(a=i,i=null),a??=arguments[3],"string"==typeof a&&(a={renderer:a});let o=Object.assign({},Q5.canvasOptions);if("object"==typeof a&&Object.assign(o,a),!e._isImage)if(e._isGraphics)e._pixelDensity=this._pixelDensity;else if(Q5._server)r.visible=!0;else{let t=r,i=document.body||document.documentElement;for(;t&&t.parentElement!=i;)t=t.parentElement;if(t||(document.getElementById(r.id)?.remove(),n()),window.IntersectionObserver){let t=!1;new IntersectionObserver((n=>{if(n[0].isIntersecting)r.visible=!0;else{let e=r.getBoundingClientRect();r.visible=e.top<window.innerHeight&&e.bottom>0&&e.left<window.innerWidth&&e.right>0}t||(e._wasLooping=e._loop,t=!0),r.visible?e._wasLooping&&!e._loop&&e.loop():(e._wasLooping=e._loop,e.noLoop())})).observe(r)}}e._setCanvasSize(t,i),Object.assign(r,o);let s=e._createCanvas(r.w,r.h,o);return e._addEventMethods&&e._addEventMethods(r),e.canvas.ready=!0,s},e.createGraphics=function(t,r,n={}){"string"==typeof n&&(n={renderer:n});let i=new Q5("graphics",void 0,n.renderer||(e._webgpuFallback?"webgpu-fallback":e._renderer));n.alpha??=!0,n.colorSpace??=e.canvas.colorSpace,n.pixelDensity??=e._pixelDensity,i._defaultImageScale=e._defaultImageScale,i.createCanvas.call(e,t,r,n);let a=i._pixelDensity*e._defaultImageScale;return i.defaultWidth=t*a,i.defaultHeight=r*a,i},e._setCanvasSize=(n,i)=>{i??=n??window.innerHeight,n??=window.innerWidth,r.w=n=Math.ceil(n),r.h=i=Math.ceil(i),t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity),t.width=n,t.height=i,e.displayMode&&!r.displayMode?e.displayMode():e._adjustDisplay(!0)},e._setImageSize=(n,i)=>{t.width=r.w=n,t.height=r.h=i,t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity)},e.defaultImageScale=t=>t?(e._g&&(e._g._defaultImageScale=t),e._defaultImageScale=t):e._defaultImageScale,e.defaultImageScale(.5),!e._isImage){if(r&&!e._isGraphics){function n(){let t=e._parent;if(t??=document.getElementsByTagName("main")[0],!t){t=document.createElement("main"),(document.body||document.documentElement).appendChild(t)}r.parent(t),document.body||document.addEventListener("DOMContentLoaded",(()=>{document.body&&document.body.appendChild(t)}))}r.parent=t=>{function n(){e.frameCount>1&&(e._didResize=!0,e._adjustDisplay())}r.parentElement&&r.parentElement.removeChild(r),"string"==typeof t&&(t=document.getElementById(t)),t.append(r),"function"==typeof ResizeObserver?(e._ro&&e._ro.disconnect(),e._ro=new ResizeObserver(n),e._ro.observe(t)):e.frameCount||window.addEventListener("resize",n)},n()}e.resizeCanvas=(t,n)=>{if(!e.ctx)return e.createCanvas(t,n);t==r.w&&n==r.h||e._resizeCanvas(t,n)},r&&!Q5._createServerCanvas&&(r.resize=e.resizeCanvas),e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._resizeCanvas(r.w,r.h),e._g&&e._g.pixelDensity(t),t):e._pixelDensity,window&&!e._isGraphics&&window.addEventListener("resize",(()=>{e._didResize=!0,t.windowWidth=window.innerWidth,t.windowHeight=window.innerHeight,t.deviceOrientation=window.screen?.orientation?.type}))}},Q5.CENTER="center",Q5.LEFT="left",Q5.RIGHT="right",Q5.TOP="top",Q5.BOTTOM="bottom",Q5.BASELINE="alphabetic",Q5.MIDDLE="middle",Q5.NORMAL="normal",Q5.ITALIC="italic",Q5.BOLD="bold",Q5.BOLDITALIC="italic bold",Q5.ROUND="round",Q5.SQUARE="butt",Q5.PROJECT="square",Q5.MITER="miter",Q5.BEVEL="bevel",Q5.NONE="none",Q5.SIMPLE="simple",Q5.CHORD_OPEN=0,Q5.PIE_OPEN=1,Q5.PIE=2,Q5.CHORD=3,Q5.RADIUS="radius",Q5.CORNER="corner",Q5.CORNERS="corners",Q5.OPEN=0,Q5.CLOSE=1,Q5.VIDEO="video",Q5.AUDIO="audio",Q5.LANDSCAPE="landscape",Q5.PORTRAIT="portrait",Q5.BLEND="source-over",Q5.REMOVE="destination-out",Q5.ADD="lighter",Q5.DARKEST="darken",Q5.LIGHTEST="lighten",Q5.DIFFERENCE="difference",Q5.SUBTRACT="subtract",Q5.EXCLUSION="exclusion",Q5.MULTIPLY="multiply",Q5.SCREEN="screen",Q5.REPLACE="copy",Q5.OVERLAY="overlay",Q5.HARD_LIGHT="hard-light",Q5.SOFT_LIGHT="soft-light",Q5.DODGE="color-dodge",Q5.BURN="color-burn",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.SEPIA=9,Q5.BRIGHTNESS=10,Q5.SATURATION=11,Q5.CONTRAST=12,Q5.HUE_ROTATE=13,Q5.C2D=Q5.P2D=Q5.P2DHDR="c2d",Q5.WEBGL="webgl",Q5.GPU=Q5.WEBGPU="webgpu",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.renderers.c2d={},Q5.renderers.c2d.canvas=(e,t)=>{let r=e.canvas;function n(){let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r]}e.colorMode&&e.colorMode("rgb",e._webgpu?1:255),e._createCanvas=function(n,i,a){if(r)return t.ctx=t.drawingContext=r.getContext("2d",a),e._isImage||(e.ctx.fillStyle=e._fill="white",e.ctx.strokeStyle=e._stroke="black",e.ctx.lineCap="round",e.ctx.lineJoin="miter",e.ctx.textAlign="left",e._strokeWeight=1),e.ctx.scale(e._pixelDensity,e._pixelDensity),e.ctx.save(),r;console.error("q5 canvas could not be created. skia-canvas and jsdom packages not found.")},e.clear=()=>{e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e._isImage||(e.background=function(t){e.ctx.save(),e.ctx.resetTransform(),e.ctx.globalAlpha=1,t.canvas?e.image(t,0,0,e.canvas.width,e.canvas.height):(Q5.Color&&!t._isColor&&(t=e.color(...arguments)),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height)),e.ctx.restore()},e._resizeCanvas=(t,n)=>{let i,a={};for(let t in e.ctx)"function"!=typeof e.ctx[t]&&(a[t]=e.ctx[t]);if(delete a.canvas,e.frameCount>1){i=new e._Canvas(r.width,r.height),i.w=r.w,i.h=r.h,i.getContext("2d").drawImage(r,0,0)}e._setCanvasSize(t,n);for(let t in a)e.ctx[t]=a[t];e.scale(e._pixelDensity),i&&e.ctx.drawImage(i,0,0,i.w,i.h)},e.fill=function(t){if(e._doFill=e._fillSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doFill=!1;e.ctx.fillStyle=e._fill=t.toString()},e.stroke=function(t){if(e._doStroke=e._strokeSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=e._stroke=t.toString()},e.strokeWeight=t=>{t||(e._doStroke=!1),e.ctx.lineWidth=e._strokeWeight=t||1e-4},e.noFill=()=>e._doFill=!1,e.noStroke=()=>e._doStroke=!1,e.opacity=t=>e.ctx.globalAlpha=t,e._getFillIdx=()=>e._fill,e._setFillIdx=t=>e._fill=t,e._getStrokeIdx=()=>e._stroke,e._setStrokeIdx=t=>e._stroke=t,e._doShadow=!1,e._shadowOffsetX=e._shadowOffsetY=e._shadowBlur=10,e.shadow=function(t){if(Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doShadow=!1;e.ctx.shadowColor=e._shadow=t.toString(),e._doShadow=!0,e.ctx.shadowOffsetX||=e._shadowOffsetX,e.ctx.shadowOffsetY||=e._shadowOffsetY,e.ctx.shadowBlur||=e._shadowBlur},e.shadowBox=(t,r,n)=>{e.ctx.shadowOffsetX=e._shadowOffsetX=t,e.ctx.shadowOffsetY=e._shadowOffsetY=r||t,e.ctx.shadowBlur=e._shadowBlur=n||0},e.noShadow=()=>{e._doShadow=!1,e.ctx.shadowOffsetX=e.ctx.shadowOffsetY=e.ctx.shadowBlur=0},e.translate=(t,r)=>{t.x&&(r=t.y,t=t.x),e.ctx.translate(t,r)},e.rotate=t=>{e._angleMode&&(t=e.radians(t)),e.ctx.rotate(t)},e.scale=(t,r)=>{t.x&&(r=t.y,t=t.x),r??=t,e.ctx.scale(t,r)},e.applyMatrix=(t,r,n,i,a,o)=>e.ctx.transform(t,r,n,i,a,o),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&&(e.ctx.resetTransform(),e.scale(e._pixelDensity),e._webgpu&&e.translate(e.halfWidth,e.halfHeight))},e._styleNames=["_fill","_stroke","_strokeWeight","_doFill","_doStroke","_fillSet","_strokeSet","_shadow","_doShadow","_shadowOffsetX","_shadowOffsetY","_shadowBlur","_tint","_textSize","_textAlign","_textBaseline","_imageMode","_rectMode","_ellipseMode","_colorMode","_colorFormat","Color"],e._styles=[],e.pushStyles=()=>{let t={};for(let r of e._styleNames)t[r]=e[r];e._styles.push(t),e._fontMod&&e._updateFont()},e.popStyles=()=>{n(),e.ctx.fillStyle=e._fill,e.ctx.strokeStyle=e._stroke,e.ctx.lineWidth=e._strokeWeight,e.ctx.shadowColor=e._shadow,e.ctx.shadowOffsetX=e._doShadow?e._shadowOffsetX:0,e.ctx.shadowOffsetY=e._doShadow?e._shadowOffsetY:0,e.ctx.shadowBlur=e._doShadow?e._shadowBlur:0},e.pushMatrix=()=>e.ctx.save(),e.popMatrix=()=>e.ctx.restore(),e.push=()=>{e.pushStyles(),e.ctx.save()},e.pop=()=>{e.ctx.restore(),n()})},Q5.renderers.c2d.shapes=e=>{e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=Q5.CENTER,e._rectMode=Q5.CORNER;let t=!0,r=[];function n(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}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=()=>{},e.line=(t,r,n,i)=>{e._doStroke&&(e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(n,i),e.ctx.stroke())};const i=2*Math.PI;function a(t,r,n,a,o,s,l){if(e._angleMode&&(o=e.radians(o),s=e.radians(s)),(o%=i)<0&&(o+=i),(s%=i)<0&&(s+=i),o>s&&(s+=i),o==s)return e.ellipse(t,r,n,a);if(n/=2,a/=2,n=Math.abs(n),a=Math.abs(a),e._doFill||l!=e.PIE_OPEN||(l=e.CHORD_OPEN),e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),l!=e.PIE&&l!=e.PIE_OPEN||e.ctx.lineTo(t,r),e._doFill&&e.ctx.fill(),e._doStroke){if(l!=e.PIE&&l!=e.CHORD||e.ctx.closePath(),l!=e.PIE_OPEN)return e.ctx.stroke();e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),e.ctx.stroke()}}function o(t,r,a,o){e.ctx.beginPath(),e.ctx.ellipse(t,r,Math.abs(a/2),Math.abs(o/2),0,0,i),n()}function s(t,r,i,a,o,l,d,c){return void 0===o?function(t,r,i,a){e.ctx.beginPath(),e.ctx.rect(t,r,i,a),n()}(t,r,i,a):void 0===l?s(t,r,i,a,o,o,o,o):(e.ctx.beginPath(),e.ctx.roundRect(t,r,i,a,[o,l,d,c]),void n())}e.arc=(t,r,n,i,o,s,l)=>{if(o==s)return e.ellipse(t,r,n,i);l??=e.PIE_OPEN,e._ellipseMode==e.CENTER?a(t,r,n,i,o,s,l):e._ellipseMode==e.RADIUS?a(t,r,2*n,2*i,o,s,l):e._ellipseMode==e.CORNER?a(t+n/2,r+i/2,n,i,o,s,l):e._ellipseMode==e.CORNERS&&a((t+n)/2,(r+i)/2,n-t,i-r,o,s,l)},e.ellipse=(t,r,n,i)=>{i??=n,e._ellipseMode==e.CENTER?o(t,r,n,i):e._ellipseMode==e.RADIUS?o(t,r,2*n,2*i):e._ellipseMode==e.CORNER?o(t+n/2,r+i/2,n,i):e._ellipseMode==e.CORNERS&&o((t+n)/2,(r+i)/2,n-t,i-r)},e.circle=(t,r,a)=>{e._ellipseMode==e.CENTER?(e.ctx.beginPath(),e.ctx.arc(t,r,Math.abs(a/2),0,i),n()):e.ellipse(t,r,a,a)},e.point=(t,r)=>{e._doStroke&&(t.x&&(r=t.y,t=t.x),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(t,r),e.ctx.stroke())},e.rect=(t,r,n,i=n,a,o,l,d)=>{e._rectMode==e.CENTER?s(t-n/2,r-i/2,n,i,a,o,l,d):e._rectMode==e.RADIUS?s(t-n,r-i,2*n,2*i,a,o,l,d):e._rectMode==e.CORNER?s(t,r,n,i,a,o,l,d):e._rectMode==e.CORNERS&&s(t,r,n-t,i-r,a,o,l,d)},e.square=(t,r,n,i,a,o,s)=>e.rect(t,r,n,n,i,a,o,s),e.capsule=(t,r,i,a,o)=>{const s=i-t,l=a-r,d=Math.hypot(s,l);if(0===d)return e.circle(t,r,2*o);const c=Math.atan2(l,s),h=-l/d*o,u=s/d*o;e.ctx.beginPath(),e.ctx.moveTo(t-h,r-u),e.ctx.arc(t,r,o,c-e.HALF_PI,c+e.HALF_PI,!0),e.ctx.lineTo(i+h,a+u),e.ctx.arc(i,a,o,c+e.HALF_PI,c-e.HALF_PI,!0),e.ctx.closePath(),n()},e.beginShape=()=>{r=[],e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),r=[],t=!0},e.endContour=()=>{r=[],t=!0},e.vertex=(n,i)=>{r=[],t?e.ctx.moveTo(n,i):e.ctx.lineTo(n,i),t=!1},e.bezierVertex=(t,n,i,a,o,s)=>{r=[],e.ctx.bezierCurveTo(t,n,i,a,o,s)},e.quadraticVertex=(t,n,i,a)=>{r=[],e.ctx.quadraticCurveTo(t,n,i,a)},e.bezier=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(n,i,a,o,s,l),e.endShape()},e.triangle=(t,r,n,i,a,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.endShape(e.CLOSE)},e.quad=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{r=[],t&&e.ctx.closePath(),n()},e.curveVertex=(n,i)=>{if(r.push([n,i]),r.length<4)return;let a=r.at(-4),o=r.at(-3),s=r.at(-2),l=r.at(-1),d=o[0]+(s[0]-a[0])/6,c=o[1]+(s[1]-a[1])/6,h=s[0]-(l[0]-o[0])/6,u=s[1]-(l[1]-o[1])/6;t&&(e.ctx.moveTo(o[0],o[1]),t=!1),e.ctx.bezierCurveTo(d,c,h,u,s[0],s[1])},e.curve=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(n,i),e.curveVertex(a,o),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,r,n,i)=>{const a=i*i*i,o=i*i;return e*(-.5*a+o-.5*i)+t*(1.5*a-2.5*o+1)+r*(-1.5*a+2*o+.5*i)+n*(.5*a-.5*o)},e.bezierPoint=(e,t,r,n,i)=>{const a=1-i;return Math.pow(a,3)*e+3*Math.pow(a,2)*i*t+3*a*Math.pow(i,2)*r+Math.pow(i,3)*n},e.curveTangent=(e,t,r,n,i)=>{const a=i*i;return e*(-3*a/2+2*i-.5)+t*(9*a/2-5*i)+r*(-9*a/2+4*i+.5)+n*(3*a/2-i)},e.bezierTangent=(e,t,r,n,i)=>{const a=1-i;return 3*n*Math.pow(i,2)-3*r*Math.pow(i,2)+6*r*a*i-6*t*a*i+3*t*Math.pow(a,2)-3*e*Math.pow(a,2)},e.erase=function(t,r){255==e._colorFormat&&(t&&(t/=255),r&&(r/=255)),e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgb(0 0 0 / ${t||1})`,e.ctx.strokeStyle=`rgb(0 0 0 / ${r||1})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInPath(t*n,r*n)},e.inStroke=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInStroke(t*n,r*n)}},Q5.renderers.c2d.image=(e,t)=>{const r=e.canvas;r&&(r.convertToBlob??=e=>new Promise((t=>{r.toBlob((e=>t(e)),e.type,e.quality)}))),e._tint=null;let n=null,i=null;e.createImage=(t,r,n={})=>(n.colorSpace??=e.canvas.colorSpace,n.defaultImageScale??=e._defaultImageScale,new Q5.Image(t,r,n)),e.loadImage=function(t,r,n){if(t.canvas)return t;if("gif"==t.slice(-3).toLowerCase())throw new Error("q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84");let i=[...arguments].at(-1);"object"==typeof i?(n=i,r=null):n=void 0;let a=e.createImage(1,1,n),o=a._pixelDensity,s=new window.Image;return s.crossOrigin="Anonymous",a.promise=new Promise(((t,i)=>{s.onload=()=>{delete a.then,a._usedAwait&&(a=e.createImage(1,1,n)),s._pixelDensity=o,a.defaultWidth=s.width*e._defaultImageScale,a.defaultHeight=s.height*e._defaultImageScale,a.naturalWidth=s.naturalWidth||s.width,a.naturalHeight=s.naturalHeight||s.height,a._setImageSize(Math.ceil(a.naturalWidth/o),Math.ceil(a.naturalHeight/o)),a.ctx.drawImage(s,0,0),r&&r(a),t(a)},s.onerror=i})),e._loaders.push(a.promise),a.then=(e,t)=>(a._usedAwait=!0,a.promise.then(e,t)),a.src=s.src=t,a},e._imageMode=Q5.CORNER,e.imageMode=t=>e._imageMode=t,e.image=(t,r,n,i,a,o=0,s=0,l,d)=>{if(!t)return;let c=t.canvas||t;i??=t.defaultWidth||c.width||t.videoWidth,a??=t.defaultHeight||c.height||t.videoHeight,"center"==e._imageMode&&(r-=.5*i,n-=.5*a);let h=t._pixelDensity||1;if(l?l*=h:l=c.width||c.videoWidth,d?d*=h:d=c.height||c.videoHeight,e._tint){if(t._retint||t._tint!=e._tint){t._tintImg??=e.createImage(t.w,t.h,{pixelDensity:h}),t._tintImg.width==t.width&&t._tintImg.height==t.height||t._tintImg.resize(t.w,t.h);let r=t._tintImg.ctx;r.globalCompositeOperation="copy",r.fillStyle=e._tint,r.fillRect(0,0,t.width,t.height),t?.canvas?.alpha&&(r.globalCompositeOperation="destination-in",r.drawImage(c,0,0,t.width,t.height)),r.globalCompositeOperation="multiply",r.drawImage(c,0,0,t.width,t.height),t._tint=e._tint,t._retint=!1}c=t._tintImg.canvas}t.flipped&&(e.ctx.save(),e.ctx.translate(r+i,0),e.ctx.scale(-1,1),r=0),e.ctx.drawImage(c,o*h,s*h,l,d,r,n,i,a),t.flipped&&e.ctx.restore()},e.filter=(t,n)=>{e.ctx.save();let i="";if(e.ctx.filter){if("string"==typeof t)i=t;else if(t==Q5.GRAY)i="saturate(0%)";else if(t==Q5.INVERT)i="invert(100%)";else if(t==Q5.BLUR){i=`blur(${Math.ceil(n*e._pixelDensity)||1}px)`}else if(t==Q5.THRESHOLD){n??=.5,i=`saturate(0%) brightness(${Math.floor(.5/Math.max(n,1e-5)*100)}%) contrast(1000000%)`}else if(t==Q5.SEPIA)i=`sepia(${n??1})`;else if(t==Q5.BRIGHTNESS)i=`brightness(${n??1})`;else if(t==Q5.SATURATION)i=`saturate(${n??1})`;else if(t==Q5.CONTRAST)i=`contrast(${n??1})`;else if(t==Q5.HUE_ROTATE){i=`hue-rotate(${n}${0==e._angleMode?"rad":"deg"})`}if(i&&(e.ctx.filter=i,"none"==e.ctx.filter))throw new Error(`Invalid filter format: ${t}`)}i||e._softFilter(t,n),e.ctx.globalCompositeOperation="source-over",e.ctx.drawImage(r,0,0,r.w,r.h),e.ctx.restore(),e.modified=e._retint=!0},e._isImage&&(e.resize=(t,n)=>{let i=new e._Canvas(r.width,r.height);i.getContext("2d",{colorSpace:r.colorSpace}).drawImage(r,0,0),e._setImageSize(t,n),e.defaultWidth=r.width*e._defaultImageScale,e.defaultHeight=r.height*e._defaultImageScale,e.ctx.clearRect(0,0,r.width,r.height),e.ctx.drawImage(i,0,0,r.width,r.height),e.modified=e._retint=!0}),e._getImageData=(t,n,i,a)=>e.ctx.getImageData(t,n,i,a,{colorSpace:r.colorSpace}),e.trim=()=>{let t=e._pixelDensity||1,n=r.width,i=r.height,a=e._getImageData(0,0,n,i).data,o=n,s=0,l=i,d=0,c=3;for(let e=0;e<i;e++)for(let t=0;t<n;t++)0!==a[c]&&(t<o&&(o=t),t>s&&(s=t),e<l&&(l=e),e>d&&(d=e)),c+=4;return l=Math.floor(l/t),d=Math.floor(d/t),o=Math.floor(o/t),s=Math.floor(s/t),e.get(o,l,s-o+1,d-l+1)},e.mask=t=>{e.ctx.save(),e.ctx.resetTransform();let r=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="destination-in",e.ctx.drawImage(t.canvas,0,0),e.ctx.globalCompositeOperation=r,e.ctx.restore(),e.modified=e._retint=!0},e.inset=(t,n,i,a,o,s,l,d)=>{let c=e._pixelDensity||1;e.ctx.drawImage(r,t*c,n*c,i*c,a*c,o,s,l,d),e.modified=e._retint=!0},e.copy=()=>{let t=e.get();for(let r in e)"function"==typeof e[r]||/(canvas|ctx|texture)/.test(r)||(t[r]=e[r]);return t},e.get=(t,n,a,o)=>{let s=e._pixelDensity||1;if(void 0!==t&&void 0===a){i||e.loadPixels();let a=Math.floor(t*s),o=4*(Math.floor(n*s)*r.width+a);return[i[o],i[o+1],i[o+2],i[o+3]]}t=Math.floor(t||0)*s,n=Math.floor(n||0)*s,a??=e.width,o??=e.height;let l=e.createImage(a,o,{pixelDensity:s});return l.ctx.drawImage(r,t,n,a*s,o*s,0,0,a,o),l.width=a,l.height=o,e._owner?._makeDrawable&&e._owner._makeDrawable(l),l},e.set=(t,n,a)=>{if(t=Math.floor(t),n=Math.floor(n),e.modified=e._retint=!0,a.canvas){let r=e._tint;return e._tint=null,e.image(a,t,n),void(e._tint=r)}i||e.loadPixels();let o=e._pixelDensity||1,s=a.r,l=a.g,d=a.b,c=a.a;1==(e._colorFormat||e._owner?._colorFormat)&&(s*=255,l*=255,d*=255,c*=255);for(let e=0;e<o;e++)for(let a=0;a<o;a++){let h=4*((n*o+e)*r.width+t*o+a);i[h]=s,i[h+1]=l,i[h+2]=d,i[h+3]=c}},e.loadPixels=()=>{n=e._getImageData(0,0,r.width,r.height),t.pixels=i=n.data},e.updatePixels=()=>{null!=n&&(e.ctx.putImageData(n,0,0),e.modified=e._retint=!0)},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,e._isImage||(e.tint=function(t){e._tint=(t._isColor?t:e.color(...arguments)).toString()},e.noTint=()=>e._tint=null)},Q5.Image=class{constructor(e,t,r={}){r.alpha??=!0,r.colorSpace??=Q5.canvasOptions.colorSpace;let n=this;n._isImage=!0,n.canvas=n.ctx=n.drawingContext=null,n.pixels=[],Q5.modules.canvas(n,n);let i=Q5.renderers.c2d;for(let e of["canvas","image","softFilters"])i[e]&&i[e](n,n);n._pixelDensity=r.pixelDensity||1,n._defaultImageScale=r.defaultImageScale||2,n.createCanvas(e,t,r);let a=n._pixelDensity*n._defaultImageScale;n.defaultWidth=e*a,n.defaultHeight=t*a,delete n.createCanvas,n._loop=!1}get w(){return this.width}get h(){return this.height}},Q5.renderers.c2d.softFilters=e=>{let t=null;function r(){let r=e.canvas.width*e.canvas.height*4;t&&t.length==r||(t=new Uint8ClampedArray(r))}e._softFilter=(n,i)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let r=0;r<e.length;r+=4){const n=.2126*e[r]+.7152*e[r+1]+.0722*e[r+2];e[r]=e[r+1]=e[r+2]=n>=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t<e.length;t+=4){const r=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];e[t]=e[t+1]=e[t+2]=r}},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 r=t-1;for(let n=0;n<e.length;n+=4)e[n]=255*(e[n]*t>>8)/r,e[n+1]=255*(e[n+1]*t>>8)/r,e[n+2]=255*(e[n+2]*t>>8)/r},e._filters[Q5.DILATE]=(n,i)=>{i??=Math.max,r(),t.set(n);let[a,o]=[e.canvas.width,e.canvas.height];for(let e=0;e<o;e++)for(let r=0;r<a;r++){let s=4*Math.max(r-1,0),l=4*Math.min(r+1,a-1),d=4*Math.max(e-1,0)*a,c=4*Math.min(e+1,o-1)*a,h=4*e*a,u=4*r;for(let e=0;e<4;e++){let r=e+d,a=e+c,o=e+h;n[h+u+e]=i(t[r+u],t[o+s],t[o+u],t[o+l],t[a+u])}}},e._filters[Q5.ERODE]=t=>{e._filters[Q5.DILATE](t,Math.min)},e._filters[Q5.BLUR]=(n,i)=>{i=i||1,i=Math.floor(i*e._pixelDensity),r(),t.set(n);let a=2*i+1,o=function(e){let t=new Float32Array(e),r=.3*i+.8,n=r*r*2;for(let i=0;i<e;i++){let a=i-e/2,o=Math.exp(-a*a/n)/(2.5066282746*r);t[i]=o}return t}(a),[s,l]=[e.canvas.width,e.canvas.height];for(let e=0;e<l;e++)for(let r=0;r<s;r++){let l=0,d=0,c=0,h=0;for(let n=0;n<a;n++){let a=4*(e*s+Math.min(Math.max(r-i+n,0),s-1));l+=t[a]*o[n],d+=t[a+1]*o[n],c+=t[a+2]*o[n],h+=t[a+3]*o[n]}let u=4*(e*s+r);n[u]=l,n[u+1]=d,n[u+2]=c,n[u+3]=h}t.set(n);for(let e=0;e<l;e++)for(let r=0;r<s;r++){let d=0,c=0,h=0,u=0;for(let n=0;n<a;n++){let a=4*(Math.min(Math.max(e-i+n,0),l-1)*s+r);d+=t[a]*o[n],c+=t[a+1]*o[n],h+=t[a+2]*o[n],u+=t[a+3]*o[n]}let f=4*(e*s+r);n[f]=d,n[f+1]=c,n[f+2]=h,n[f+3]=u}});let a=e._getImageData(0,0,e.canvas.width,e.canvas.height);e._filters[n](a.data,i),e.ctx.putImageData(a,0,0)}},Q5.renderers.c2d.text=(e,t)=>{e._textAlign="left",e._textBaseline="alphabetic",e._textSize=12;let r="sans-serif",n=!1,i=15,a=3,o="normal",s="normal",l=0,d=!1,c=0;e._fontMod=!1;let h=e._textCache={};e.loadFont=(t,r)=>{let n;if(t.includes("fonts.googleapis.com/css"))n=function(e,t){e.startsWith("http")||(e="https://"+e);const r=new URL(e).searchParams,n=r.get("family");if(!n)return console.error("Invalid Google Fonts URL: missing family parameter"),null;const i=n.split(":")[0];let a={family:i};return a.promise=(async()=>{try{const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch Google Font: ${r.status} ${r.statusText}`);let n,o=await r.text(),s=/@font-face\s*{([^}]*)}/g,l=/src:\s*url\(([^)]+)\)[^;]*;/,d=/font-family:\s*['"]([^'"]+)['"]/,c=/font-weight:\s*([^;]+);/,h=/font-style:\s*([^;]+);/,u=[];for(;null!==(n=s.exec(o));){let e=n[1],t=l.exec(e);if(!t)continue;let r=t[1],i=d.exec(e);if(!i)continue;let a=i[1],o=c.exec(e),s=o?o[1]:"400",f=h.exec(e),p=f?f[1]:"normal",g=`${a}-${s}-${p}`.replace(/\s+/g,"-"),m=new FontFace(a,`url(${r})`,{weight:s,style:p});document.fonts.add(m);try{await m.load(),u.push(m)}catch(e){console.error(`Failed to load font face: ${g}`,e)}}return a._usedAwait&&(a={family:i}),a.faces=u,delete a.then,t&&t(a),a}catch(e){throw console.error("Error loading Google Font:",e),e}})(),a}(t,r);else{let e=t.split("/").pop().split(".")[0].replace(" ","");n={family:e};let i=new FontFace(e,`url(${encodeURI(t)})`);document.fonts.add(i),n.promise=new Promise(((e,t)=>{i.load().then((()=>{delete n.then,r&&r(i),e(i)})).catch((e=>{t(e)}))}))}return e._loaders.push(n.promise),e.textFont(n.family),n.then=(e,t)=>(n._usedAwait=!0,n.promise.then(e,t)),n},e.textFont=t=>{if(t&&"string"!=typeof t&&(t=t.family),!t||t==r)return r;r=t,e._fontMod=!0,l=-1},e.textSize=t=>{if(null==t)return e._textSize;e._textSize=t,e._fontMod=!0,l=-1,n||(i=1.25*t,a=i-t)},e.textStyle=t=>{if(!t)return o;o=t,e._fontMod=!0,l=-1},e.textWeight=t=>{if(!t)return s;s=t,e._fontMod=!0,l=-1},e.textLeading=t=>null==t?i||1.25*e._textSize:(n=!0,t==i?i:(i=t,a=t-e._textSize,void(l=-1))),e.textAlign=(t,r)=>{e.ctx.textAlign=e._textAlign=t,r&&(e.ctx.textBaseline=e._textBaseline=r==e.CENTER?"middle":r)},e._updateFont=()=>{e.ctx.font=`${o} ${s} ${e._textSize}px ${r}`,e._fontMod=!1},e.textWidth=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).width),e.textAscent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxDescent),e.textFill=e.fill,e.textStroke=e.stroke;e.createTextImage=(t,r,n)=>{d=!0;let i=e.text(t,0,0,r,n);return d=!1,i};let u=[];e.text=(t,n,s,f,p)=>{if(void 0===t||!e._doFill&&!e._doStroke)return;t=t.toString();let g,m,x,_,v,b,y,w,S=e.ctx;if(e._fontMod&&e._updateFont(),d)if(-1==l&&(()=>{let t=r+e._textSize+o+i,n=5381;for(let e=0;e<t.length;e++)n=33*n^t.charCodeAt(e);l=n>>>0})(),m=e._fill+e._stroke+e._strokeWeight,x=h[t],x?_=x[l]:x=h[t]={},_){if(g=_[m],g)return g;if(_.size>=4){for(let e in _){g=_[e],delete _[e];break}v=!0}}else _=x[l]={};if(-1==t.indexOf("\n")?u[0]=t:u=t.split("\n"),t.length>f){let e=[];for(let t of u){let r=0;for(;r<t.length;){let n=r+f;if(n>=t.length){e.push(t.slice(r));break}let i=t.lastIndexOf(" ",n);(-1===i||i<r)&&(i=n),e.push(t.slice(r,i)),r=i+1}}u=e}if(d){if(b=0,y=i,g){let e=g.canvas;g.ctx.clearRect(0,0,e.width,e.height),g.modified=!0}else{let t=e.ctx.textBaseline;e.ctx.textBaseline="alphabetic";let r=S.measureText(" "),n=r.fontBoundingBoxAscent,o=r.fontBoundingBoxDescent;e.ctx.textBaseline=t;let s=0;for(let e of u){let t=S.measureText(e).width;t>s&&(s=t)}let l=Math.ceil(s),d=Math.ceil(i*u.length+o);g=e.createImage.call(e,l,d,{pixelDensity:e._pixelDensity,defaultImageScale:1/e._pixelDensity}),g._ascent=n,g._descent=o,g._top=o+a,g._middle=g._top+.5*n+i*(u.length-1)*.5,g._bottom=g._top+n+i*(u.length-1),g._leading=i}S=g.ctx,S.font=e.ctx.font,S.fillStyle=e._fill,S.strokeStyle=e._stroke,S.lineWidth=e.ctx.lineWidth}else b=n,y=s,"middle"==e._textBaseline?y-=i*(u.length-1)*.5:"bottom"==e._textBaseline&&(y-=i*(u.length-1));e._fillSet||(w=S.fillStyle,S.fillStyle="black");let C=0;for(let t of u)if(e._doStroke&&e._strokeSet&&S.strokeText(t,b,y),e._doFill&&S.fillText(t,b,y),y+=i,C++,C>=p)break;if(u=[],e._fillSet||(S.fillStyle=w),d){if(_[m]=g,v||(_.size||(Object.defineProperty(_,"size",{writable:!0,enumerable:!1}),_.size=0),_.size++,c++),c>Q5.MAX_TEXT_IMAGES){for(const e in h){x=h[e];for(const e in x){_=x[e];for(let e in _){let t=_[e];t._texture&&t._texture.destroy(),delete _[e]}}}c=0}return g}},e.textImage=(t,r,n)=>{"string"==typeof t&&(t=e.createTextImage(t));let i=e._imageMode;e._imageMode="corner";let a=e._textAlign;"center"==a?r-=t.canvas.hw:"right"==a&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?n-=t._leading:"middle"==o?n-=t._middle:"bottom"==o?n-=t._bottom:"top"==o&&(n-=t._top),e.image(t,r,n),e._imageMode=i}},Q5.fonts=[],Q5.MAX_TEXT_IMAGES=5e3,Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e.RGBHDR=e._colorMode="rgb",e.HSL="hsl",e.HSB="hsb",e.OKLCH="oklch",e.SRGB="srgb",e.DISPLAY_P3="display-p3",e.colorMode=(r,n,i)=>{e._colorMode=r;let a="srgb"==e.canvas.colorSpace||"srgb"==i;e._srgb=a,n??="rgb"==r&&(e._c2d||a)?255:1,e._colorFormat="integer"==n||255==n?255:1,"oklch"==r?t.Color=Q5.ColorOKLCH:"hsl"==r?t.Color=a?Q5.ColorHSL:Q5.ColorHSL_P3:"hsb"==r?t.Color=a?Q5.ColorHSB:Q5.ColorHSB_P3:(255==e._colorFormat?t.Color=a?Q5.ColorRGB_8:Q5.ColorRGB_P3_8:t.Color=a?Q5.ColorRGB:Q5.ColorRGB_P3,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],coral:[255,127,80],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],silver:[192,192,192],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=(t,r,n,i)=>{let a=e.Color;if(t._isColor)return new a(...t.levels);if(null==r){if("string"==typeof t){if("#"==t[0])t.length<=5?(t.length>4&&(i=parseInt(t[4]+t[4],16)),n=parseInt(t[3]+t[3],16),r=parseInt(t[2]+t[2],16),t=parseInt(t[1]+t[1],16)):(t.length>7&&(i=parseInt(t.slice(7,9),16)),n=parseInt(t.slice(5,7),16),r=parseInt(t.slice(3,5),16),t=parseInt(t.slice(1,3),16));else{if(!e._namedColors[t]){let e=new a(0,0,0);return e._css=t,e.toString=function(){return this._css},e}if([t,r,n,i]=e._namedColors[t],"rgb"!=e._colorMode)return a=e._srgb?Q5.ColorRGB_8:Q5.ColorRGB_P3_8,new a(t,r,n,i)}1==e._colorFormat&&(t/=255,r&&(r/=255),n&&(n/=255),i&&(i/=255))}(Array.isArray(t)||t.constructor==Float32Array)&&([t,r,n,i]=t)}return null==n?e._colorMode==Q5.OKLCH?new a(t,0,0,r):new a(t,t,t,r):new a(t,r,n,i)},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=t=>{if(t.l)return t.l;let r=100*(.2126*t.r+.7152*t.g+.0722*t.b);return 255==e._colorFormat?r/255:r},e.hue=t=>{if(t.h)return t.h;let r=t.r,n=t.g,i=t.b;255==e._colorFormat&&(r/=255,n/=255,i/=255);let a,o=Math.max(r,n,i),s=Math.min(r,n,i);return a=o==s?0:o==r?60*(n-i)/(o-s):o==n?60*(i-r)/(o-s)+120:60*(r-n)/(o-s)+240,a<0&&(a+=360),a},e.lerpColor=(t,r,n)=>{if(n=Math.max(0,Math.min(1,n)),"rgb"==e._colorMode)return new e.Color(e.lerp(t.r,r.r,n),e.lerp(t.g,r.g,n),e.lerp(t.b,r.b,n),e.lerp(t.a,r.a,n));{let i=r.h-t.h;i>180&&(i-=360),i<-180&&(i+=360);let a=t.h+n*i;return a<0&&(a+=360),a>360&&(a-=360),new e.Color(e.lerp(t.l,r.l,n),e.lerp(t.c,r.c,n),a,e.lerp(t.a,r.a,n))}}},Q5.Color=class{constructor(){this._isColor=!0,this._q5Color=!0}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,r,n){super(),this.l=e,this.c=t,this.h=r,this.a=n??1}get levels(){return[this.l,this.c,this.h,this.a]}equals(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h&&this.a==e.a}isSameColor(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h}toString(){return`oklch(${this.l} ${this.c} ${this.h} / ${this.a})`}get lightness(){return this.l}set lightness(e){this.l=e}get chroma(){return this.c}set chroma(e){this.c=e}get hue(){return this.h}set hue(e){this.h=e}},Q5.ColorRGB=class extends Q5.Color{constructor(e,t,r,n){super(),this.r=e,this.g=t,this.b=r,this.a=n??1}get levels(){return[this.r,this.g,this.b,this.a]}equals(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b}toString(){return`color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`}get red(){return this.r}set red(e){this.r=e}get green(){return this.g}set green(e){this.g=e}get blue(){return this.b}set blue(e){this.b=e}},Q5.ColorRGB_P3=class extends Q5.ColorRGB{toString(){return`color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`}},Q5.ColorRGB_8=class extends Q5.ColorRGB{constructor(e,t,r,n){super(e,t,r,n??255)}setRed(e){this.r=e}setGreen(e){this.g=e}setBlue(e){this.b=e}setAlpha(e){this.a=e}toString(){return`rgb(${this.r} ${this.g} ${this.b} / ${this.a/255})`}},Q5.ColorRGB_P3_8=class extends Q5.ColorRGB_8{constructor(e,t,r,n){super(e,t,r,n??255),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),r=(this._b/255).toFixed(3),n=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${r} / ${n})`,this._edited=!1}return this._css}},Q5.ColorHSL=class extends Q5.Color{constructor(e,t,r,n){super(),this.h=e,this.s=t,this.l=r,this.a=n??1}get levels(){return[this.h,this.s,this.l,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l}toString(){return`hsl(${this.h} ${this.s} ${this.l} / ${this.a})`}get hue(){return this.h}set hue(e){this.h=e}get saturation(){return this.s}set saturation(e){this.s=e}get lightness(){return this.l}set lightness(e){this.l=e}},Q5.ColorHSL_P3=class extends Q5.ColorHSL{toString(){return`color(display-p3 ${Q5.HSLtoRGB(this.h,this.s,this.l).join(" ")} / ${this.a})`}},Q5.ColorHSB=class extends Q5.ColorHSL{constructor(e,t,r,n){super(e,t,r,n),delete this.l,this.b=r}get levels(){return[this.h,this.s,this.b,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b}toString(){return`hsl(${Q5.HSBtoHSL(this.h,this.s,this.b).join(" ")} / ${this.a})`}get v(){return this.b}set v(e){this.b=e}get brightness(){return this.b}set brightness(e){this.b=e}get value(){return this.b}set value(e){this.b=e}},Q5.ColorHSB_P3=class extends Q5.ColorHSB{toString(){return`color(display-p3 ${Q5.HSLtoRGB(...Q5.HSBtoHSL(this.h,this.s,this.b)).join(" ")} / ${this.a})`}},Q5.HSLtoRGB=(e,t,r)=>{r/=100;let n=t/100*Math.min(r,1-r),i=(t,i=(t+e/30)%12)=>r-n*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]},Q5.HSBtoHSL=(e,t,r,n=r*(1-t/200))=>[e,n&&100!=n?(r-n)/Math.min(n,100-n)*100:0,n];{const e=(e,t)=>[e[0]*t[0]+e[1]*t[1]+e[2]*t[2],e[3]*t[0]+e[4]*t[1]+e[5]*t[2],e[6]*t[0]+e[7]*t[1]+e[8]*t[2]],t=(e,t,r)=>[e,isNaN(r)?0:t*Math.cos(r*Math.PI/180),isNaN(r)?0:t*Math.sin(r*Math.PI/180)],r=e=>e.map((e=>Math.max(0,Math.min(1,Math.abs(e)>.0031308?(e<0?-1:1)*(1.055*Math.abs(e)**(1/2.4)-.055):12.92*e)))),n=t=>{const r=e([1,.3963377773761749,.2158037573099136,1,-.1055613458156586,-.0638541728258133,1,-.0894841775298119,-1.2914855480194092],t);return e([1.2268798758459243,-.5578149944602171,.2813910456659647,-.0405757452148008,1.112286803280317,-.0717110580655164,-.0763729366746601,-.4214933324022432,1.5869240198367816],r.map((e=>e**3)))},i=t=>e([3.2409699419045226,-1.537383177570094,-.4986107602930034,-.9692436362808796,1.8759675015077202,.04155505740717559,.05563007969699366,-.20397695888897652,1.0569715142428786],t);Q5.OKLCHtoRGB=(e,a,o)=>r(i(n(t(e,a,o))))}Q5.modules.display=e=>{if(!e.canvas||e._isGraphics)return;let t=e.canvas;e.MAXED="maxed",e.SMOOTH="smooth",e.PIXELATED="pixelated",0!=Q5._instanceCount||Q5._server||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 display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.q5-centered,\nmain.q5-maxed {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>"),e._adjustDisplay=e=>{let r=t.style;if(r)if("normal"==t.displayMode){if(!e)return;r.width=t.w*t.displayScale+"px",r.height=t.h*t.displayScale+"px"}else{let e=t.parentElement.getBoundingClientRect();t.w/t.h>e.width/e.height?("centered"==t.displayMode?(r.width=t.w*t.displayScale+"px",r.maxWidth="100%"):r.width="100%",r.height="auto",r.maxHeight=""):(r.width="auto",r.maxWidth="","centered"==t.displayMode?(r.height=t.h*t.displayScale+"px",r.maxHeight="100%"):r.height="100%")}},e.displayMode=(r="normal",n="smooth",i=1)=>{Q5._server||("string"==typeof i&&(i=parseFloat(i.slice(1))),"fullscreen"==r&&(r="maxed"),"center"==r&&(r="centered"),t.displayMode&&(t.parentElement.classList.remove("q5-"+t.displayMode),t.classList.remove("q5-pixelated")),t.parentElement.classList.add("q5-"+r),"pixelated"==n&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.defaultImageScale(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),Object.assign(t,{displayMode:r,renderQuality:n,displayScale:i}),e.ctx&&e.pushStyles(),e._adjustDisplay(!0),e.ctx&&e.popStyles())},e.fullscreen=e=>{if(null==e)return document.fullscreenElement;e?document.body.requestFullscreen():document.exitFullscreen()}},Q5.modules.dom=(e,t)=>{e.elementMode=t=>e._elementMode=t,e.createElement=(t,r)=>{let n=document.createElement(t);return"center"==e._elementMode&&(n.style.transform="translate(-50%, -50%)"),r&&(n.innerHTML=r),Object.defineProperty(n,"x",{get:()=>n._x,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetLeft+t;n.style.left=i+"px",n._x=i}}),Object.defineProperty(n,"y",{get:()=>n._y,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetTop+t;n.style.top=i+"px",n._y=i}}),Object.defineProperty(n,"width",{get:()=>parseFloat(n.style.width||0),set:e=>n.style.width=e+"px"}),Object.defineProperty(n,"height",{get:()=>parseFloat(n.style.height||0),set:e=>n.style.height=e+"px"}),n.position=(e,t,r)=>(r&&(n.style.position=r),n.x=e,n.y=t,n),Object.defineProperty(n,"size",{writable:!0}),n.size=(e,t)=>(n.width=e,n.height=t,n),n.center=()=>(n.style.position="absolute",n.x=e.canvas.hw,n.y=e.canvas.hh,n),n.show=()=>(n.style.display="",n),n.hide=()=>(n.style.display="none",n),n.parent=e=>(e.append(n),n),e._addEventMethods(n),e._elements.push(n),e.canvas?e.canvas.parentElement.append(n):document.body.append(n),n.elt=n,n},e.createEl=e.createElement,e._addEventMethods=e=>{let t=e.addEventListener;e.mousePressed=e=>t("mousedown",e),e.mouseReleased=e=>t("mouseup",e),e.mouseClicked=e=>t("click",e),e.mouseMoved=e=>t("mousemove",e),e.mouseWheel=e=>t("wheel",e)},e.createA=(t,r,n)=>{let i=e.createEl("a",r);return i.href=t,i.target=n?"_blank":"_self",i},e.createButton=t=>e.createEl("button",t),e.createCheckbox=(t="",r=!1)=>{let n=e.createEl("input");n.type="checkbox",n.checked=r;let i=e.createEl("label",t);return i.addEventListener("click",(()=>{n.checked=!n.checked,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))})),n.insertAdjacentElement("afterend",i),n.label=i,n},e.createColorPicker=(t="#ffffff")=>{let r=e.createEl("input");return r.type="color",r.value=t.toString(),r},e.createDiv=t=>e.createEl("div",t),e.createImg=t=>{let r=e.createEl("img");return r.crossOrigin="anonymous",r.src=t,r},e.createInput=(t="",r="text")=>{let n=e.createEl("input");return n.value=t,n.type=r,n.style.boxSizing="border-box",n},e.createP=t=>e.createEl("p",t);let r=0;function n(t){t.width||=t.videoWidth,t.height||=t.videoHeight,t.defaultWidth=t.width*e._defaultImageScale,t.defaultHeight=t.height*e._defaultImageScale,t.ready=!0}e.createRadio=t=>{let n=e.createEl("div");return n.name=t||"radio"+r++,n.buttons=[],Object.defineProperty(n,"value",{get:()=>n.selected?.value,set:e=>{let t=n.buttons.find((t=>t.value==e));t&&(t.checked=!0,n.selected=t)}}),n.option=(t,r)=>{let i=e.createEl("input");i.type="radio",i.name=n.name,i.value=r||t,i.addEventListener("input",(()=>n.selected=i));let a=e.createEl("label",t);return a.addEventListener("click",(()=>{i.checked=!0,n.selected=i,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0}))})),i.label=a,n.append(i),n.append(a),n.buttons.push(i),n},n},e.createSelect=t=>{let r=e.createEl("select");if(t){let n=e.createEl("option",t);n.disabled=!0,n.selected=!0,r.append(n)}return Object.defineProperty(r,"selected",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.textContent)):r.selectedOptions[0]?.textContent,set:e=>{if(r.multiple)Array.from(r.options).forEach((t=>{t.selected=e.includes(t.textContent)}));else{const t=Array.from(r.options).find((t=>t.textContent===e));t&&(t.selected=!0)}}}),Object.defineProperty(r,"value",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.value)):r.selectedOptions[0]?.value,set:e=>{if(r.multiple)r.options.forEach((t=>t.selected=e.includes(t.value)));else{let t;for(let n=0;n<r.options.length;n++)if(r.options[n].value==e){t=r.options[n];break}t&&(t.selected=!0)}}}),r.option=(t,n)=>{let i=e.createEl("option",t);return i.value=n||t,r.append(i),r},r},e.createSlider=(t,r,n,i)=>{let a=e.createEl("input");return a.type="range",a.min=t,a.max=r,a.step=i,a.value=n,a.val=()=>parseFloat(a.value),a},e.createSpan=t=>e.createEl("span",t),e.createVideo=t=>{let r=e.createEl("video");return r.crossOrigin="anonymous",t&&(r.promise=new Promise((i=>{r.addEventListener("loadeddata",(()=>{delete r.then,r._usedAwait&&(r=e.createEl("video"),r.crossOrigin="anonymous",r.src=t),n(r),i(r)})),r.src=t})),e._loaders.push(r.promise),r.then=(e,t)=>(r._usedAwait=!0,r.promise.then(e,t))),r},e.createCapture=function(t,r=!0,i){let a="string"==typeof t?{[t]:!0}:t||{video:!0,audio:!0};!0===a.video&&(a.video={width:3840,height:2160}),a.video.facingMode??="user";let o=e.createVideo();return o.promise=(async()=>{let t;try{t=await navigator.mediaDevices.getUserMedia(a)}catch(e){throw e}return delete o.then,o._usedAwait&&(o=e.createVideo()),function(t){t.playsinline=t.autoplay=!0,r&&(t.flipped=!0,t.style.transform="scale(-1, 1)"),t.loadPixels=()=>{let r=e.createGraphics(t.videoWidth,t.videoHeight,{renderer:"c2d"});r.image(t,0,0),r.loadPixels(),t.pixels=r.pixels,r.remove()}}(o),o.srcObject=t,await new Promise((e=>o.addEventListener("loadeddata",e))),n(o),i&&i(o),o})(),e._loaders.push(o.promise),o.then=(e,t)=>(o._usedAwait=!0,o.promise.then(e,t)),o},e.findElement=e=>document.querySelector(e),e.findElements=e=>document.querySelectorAll(e)},Q5.modules.fes=e=>{if(e._fes=async t=>{if(Q5.disableFriendlyErrors)return;t._handledByFES=!0;let r=t.stack?.split("\n");if(!r?.length)return;let n=1,i="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(n=0,i="@");r[n].indexOf("q5")>=0;)n++;let a=r[n].split(i).at(-1);a.startsWith("blob:")&&(a=a.slice(5)),a=a.split(")")[0];let o=a.split(":"),s=parseInt(o.at(-2));o[o.length-1]=o.at(-1).split(")")[0];let l=t.file||o.slice(0,-2).join(":"),d=l.split("/").at(-1);try{let t=(await(await fetch(l)).text()).split("\n"),r=t[s-1]?.trim()??"",n=["🐛","🐞","🐜","🦗","🦋","🪲"][Math.floor(6*Math.random())],i=window.self!==window.top,a=`q5.js ${n}`,o=` Error in ${d} on line ${s}:\n\n${r}`;i?e.log(a+o):e.log(`%c${a}%c${o}`,"background: #b7ebff; color: #000;","")}catch(e){}},"undefined"!=typeof window&&window.addEventListener){let t=new Error,r=t.stack?.split("\n")||"";for(let t of r){let r=t.match(/(https?:\/\/[^\s)]+\.js|\b\/[^\s)]+\.js)/);if(r){let t=r[1];if(!/q5|p5play/i.test(t)){e._sketchFile=t;break}}}e._sketchFile&&(window.addEventListener("error",(t=>{let r=t.error;t.filename!==e._sketchFile||r?._handledByFES||(r.file=t.filename,e._fes(r))})),window.addEventListener("unhandledrejection",(t=>{let r=t.reason;r?.stack?.includes(e._sketchFile)&&!r?._handledByFES&&e._fes(r)})))}if(e._isGlobal&&0!=Q5.online&&null!=typeof navigator&&navigator.onLine){!async function(){try{let e=await fetch("https://data.jsdelivr.com/v1/package/npm/q5");if(!e.ok)return;let t=(await e.json()).tags.latest;t=t.slice(0,t.lastIndexOf(".")),t!=Q5.version&&console.warn(`q5.js v${t} is now available! Consider updating from v${Q5.version}.`)}catch(e){}}()}},Q5.modules.input=(e,t)=>{if(e._isGraphics)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.pointers={},e.mouseButton="",e.keyIsPressed=!1,e.mouseIsPressed=!1,e.key="",e.keyCode=0,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 r={},n=[Q5.LEFT,Q5.CENTER,Q5.RIGHT],i=e.canvas;e._startAudio=()=>{Q5.aud&&"running"==Q5.aud?.state||e.userStartAudio()},e._updatePointer=r=>{let n=r.pointerId;e.pointers[n]??={event:r};let a,o,s=e.pointers[n];if(s.event=r,i){let t=i.getBoundingClientRect(),n=i.scrollWidth/e.width||1,s=i.scrollHeight/e.height||1;a=(r.clientX-t.left)/n,o=(r.clientY-t.top)/s,e._webgpu&&(a-=i.hw,o-=i.hh)}else a=r.clientX,o=r.clientY;s.x=a,s.y=o,!r.isPrimary&&r.pointerId||(document.pointerLockElement?(t.mouseX+=r.movementX,t.mouseY+=r.movementY):(t.mouseX=a,t.mouseY=o),t.moveX=r.movementX,t.moveY=r.movementY)};let a=0;function o(t){const r=e.canvas.getBoundingClientRect(),n=e.canvas.scrollWidth/e.width||1,i=e.canvas.scrollHeight/e.height||1;let a=0,o=0;return e._webgpu&&(a=e.halfWidth,o=e.halfHeight),{x:(t.clientX-r.left)/n-a,y:(t.clientY-r.top)/i-o,id:t.identifier}}if(e._onpointerdown=r=>{a++,e._startAudio(),e._updatePointer(r),t.mouseIsPressed=!0,t.mouseButton=n[r.button],e.mousePressed(r)},e._onpointermove=t=>{i&&!i.visible||(e._updatePointer(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t))},e._onpointerup=r=>{t.mouseIsPressed=!1,a>0&&(a--,e._updatePointer(r),delete e.pointers[r.pointerId],e.mouseReleased(r))},e._onclick=r=>{e._updatePointer(r),t.mouseIsPressed=!0,e.mouseClicked(r),t.mouseIsPressed=!1},e._ondblclick=r=>{e._updatePointer(r),t.mouseIsPressed=!0,e.doubleClicked(r),t.mouseIsPressed=!1},e._onwheel=t=>{e._updatePointer(t),t.delta=t.deltaY;let r=e.mouseWheel(t);(e._isGlobal&&!r||0==r)&&t.preventDefault()},e.cursor=(t,r,n)=>{let i="";t.includes(".")&&(t=`url("${t}")`,i=", auto"),void 0!==r&&(t+=" "+r+" "+n),e.canvas.style.cursor=t+i},e.noCursor=()=>e.canvas.style.cursor="none",e.pointerLock=(e=!1)=>{document.body?.requestPointerLock({unadjustedMovement:e})},e._onkeydown=n=>{n.repeat||(e._startAudio(),t.keyIsPressed=!0,t.key=n.key,t.keyCode=n.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!0,e.keyPressed(n),1==n.key.length&&e.keyTyped(n))},e._onkeyup=n=>{t.keyIsPressed=!1,t.key=n.key,t.keyCode=n.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!1,e.keyReleased(n)},e.keyIsDown=e=>!!r["string"==typeof e?e.toLowerCase():e],e._updateTouches=t=>{if(i&&!i.visible)return;let r=[...t.changedTouches].map(o);for(let t of r){let r=e.touches.find((e=>e.id==t.id));r?(r.x=t.x,r.y=t.y):e.touches.push(t)}for(let r=e.touches.length-1;r>=0;r--){let n=e.touches[r],i=!1;for(let e=0;e<t.touches.length;e++)if(t.touches[e].identifier===n.id){i=!0;break}i||e.touches.splice(r,1)}},e._ontouchstart=t=>{e._startAudio(),e.touchStarted(t)||t.preventDefault()},e._ontouchmove=t=>{e.touchMoved(t)||t.preventDefault()},e._ontouchend=t=>{e.touchEnded(t)||t.preventDefault()},window){let t=window.addEventListener;t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1);let r=window.PointerEvent?"pointer":"mouse";t(r+"move",(t=>e._onpointermove(t)),!1),t(r+"up",(t=>e._onpointerup(t))),t(r+"cancel",(t=>e._onpointerup(t))),t("touchstart",(t=>e._updateTouches(t))),t("touchmove",(t=>e._updateTouches(t))),t("touchend",(t=>e._updateTouches(t))),t("touchcancel",(t=>e._updateTouches(t))),i&&i.addEventListener("wheel",(t=>e._onwheel(t))),!e._isGlobal&&i&&(t=i.addEventListener.bind(i)),t(r+"down",(t=>e._onpointerdown(t))),t("click",(t=>e._onclick(t))),t("dblclick",(t=>e._ondblclick(t))),i&&(t=i.addEventListener.bind(i)),t("touchstart",(t=>e._ontouchstart(t))),t("touchmove",(t=>e._ontouchmove(t))),t("touchend",(t=>e._ontouchend(t))),t("touchcancel",(t=>e._ontouchend(t)))}},Q5.modules.math=(e,t)=>{e.RADIANS=0,e.DEGREES=1,e.PI=Math.PI,e.HALF_PI=Math.PI/2,e.QUARTER_PI=Math.PI/4,e.TWO_PI=e.TAU=2*Math.PI,e.abs=Math.abs,e.ceil=Math.ceil,e.exp=Math.exp,e.floor=e.int=Math.floor,e.loge=Math.log,e.mag=Math.hypot,e.max=Math.max,e.min=Math.min,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2,e.round=(e,t=0)=>{let r=10**t;return Math.round(e*r)/r};let r=e._angleMode=0;e.angleMode=t=>(r=e._angleMode=0==t||"radians"==t?0:1,r?"degrees":"radians");let n=e._DEGTORAD=Math.PI/180,i=e._RADTODEG=180/Math.PI;function a(){let e,t,r=4294967295;return{setSeed(n){e=t=(n??Math.random()*r)>>>0},getSeed:()=>t,rand:()=>(e^=e<<17,e^=e>>13,e^=e<<5,(e>>>0)/r)}}e.degrees=t=>t*e._RADTODEG,e.radians=t=>t*e._DEGTORAD,e.map=Q5.prototype.map=(e,t,r,n,i,a)=>{let o=n+1*(e-t)/(r-t)*(i-n);return a?n<i?Math.min(Math.max(o,n),i):Math.min(Math.max(o,i),n):o},e.dist=function(){let e=arguments;return 2==e.length?Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y):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.lerp=(e,t,r)=>e*(1-r)+t*r,e.constrain=(e,t,r)=>Math.min(Math.max(e,t),r),e.norm=(t,r,n)=>e.map(t,r,n,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=e=>Math.sin(r?e*n:e),e.cos=e=>Math.cos(r?e*n:e),e.tan=e=>Math.tan(r?e*n:e),e.asin=e=>{let t=Math.asin(e);return r?t*i:t},e.acos=e=>{let t=Math.acos(e);return r?t*i:t},e.atan=e=>{let t=Math.atan(e);return r?t*i:t},e.atan2=(e,t)=>{let n=Math.atan2(e,t);return r?n*i:n};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.jit=(t=1)=>e.random(-t,t),e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,r;return{setSeed(n){r=t=(n??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(r=(1664525*r+1013904223)%e,r/e)}}():t==e.SHR3&&(o=a()),o.setSeed()};var s=new function(){var e,t,r,n=new Array(128),i=new Array(256),a=new Array(128),s=new Array(128),l=new Array(256),d=new Array(256),c=()=>4294967296*o.rand()-2147483648,h=()=>.5+2.328306e-10*(c()|0),u=()=>{for(var t,i,o,l,d=3.44262;;){if(t=r*a[e],0==e){do{o=h(),l=h(),t=.2904764*-Math.log(o),i=-Math.log(l)}while(i+i<t*t);return r>0?d+t:-d-t}if(s[e]+h()*(s[e-1]-s[e])<Math.exp(-.5*t*t))return t;if(r=c(),e=127&r,Math.abs(r)<n[e])return r*a[e]}},f=()=>{for(var r;;){if(0==e)return 7.69711-Math.log(h());if(r=t*l[e],d[e]+h()*(d[e-1]-d[e])<Math.exp(-r))return r;if((t=c())<i[e=255&t])return t*l[e]}};this.SHR3=c,this.UNI=h,this.RNOR=()=>(r=c(),e=127&r,Math.abs(r)<n[e]?r*a[e]:u()),this.REXP=()=>(t=c()>>>0)<n[e=255&t]?t*l[e]:f(),this.zigset=()=>{var e,t,r=2147483648,o=4294967296,c=3.442619855899,h=c,u=.00991256303526217,f=7.697117470131487,p=f,g=.003949659822581572;for(e=u/Math.exp(-.5*c*c),n[0]=Math.floor(c/e*r),n[1]=0,a[0]=e/r,a[127]=c/r,s[0]=1,s[127]=Math.exp(-.5*c*c),t=126;t>=1;t--)c=Math.sqrt(-2*Math.log(u/c+Math.exp(-.5*c*c))),n[t+1]=Math.floor(c/h*r),h=c,s[t]=Math.exp(-.5*c*c),a[t]=c/r;for(e=g/Math.exp(-f),i[0]=Math.floor(f/e*o),i[1]=0,l[0]=e/o,l[255]=f/o,d[0]=1,d[255]=Math.exp(-f),t=254;t>=1;t--)f=-Math.log(g/f+Math.exp(-f)),i[t+1]=Math.floor(f/p*o),p=f,d[t]=Math.exp(-f),l[t]=f/o}};let l;s.hasInit=!1,e.randomGaussian=(e,t)=>(s.hasInit||(s.zigset(),s.hasInit=!0),s.RNOR()*t+e),e.randomExponential=()=>(s.hasInit||(s.zigset(),s.hasInit=!0),s.REXP()),e.PERLIN="perlin",e.SIMPLEX="simplex",e.BLOCKY="blocky",e.NoiseGenerator=Q5.PerlinNoise,e.noiseMode=e=>{t.NoiseGenerator=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],l=null},e.noiseSeed=t=>{l=new e.NoiseGenerator(t)},e.noise=(t=0,r=0,n=0)=>(l??=new e.NoiseGenerator,l.noise(t,r,n)),e.noiseDetail=(t,r)=>{l??=new e.NoiseGenerator,t>0&&(l.octaves=t),r>0&&(l.falloff=r)}},Q5.NoiseGenerator=class{},Q5.PerlinNoise=class extends Q5.NoiseGenerator{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,r,n=[];for(let e=0;e<256;e++)n[e]=e;for(let i=255;i>0;i--)t=(e=16807*e%2147483647)%(i+1),r=n[i],n[i]=n[t],n[t]=r;return n}dot(e,t,r,n){return e[0]*t+e[1]*r+e[2]*n}mix(e,t,r){return(1-r)*e+r*t}fade(e){return e*e*e*(e*(6*e-15)+10)}noise(e,t,r){let n=this,i=0,a=1,o=1,s=0;for(let l=0;l<n.octaves;l++){const l=255&Math.floor(e*a),d=255&Math.floor(t*a),c=255&Math.floor(r*a),h=e*a-Math.floor(e*a),u=t*a-Math.floor(t*a),f=r*a-Math.floor(r*a),p=n.fade(h),g=n.fade(u),m=n.fade(f),x=n.p[l]+d,_=n.p[x]+c,v=n.p[x+1]+c,b=n.p[l+1]+d,y=n.p[b]+c,w=n.p[b+1]+c,S=n.mix(n.dot(n.grad3[n.p[_]%12],h,u,f),n.dot(n.grad3[n.p[y]%12],h-1,u,f),p),C=n.mix(n.dot(n.grad3[n.p[v]%12],h,u-1,f),n.dot(n.grad3[n.p[w]%12],h-1,u-1,f),p),Q=n.mix(n.dot(n.grad3[n.p[_+1]%12],h,u,f-1),n.dot(n.grad3[n.p[y+1]%12],h-1,u,f-1),p),M=n.mix(n.dot(n.grad3[n.p[v+1]%12],h,u-1,f-1),n.dot(n.grad3[n.p[w+1]%12],h-1,u-1,f-1),p),P=n.mix(S,C,g),E=n.mix(Q,M,g);i+=n.mix(P,E,m)*o,s+=o,o*=n.falloff,a*=2}return(i/s+1)/2}},Q5.modules.record=(e,t)=>{let r,n,i,a,o,s,l;function d(t={}){document.head.insertAdjacentHTML("beforeend","<style>\n.rec {\n\tdisplay: flex;\n\tz-index: 1000;\n\tgap: 6px;\n\tbackground: #1a1b1d;\n\tpadding: 6px 8px;\n\tborder-radius: 21px;\n\tbox-shadow: #0000001a 0px 4px 12px;\n\tborder: 2px solid transparent; \n\topacity: 0.6;\n\ttransition: all 0.3s;\n\twidth: 134px;\n\toverflow: hidden;\n}\n\n.rec:hover {\n\twidth: unset;\n\topacity: 0.96;\n}\n\n.rec.recording { border-color: #cc3e44; }\n\n.rec button,\n.rec select { cursor: pointer; }\n\n.rec button,\n.rec select,\n.rec input,\n.rec span {\n\tfont-family: sans-serif;\n\tfont-size: 14px;\n\tpadding: 2px 10px;\n\tborder-radius: 18px;\n\toutline: none;\n\tbackground: #232529;\n\tcolor: #d4dae6;\n\tbox-shadow: #0000001a 0px 4px 12px;\n\tborder: 1px solid #46494e;\n\tvertical-align: middle;\n\tline-height: 18px;\n\ttransition: all 0.3s;\n}\n\n.rec .audio-toggle {\n\tfont-size: 16px;\n\tpadding: 2px 10px;\n}\n\n.rec .bitrate input {\n\tborder-radius: 18px 0 0 18px;\n\tborder-right: 0;\n\twidth: 40px;\n\tpadding: 2px 5px 2px 10px;\n\ttext-align: right;\n}\n\n.rec .bitrate span {\n\tborder-radius: 0 18px 18px 0;\n\tborder-left: 0;\n\tpadding: 2px 10px 2px 5px;\n\tbackground: #333;\n}\n\n.rec .record-button { \n\tcolor: #cc3e44;\n\tfont-size: 18px;\n}\n\n.rec select:hover,\n.rec button:hover { background: #32343b; }\n\n.rec button:disabled {\n\topacity: 0.5;\n\tcolor: #969ba5;\n\tcursor: not-allowed;\n}\n</style>"),r=e.createEl("div"),r.className="rec",r.innerHTML='\n<button class="record-button"></button>\n<span class="record-timer"></span>\n<button></button>\n',[n,a,i]=r.children,r.x=r.y=8,r.resetTimer=()=>r.time={hours:0,minutes:0,seconds:0,frames:0},r.resetTimer();let d="video/mp4; codecs=";r.formats={"H.264":d+'"avc1.42E01E"',VP9:d+"vp9"};let u=d+'"avc1.640034"';e.canvas.width*e.canvas.height>32e5&&MediaRecorder.isTypeSupported(u)&&(r.formats["H.264"]=u),Object.assign(r.formats,t.formats),o=e.createSelect("format");for(const e in r.formats)o.option(e,r.formats[e]);o.title="Video Format",r.append(o);let g=e.createEl("div");g.className="bitrate",g.style.display="flex",r.append(g),s=e.createInput();let m=document.createElement("span");function x(){r.encoderSettings.mimeType=o.value}function _(){r.encoderSettings.videoBitsPerSecond=1e6*s.value}m.textContent="mbps",s.title=m.title="Video Bitrate",g.append(s),g.append(m),l=e.createEl("button"),l.className="audio-toggle active",l.textContent="🔊",l.title="Toggle Audio Recording",r.append(l),r.captureAudio=!0,l.addEventListener("click",(()=>{r.captureAudio=!r.captureAudio,l.textContent=r.captureAudio?"🔊":"🔇",l.classList.toggle("active",r.captureAudio)})),r.encoderSettings={},o.addEventListener("change",x),s.addEventListener("change",_),Object.defineProperty(r,"bitrate",{get:()=>s.value,set:e=>{s.value=e,_()}}),Object.defineProperty(r,"format",{get:()=>o.selected,set:e=>{e=e.toUpperCase(),r.formats[e]&&(o.selected=e,x())}}),r.format="H.264";let v=e.canvas.height;r.bitrate=v>=4320?96:v>=2160?64:v>=1440?48:v>=1080?32:v>=720?26:16,n.addEventListener("click",(()=>{e.recording?r.paused?h():e.pauseRecording():c()})),i.addEventListener("click",(()=>{r.paused?e.saveRecording():e.deleteRecording()})),f(),e.registerMethod("post",p)}function c(){if(!e.recording){if(e.userStartAudio(),!r.stream){r.frameRate??=e.getTargetFrameRate();let t=e.canvas.captureStream(r.frameRate);if(r.videoTrack=t.getVideoTracks()[0],r.captureAudio&&e.getAudioContext){let t=e.getAudioContext(),n=t.createMediaStreamDestination();t.destination.input?t.destination.input.connect(n):Q5.soundOut.connect(n),r.audioTrack=n.stream.getAudioTracks()[0],r.stream=new MediaStream([r.videoTrack,r.audioTrack])}else r.stream=t}r.mediaRecorder=new MediaRecorder(r.stream,r.encoderSettings),r.chunks=[],r.mediaRecorder.addEventListener("dataavailable",(e=>{e.data.size>0&&r.chunks.push(e.data)})),r.mediaRecorder.start(),t.recording=!0,r.paused=!1,r.classList.add("recording"),r.resetTimer(),f(!0)}}function h(){e.recording&&r.paused&&(r.mediaRecorder.resume(),r.paused=!1,f(!0))}function u(){e.recording&&(r.resetTimer(),r.mediaRecorder.stop(),t.recording=!1,r.paused=!1,r.classList.remove("recording"))}function f(e){n.textContent=e?"⏸":"⏺",n.title=(e?"Pause":"Start")+" Recording",i.textContent=e?"🗑️":"💾",i.title=(e?"Delete":"Save")+" Recording",i.disabled=!e}function p(){if(e.recording&&!r.paused){r.time.frames++;let t=e.getTargetFrameRate();r.time.frames>=t&&(r.time.seconds+=Math.floor(r.time.frames/t),r.time.frames%=t,r.time.seconds>=60&&(r.time.minutes+=Math.floor(r.time.seconds/60),r.time.seconds%=60,r.time.minutes>=60&&(r.time.hours+=Math.floor(r.time.minutes/60),r.time.minutes%=60)))}a.textContent=function(){let{hours:e,minutes:t,seconds:n,frames:i}=r.time;return`${String(e).padStart(2,"0")}:${String(t).padStart(2,"0")}:${String(n).padStart(2,"0")}:${String(i).padStart(2,"0")}`}()}e.recording=!1,e.createRecorder=e=>(r||d(e),r),e.record=t=>{r||(d(t),r.hide()),e.recording?r.paused&&h():c()},e.pauseRecording=()=>{e.recording&&!r.paused&&(r.mediaRecorder.pause(),r.paused=!0,f(),n.title="Resume Recording",i.disabled=!1)},e.deleteRecording=()=>{u(),f(),t.recording=!1},e.saveRecording=async n=>{if(!e.recording)return;await new Promise((e=>{r.mediaRecorder.onstop=e,u()}));let i=r.encoderSettings.mimeType,a=i.slice(6,i.indexOf(";")),o=URL.createObjectURL(new Blob(r.chunks,{type:i})),s=document.createElement("iframe"),l=document.createElement("a");s.style.display="none",s.name="download_"+Date.now(),document.body.append(s),l.target=s.name,l.href=o,n??=document.title+" "+(new Date).toLocaleString(void 0,{hour12:!1}).replace(","," at").replaceAll("/","-").replaceAll(":","_"),l.download=`${n}.${a}`,await new Promise((e=>{s.onload=()=>{document.body.removeChild(s),e()},l.click()})),setTimeout((()=>URL.revokeObjectURL(o)),1e3),f(),t.recording=!1}},Q5.modules.sound=(e,t)=>{e.Sound=Q5.Sound;let r=[];e.loadSound=(t,n)=>{let i=new Q5.Sound;return r.push(i),i.promise=(async()=>{let e;i._usedAwait&&(r.splice(r.indexOf(i),1),i=new Q5.Sound,r.push(i));try{await i.load(t)}catch(t){e=t}if(delete i.then,e)throw e;return n&&n(i),i})(),e._loaders.push(i.promise),i.then=(e,t)=>(i._usedAwait=!0,i.promise.then(e,t)),i},e.loadAudio=(t,r)=>{let n=new Audio(t);return n._isAudio=!0,n.crossOrigin="Anonymous",n.promise=new Promise(((e,i)=>{function a(){n.loaded||(delete n.then,n._usedAwait&&(n=new Audio(t),n._isAudio=!0,n.crossOrigin="Anonymous"),n.loaded=!0,r&&r(n),e(n))}n.addEventListener("canplay",a),n.addEventListener("suspend",a),n.addEventListener("error",i)})),e._loaders.push(n.promise),n.then=(e,t)=>(n._usedAwait=!0,n.promise.then(e,t)),n},e.getAudioContext=()=>Q5.aud,e.userStartAudio=()=>{if(window.AudioContext){if(Q5._offlineAudio){Q5._offlineAudio=!1,Q5.aud=new window.AudioContext,Q5.soundOut=Q5.aud.createGain(),Q5.soundOut.connect(Q5.aud.destination);for(let e of Q5.instances)e._userAudioStarted()}return Q5.aud.resume()}},e._userAudioStarted=()=>{for(let e of r)e.init()},e.outputVolume=e=>{Q5.soundOut&&(Q5.soundOut.gain.value=e)}},window.OfflineAudioContext&&(Q5.aud=new window.OfflineAudioContext(2,1,44100),Q5._offlineAudio=!0,Q5.soundOut=Q5.aud.createGain(),Q5.soundOut.connect(Q5.aud.destination)),Q5.Sound=class{constructor(){this._isSound=!0,this.sources=new Set,this.loaded=this.paused=!1}async load(e){this.url=e;let t=await fetch(e);this.buffer=await t.arrayBuffer(),this.buffer=await Q5.aud.decodeAudioData(this.buffer),Q5.aud&&this.init()}init(){this.buffer.length&&(this.gainNode=Q5.aud.createGain(),this.pannerNode=Q5.aud.createStereoPanner(),this.gainNode.connect(this.pannerNode),this.pannerNode.connect(Q5.soundOut),this.loaded=!0,this._volume&&(this.volume=this._volume),this._pan&&(this.pan=this._pan))}_newSource(e,t){let r=Q5.aud.createBufferSource();return r.buffer=this.buffer,r.connect(this.gainNode),r.loop=this._loop,r._startedAt=Q5.aud.currentTime,r._offset=e,r._duration=t,r.start(0,r._offset,r._duration),this.sources.add(r),r.promise=new Promise((e=>{r.onended=()=>{this.paused||(this.ended=!0,this._onended&&this._onended(),this.sources.delete(r),e())}})),r}play(e=0,t){if(!this.loaded)return;let r;if(this.paused){let e=[];for(let t of this.sources)e.push({offset:t._offset,duration:t._duration}),this.sources.delete(t);e.sort(((e,t)=>(e.duration??this.buffer.duration-e.offset)-(t.duration??this.buffer.duration-t.offset)));for(let t of e)r=this._newSource(t.offset,t.duration)}else r=this._newSource(e,t);return this.paused=this.ended=!1,r.promise}pause(){if(this.isPlaying()){for(let e of this.sources){e.stop();let t=Q5.aud.currentTime-e._startedAt;e._offset+=t,e._duration&&(e._duration-=t)}this.paused=!0}}stop(){for(let e of this.sources)e.stop(),this.sources.delete(e);this.paused=!1,this.ended=!0}get volume(){return this._volume}set volume(e){this.loaded&&(this.gainNode.gain.value=e),this._volume=e}get pan(){return this._pan}set pan(e){this.loaded&&(this.pannerNode.pan.value=e),this._pan=e}get loop(){return this._loop}set loop(e){this.sources.forEach((t=>t.loop=e)),this._loop=e}get playing(){return!this.paused&&this.sources.size>0}setVolume(e){this.volume=e}setPan(e){this.pan=e}setLoop(e){this.loop=e}isLoaded(){return this.loaded}isPlaying(){return this.playing}isPaused(){return this.paused}isLooping(){return this._loop}onended(e){this._onended=e}},Q5.modules.util=(e,t)=>{e._loadFile=(t,r,n)=>{let i={};return i.promise=fetch(t).then((e=>e.ok?"json"==n?e.json():e.text():(reject("error loading file"),null))).then((e=>("csv"==n&&(e=Q5.CSV.parse(e)),"string"==typeof e?i.text=e:Object.assign(i,e),delete i.then,r&&r(e),e))),e._loaders.push(i.promise),i.then=(e,t)=>i.promise.then(e,t),i},e.loadText=(t,r)=>e._loadFile(t,r,"text"),e.loadJSON=(t,r)=>e._loadFile(t,r,"json"),e.loadCSV=(t,r)=>e._loadFile(t,r,"csv"),e.loadXML=(t,r)=>{let n={};return n.promise=fetch(t).then((e=>e.text())).then((e=>{let t=(new DOMParser).parseFromString(e,"application/xml");return n.DOM=t,delete n.then,r&&r(t),t})),e._loaders.push(n.promise),n.then=(e,t)=>n.promise.then(e,t),n};const r=/(jpe?g|png|gif|webp|avif|svg)/i,n=/(ttf|otf|woff2?|eot|json)/i,i=/(serif|sans-serif|monospace|cursive|fantasy)/i,a=/(wav|flac|mp3|ogg|m4a|aac|aiff|weba)/i;async function o(e,t,n){let i;if(t=t||"untitled",n=n||"png",r.test(n)){let t=e.canvas||e;i=await t.convertToBlob({type:"image/"+n})}else{let t="text/plain";"json"==n&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),i=new Blob([e],{type:t})}let a=document.createElement("a");a.href=URL.createObjectURL(i),a.download=t+"."+n,a.click(),setTimeout((()=>URL.revokeObjectURL(a.href)),1e3)}e.load=function(...t){Array.isArray(t[0])&&(t=t[0]);let o=[];for(let s of t){let t,l=s.split(".").pop().toLowerCase();t="json"!=l||s.includes("-msdf.")?"csv"==l?e.loadCSV(s):r.test(l)?e.loadImage(s):n.test(l)||i.test(s)?e.loadFont(s):a.test(l)?e.loadSound(s):"xml"==l?e.loadXML(s):e.loadText(s):e.loadJSON(s),o.push(t)}return 1==t.length?o[0]:Promise.all(o)},e.save=(t,r,n)=>{if((!t||"string"==typeof t&&(!r||!n&&r.length<5))&&(n=r,r=t,t=e),n)o(t,r,n);else if(r){let e=r.lastIndexOf(".");o(t,r.slice(0,e),r.slice(e+1))}else o(t)},e.canvas&&!Q5._createServerCanvas&&(e.canvas.save=e.saveCanvas=e.save),"object"==typeof localStorage&&(e.storeItem=(e,t)=>localStorage.setItem(e,t),e.getItem=e=>localStorage.getItem(e),e.removeItem=e=>localStorage.removeItem(e),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(),e.nf=(e,t,r)=>{let n=e<0,i=(e=Math.abs(e)).toFixed(r).split(".");i[0]=i[0].padStart(t,"0");let a=i.join(".");return n&&(a="-"+a),a},e.shuffle=(t,r)=>{r||(t=[...t]);for(let r=t.length-1;r>0;r--){let n=Math.floor(e.random()*(r+1));[t[r],t[n]]=[t[n],t[r]]}return t}},Q5.CSV={},Q5.CSV.parse=(e,t=",",r="\n")=>{if(!e.length)return[];let n=[],i=e.split(r),a=i[0].split(t).map((e=>e.replaceAll('"',"")));for(let e=1;e<i.length;e++){let r={},o=i[e].split(t);a.forEach(((e,t)=>r[e]=JSON.parse(o[t]))),n.push(r)}return n},Q5.modules.vector=e=>{e.Vector=Q5.Vector,e.createVector=(t,r,n)=>new e.Vector(t,r,n,e)},Q5.Vector=class{constructor(e,t,r,n){this.x=e||0,this.y=t||0,this.z=r||0,this._isVector=!0,this._$=n||window,this._useCache=!1,this._mag=0,this._magCached=!1,this._direction=0,this._directionCached=!1}set(e,t,r){return this.x=e?.x||e||0,this.y=e?.y||t||0,this.z=e?.z||r||0,this}copy(){return new Q5.Vector(this.x,this.y,this.z)}_arg2v(e,t,r){return void 0!==e?.x?e:void 0!==t?{x:e,y:t,z:r||0}:{x:e,y:e,z:e}}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}_calcMag(){const e=this.x,t=this.y,r=this.z;this._mag=Math.sqrt(e*e+t*t+r*r),this._magCached=this._useCache}mag(){return this._magCached||this._calcMag(),this._mag}magSq(){if(this._magCached)return this._mag*this._mag;const e=this.x,t=this.y,r=this.z;return e*e+t*t+r*r}setMag(e){this._magCached||this._calcMag();let t=this._mag;if(0==t){const t=this.direction();this.x=e*this._$.cos(t),this.y=e*this._$.sin(t)}else{let r=e/t;this.x*=r,this.y*=r,this.z*=r}return this._mag=e,this._magCached=this._useCache,this}direction(){if(!this._directionCached){const e=this.x,t=this.y;(e||t)&&(this._direction=this._$.atan2(this.y,this.x)),this._directionCached=this._useCache}return this._direction}setDirection(e){let t=this.mag();return t&&(this.x=t*this._$.cos(e),this.y=t*this._$.sin(e)),this._direction=e,this._directionCached=this._useCache,this}heading(){return this.direction()}setHeading(e){return this.setDirection(e)}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,r=this.y-e.y,n=this.z-e.z;return Math.sqrt(t*t+r*r+n*n)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,r=this.z*e.x-this.x*e.z,n=this.x*e.y-this.y*e.x;return this.x=t,this.y=r,this.z=n,this}normalize(){this._magCached||this._calcMag();let e=this._mag;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._mag=1,this._magCached=this._useCache,this}limit(e){this._magCached||this._calcMag();let t=this._mag;if(t>e){let r=e/t;this.x*=r,this.y*=r,this.z*=r,this._mag=e,this._magCached=this._useCache}return this}rotate(e){let t=this._$.cos(e),r=this._$.sin(e),n=this.x*t-this.y*r,i=this.x*r+this.y*t;return this.x=n,this.y=i,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=e.at(-1);if(0==t)return this;let r=this._arg2v(...e.slice(0,-1));return this.x+=(r.x-this.x)*t,this.y+=(r.y-this.y)*t,this.z+=(r.z-this.z)*t,this}slerp(){let e=[...arguments],t=e.at(-1);if(0==t)return this;let r=this._arg2v(...e.slice(0,-1));if(1==t)return this.set(r);let n=this.mag(),i=r.mag();if(0==n||0==i)return this.mult(1-t).add(r.mult(t));let a=Q5.Vector.cross(this,r),o=a.mag(),s=Math.atan2(o,this.dot(r));if(o>0)a.div(o);else{if(s<this._$.HALF_PI)return this.mult(1-t).add(r.mult(t));0==this.z&&0==r.z?a.set(0,0,1):0!=this.x?a.set(this.y,-this.x,0).normalize():a.set(1,0,0)}let l=a.cross(this),d=1-t+t*i/n,c=d*Math.cos(t*s),h=d*Math.sin(t*s);return this.x=this.x*c+l.x*h,this.y=this.y*c+l.y*h,this.z=this.z*c+l.z*h,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._mag=t,this._magCached=this._useCache,this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this.z=0,this}fromAngles(e,t,r){void 0===r&&(r=1),this._mag=r,this._magCached=this._useCache;const n=this._$.cos(t),i=this._$.sin(t),a=this._$.cos(e),o=this._$.sin(e);return this.x=r*o*i,this.y=-r*a,this.z=r*o*n,this}random2D(){return this._mag=1,this._magCached=this._useCache,this.fromAngle(Math.random()*Math.PI*2)}random3D(){return this._mag=1,this._magCached=this._useCache,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,r)=>e.equals(t,r),Q5.Vector.lerp=(e,t,r)=>e.copy().lerp(t,r),Q5.Vector.slerp=(e,t,r)=>e.copy().slerp(t,r),Q5.Vector.limit=(e,t)=>e.copy().limit(t),Q5.Vector.direction=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),Q5.Vector.reflect=(e,t)=>e.copy().reflect(t),Q5.Vector.random2D=()=>(new Q5.Vector).random2D(),Q5.Vector.random3D=()=>(new Q5.Vector).random3D(),Q5.Vector.fromAngle=(e,t)=>(new Q5.Vector).fromAngle(e,t),Q5.Vector.fromAngles=(e,t,r)=>(new Q5.Vector).fromAngles(e,t,r),Q5.renderers.webgpu={},Q5.renderers.webgpu.canvas=(e,t)=>{const r=e.canvas;e.colorMode&&e.colorMode("rgb",1),e._baseShaderCode="\nstruct Q5 {\n\twidth: f32,\n\theight: f32,\n\thalfWidth: f32,\n\thalfHeight: f32,\n\tpixelDensity: f32,\n\tframeCount: f32,\n\ttime: f32,\n\tdeltaTime: f32,\n\tmouseX: f32,\n\tmouseY: f32,\n\tmouseIsPressed: f32,\n\tkeyCode: f32,\n\tkeyIsPressed: f32\n}",e._g=e.createGraphics(1,1,"c2d"),e._g.colorMode&&e._g.colorMode(e.RGB,1);let n,i,a,o,s,l,d,c,h,u,f=2,p=12,g=0,m=0;e._pipelineConfigs=[],e._pipelines=[],e._buffers=[];let x=[],_=new Float32Array(1e6);_.set([0,0,0,0,0,0,0,1,1,1,1,1]);let v=Q5.device.createBindGroupLayout({label:"mainLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}}]});e._bindGroupLayouts=[v];let b=Q5.device.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),y=()=>{let t=[e.canvas.width,e.canvas.height],r="bgra8unorm";a=Q5.device.createTexture({size:t,sampleCount:4,format:r,usage:GPUTextureUsage.RENDER_ATTACHMENT}).createView();let n=GPUTextureUsage.COPY_SRC|GPUTextureUsage.COPY_DST|GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT;e._frameA=s=Q5.device.createTexture({label:"frameA",size:t,format:r,usage:n}),e._frameB=o=Q5.device.createTexture({label:"frameB",size:t,format:r,usage:n}),e._frameShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex: u32\n}\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) texCoord: vec2f\n}\n\nconst ndc = array(vec2f(-1,-1), vec2f(1,-1), vec2f(-1,1), vec2f(1,1));\nconst quad = array(vec2f(0,1), vec2f(1,1), vec2f(0,0), vec2f(1,0));\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var samp: sampler;\n@group(0) @binding(2) var tex: texture_2d<f32>;\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tvar f: FragParams;\n\tf.position = vec4f(ndc[v.vertexIndex], 0.0, 1.0);\n\tf.texCoord = quad[v.vertexIndex];\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams ) -> @location(0) vec4f {\n\treturn textureSample(tex, samp, f.texCoord);\n}";let i=Q5.device.createShaderModule({label:"frameShader",code:e._frameShaderCode});d=Q5.device.createSampler({magFilter:"linear",minFilter:"linear"}),l=Q5.device.createBindGroupLayout({label:"frameLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]});let c=Q5.device.createPipelineLayout({bindGroupLayouts:[l]});e._pipelineConfigs[0]={layout:c,vertex:{module:i,entryPoint:"vertexMain"},fragment:{module:i,entryPoint:"fragMain",targets:[{format:r}]},primitive:{topology:"triangle-strip"},multisample:{count:4}},e._pipelines[0]=Q5.device.createRenderPipeline(e._pipelineConfigs[0]),h=Q5.device.createBindGroup({layout:l,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:d},{binding:2,resource:o.createView()}]}),u=Q5.device.createBindGroup({layout:l,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:d},{binding:2,resource:s.createView()}]})};e._createCanvas=(n,i,a)=>(t.ctx=t.drawingContext=r.getContext("webgpu"),a.format??=navigator.gpu.getPreferredCanvasFormat(),a.device??=Q5.device,a.alpha&&(a.alphaMode="premultiplied"),e.ctx.configure(a),y(),r),e._resizeCanvas=(t,r)=>{e._setCanvasSize(t,r),y()};let w=!0,S="rgb",C=1;if(e.colorMode){let t=e.colorMode;e.colorMode=function(){t(...arguments),S=e._colorMode,w="rgb"==S,C=e._colorFormat}}const Q=(t,r,n,i)=>{if(!1===w||void 0===r&&!t._isColor&&"number"!=typeof t?!1!==w&&"string"!=typeof t&&Array.isArray(t)?[t,r,n,i]=t:t=e.color(t,r,n,i):void 0===n&&(i=r??C,r=n=t),i??=C,t._isColor){let e=t;w?({r:t,g:r,b:n,a:i}=e):(i=e.a,e=null!=e.c?Q5.OKLCHtoRGB(e.l,e.c,e.h):null!=e.l?Q5.HSLtoRGB(e.h,e.s,e.l):Q5.HSLtoRGB(...Q5.HSBtoHSL(e.h,e.s,e.b)),[t,r,n]=e)}255===C&&(t/=255,r/=255,n/=255,i/=255);let a=_,o=p;a[o++]=t,a[o++]=r,a[o++]=n,a[o++]=i,p=o,f++};let M=!0,P=!0,E=!1,I=!1,R=1,A=2,T=2,k=1,O=1,G=.5,D=.25,B=.5;e.fill=(e,t,r,n)=>{Q(e,t,r,n),M=E=!0,A=f},e.stroke=(e,t,r,n)=>{Q(e,t,r,n),P=I=!0,R=f},e.tint=(e,t,r,n)=>{Q(e,t,r,n),T=f},e.opacity=e=>k=e,e.noFill=()=>M=!1,e.noStroke=()=>P=!1,e.noTint=()=>T=2,e.strokeWeight=e=>{if(void 0===e)return O;e?(e=Math.abs(e),O=e,G=e/2,D=e/4,B=G*W):P=!1},e._getStrokeWeight=()=>[O,G,D,B],e._setStrokeWeight=e=>{[O,G,D,B]=e},e._getFillIdx=()=>A,e._setFillIdx=e=>A=e,e._doFill=()=>M=!0,e._getStrokeIdx=()=>R,e._setStrokeIdx=e=>R=e,e._doStroke=()=>P=!0;const L=e._isGraphics?1e3:Q5.MAX_TRANSFORMS,F=16*L*4,z=new Float32Array(16*L);let U,N=[],V=[],H=0,q=!1;N.push([1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1]),z.set(N[0]),e.translate=(e,t)=>{if(!e&&!t)return;let r=U;r[12]+=e*r[0]+t*r[4],r[13]+=e*r[1]+t*r[5],q=!0},e.rotate=e.rotateZ=(t,r)=>{if(!t)return;let n,i;void 0===r?(e._angleMode&&(t*=e._DEGTORAD),n=Math.cos(t),i=Math.sin(t)):(n=t,i=r);let a=U,o=a[0],s=a[1],l=a[4],d=a[5];1!=o||s||l||1!=d?(a[0]=o*n+s*i,a[1]=s*n-o*i,a[4]=l*n+d*i,a[5]=d*n-l*i):(a[0]=n,a[1]=-i,a[4]=i,a[5]=n),q=!0};let W=1;e.scale=(e=1,t,r=1)=>{t??=e,W=Math.max(Math.abs(e),Math.abs(t)),B=G*W;let n=U;n[0]*=e,n[1]*=e,n[2]*=e,n[3]*=e,n[4]*=t,n[5]*=t,n[6]*=t,n[7]*=t,n[8]*=r,n[9]*=r,n[10]*=r,n[11]*=r,q=!0},e.shearX=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),n=U,i=n[0],a=n[1],o=n[4],s=n[5];n[4]=o+i*r,n[5]=s+a*r,q=!0},e.shearY=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),n=U,i=n[0],a=n[1],o=n[4],s=n[5];n[0]=i+o*r,n[1]=a+s*r,q=!0},e.applyMatrix=(...e)=>{let t;if(t=1==e.length?e[0]:e,t.length<=6){t=[t[0],t[1],0,t[2],t[3],0,t[4]||0,t[5]||0,1]}if(t.length<=9)t=[t[0],t[1],0,t[2],t[3],t[4],0,t[5],0,0,1,0,t[6],t[7],0,t[8]];else if(16!=t.length)throw new Error("Matrix must be a 3x3 or 4x4 array.");U=t.slice(),q=!0};const $=()=>{z.set(U,16*N.length),H=N.length,N.push(U.slice()),q=!1};let j=[];e.pushMatrix=()=>{q&&$(),V.push(H),j.push(W)},e.popMatrix=()=>{if(!V.length)return console.warn("Matrix index stack is empty!");let e=V.pop();U=N[e].slice(),H=e,q=!1,W=j.pop(),B=G*W},e.resetMatrix=()=>{U=N[0].slice(),H=0,W=1,B=G},e.resetMatrix();let X=[];e.pushStyles=()=>{X.push([A,R,O,G,W,B,M,P,E,I,k,T,Et,It,Rt,mt,Fe,Ke,w,S,C,e.Color])},e.popStyles=()=>{let t=X.pop();[A,R,O,G,W,B,M,P,E,I,k,T,Et,It,Rt,mt,Fe,Ke,w,S,C]=t,e._colorFormat=C,e._colorMode=S,e.Color=t.at(-1)},e.push=()=>{e.pushMatrix(),e.pushStyles()},e.pop=()=>{e.popMatrix(),e.popStyles()};let Y=[0,0,0,0];const J=(e,t,r,n,i)=>{let a,o,s,l;if(i&&"corner"!=i)if("center"==i){let i=r/2,d=n/2;a=e-i,o=e+i,s=t-d,l=t+d}else a=e,o=r,s=t,l=n;else a=e,o=e+r,s=t,l=t+n;return Y[0]=a,Y[1]=o,Y[2]=s,Y[3]=l,Y};let K=["zero","one","src-alpha","one-minus-src-alpha","dst","dst-alpha","one-minus-dst-alpha","one-minus-src"],Z=["add","subtract","reverse-subtract","min","max"];const ee={"source-over":[2,3,0,2,3,0],"destination-over":[6,1,0,6,1,0],"source-in":[5,0,0,5,0,0],"destination-in":[0,2,0,0,2,0],"source-out":[6,0,0,6,0,0],"destination-out":[0,3,0,0,3,0],"source-atop":[5,3,0,5,3,0],"destination-atop":[6,2,0,6,2,0],lighter:[1,1,0,1,1,0],darken:[1,1,3,3,5,0],lighten:[1,1,4,3,5,0],replace:[1,0,0,1,0,0]};let te=Object.keys(ee);e.blendConfigs={};for(const[t,r]of Object.entries(ee))e.blendConfigs[t]={color:{srcFactor:K[r[0]],dstFactor:K[r[1]],operation:Z[r[2]]},alpha:{srcFactor:K[r[3]],dstFactor:K[r[4]],operation:Z[r[5]]}};let re,ne,ie,ae,oe,se,le,de,ce,he,ue="source-over";e.blendMode=e=>{if(e==ue)return;ue=e;let t=te.indexOf(e);-1!=t?x.push(0,t):console.error(`Blend mode "${e}" not supported in q5.js WebGPU.`)},e.clear=()=>{re=!0},e.background=(t,n,i,a)=>{if(t.canvas){e.push(),e.resetMatrix();let n=t;mt="corner",e.image(n,-r.hw,-r.hh,r.w,r.h),e.pop()}else{Q(t,n,i,a);let e=-r.hw,o=r.hw,s=-r.hh,l=r.hh;Pe(e,s,o,s,o,l,e,l,f,0)}},e._beginRender=()=>{const t=o;o=s,s=t;const r=h;h=u,u=r,n=Q5.device.createCommandEncoder(),e._pass=i=n.beginRenderPass({label:"q5-webgpu",colorAttachments:[{view:a,resolveTarget:o.createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]}),c=u,re||(i.setPipeline(e._pipelines[g]),i.setBindGroup(0,c),i.draw(4)),re=!1},e._render=()=>{let t=16*N.length*4;(!ne||ne.size<t)&&(ne&&ne.destroy(),ne=Q5.device.createBuffer({size:Math.min(2*t,F),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ne,0,z.subarray(0,16*N.length));let r=4*p;(!ie||ie.size<r)&&(ie&&ie.destroy(),ie=Q5.device.createBuffer({size:2*r,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ie,0,_.subarray(0,p)),e._uniforms[0]=e.width,e._uniforms[1]=e.height,e._uniforms[2]=e.halfWidth,e._uniforms[3]=e.halfHeight,e._uniforms[4]=e._pixelDensity,e._uniforms[5]=e.frameCount,e._uniforms[6]=performance.now(),e._uniforms[7]=e.deltaTime,e._uniforms[8]=e.mouseX,e._uniforms[9]=e.mouseY,e._uniforms[10]=e.mouseIsPressed?1:0,e._uniforms[11]=e.keyCode,e._uniforms[12]=e.keyIsPressed?1:0,Q5.device.queue.writeBuffer(b,0,e._uniforms),de&&ce===ne&&he===ie||(de=Q5.device.createBindGroup({layout:v,entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:{buffer:ne}},{binding:2,resource:{buffer:ie}}]}),ce=ne,he=ie),i.setBindGroup(0,de),e._pass.setPipeline(e._pipelines[1]);let n=4*me;if((!ae||ae.size<n)&&(ae&&ae.destroy(),ae=Q5.device.createBuffer({size:2*n,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(ae,0,ge.subarray(0,me)),e._pass.setVertexBuffer(0,ae),ot){e._pass.setPipeline(e._pipelines[2]);let t=4*ot;(!oe||oe.size<t)&&(oe&&oe.destroy(),oe=Q5.device.createBuffer({size:2*t,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(oe,0,at.subarray(0,ot)),e._pass.setVertexBuffer(1,oe),pt&&(e._pass.setPipeline(e._pipelines[3]),e._pass.setVertexBuffer(1,oe))}if(Lt.length){let t=0;for(let e of Lt)Ut.set(e,t),t+=e.length;let r=4*t;(!se||se.size<r)&&(se&&se.destroy(),se=Q5.device.createBuffer({size:2*r,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(se,0,Ut.buffer,0,r);let n=0;for(let e of Ft)Nt.set(e,n),n+=e.length;let i=4*n;(!le||le.size<i)&&(le&&le.destroy(),le=Q5.device.createBuffer({label:"textBuffer",size:2*i,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),Q5.device.queue.writeBuffer(le,0,Nt.buffer,0,i),e._textBindGroup=Q5.device.createBindGroup({label:"textBindGroup",layout:bt,entries:[{binding:0,resource:{buffer:se}},{binding:1,resource:{buffer:le}}]})}Q5.device.queue.writeBuffer(De,0,Oe.buffer,Oe.byteOffset,4*Ge),Q5.device.queue.writeBuffer(Xe,0,$e.buffer,$e.byteOffset,4*je);let a=0,o=0,s=0,l=0,d=0,c=-1;for(let t=0;t<x.length;t+=2){let r=x[t+1];if(x[t]!=c){if(0==x[t]){let t=te[r];for(let r=1;r<e._pipelines.length;r++)e._pipelineConfigs[r].fragment.targets[0].blend=e.blendConfigs[t],e._pipelines[r]=Q5.device.createRenderPipeline(e._pipelineConfigs[r]);continue}c=x[t],i.setPipeline(e._pipelines[c]),5==c?(i.setIndexBuffer(Ae,"uint16"),i.setBindGroup(1,Be)):6==c&&(i.setIndexBuffer(He,"uint16"),i.setBindGroup(1,Ye))}if(6==c)i.drawIndexed(18,r,0,0,d),d+=r;else if(5==c)i.drawIndexed(6,r,0,0,l),l+=r;else if(4==c||c>=4e3){let n=x[t+2];i.setBindGroup(1,Mt[n].bindGroup),i.setBindGroup(2,e._textBindGroup),i.draw(4,r,0,s),s+=r,t++}else 2==c||3==c||c>=2e3?(i.setBindGroup(1,e._textureBindGroups[r]),i.draw(4,1,o),o+=4):(i.draw(r,1,a),a+=r)}},e._finishRender=()=>{i.end(),i=n.beginRenderPass({colorAttachments:[{view:a,resolveTarget:e.ctx.getCurrentTexture().createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]}),c=h,i.setPipeline(e._pipelines[m]),i.setBindGroup(0,c),i.draw(4),i.end(),Q5.device.queue.submit([n.finish()]),e._pass=i=n=null,x.length=0,f=2,p=12,N.length=1,V.length=0,e._texture=o,me=0,ot=0,pt>0&&(e._textureBindGroups.length=ft),pt=0,Lt.length=0,Ft.length=0,Ge=0,je=0,Q5.device.queue.onSubmittedWorkDone().then((()=>{for(let t of e._buffers)t.destroy();e._buffers=[]}))};let fe=1;e._shapesShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex : u32,\n\t@location(0) pos: vec2f,\n\t@location(1) colorIndex: f32,\n\t@location(2) matrixIndex: f32\n}\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) color: vec4f\n}\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tvar vert = transformVertex(v.pos, v.matrixIndex);\n\n\tvar f: FragParams;\n\tf.position = vert;\n\tf.color = colors[i32(v.colorIndex)];\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\treturn f.color;\n}\n";let pe=Q5.device.createShaderModule({label:"shapesShader",code:e._shapesShaderCode}),ge=new Float32Array(e._isGraphics?1e3:1e7),me=0;const xe=2*Math.PI;Math.PI;let _e=Q5.device.createPipelineLayout({label:"shapesPipelineLayout",bindGroupLayouts:e._bindGroupLayouts});e._pipelineConfigs[1]={label:"shapesPipeline",layout:_e,vertex:{module:pe,entryPoint:"vertexMain",buffers:[{arrayStride:16,attributes:[{format:"float32x2",offset:0,shaderLocation:0},{format:"float32",offset:8,shaderLocation:1},{format:"float32",offset:12,shaderLocation:2}]}]},fragment:{module:pe,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[1]=Q5.device.createRenderPipeline(e._pipelineConfigs[1]);const ve=(e,t,r,n)=>{let i=ge,a=me;i[a++]=e,i[a++]=t,i[a++]=r,i[a++]=n,me=a};let be="round",ye="round";e.strokeCap=e=>be=e,e.strokeJoin=e=>ye=e,e.lineMode=()=>{be="square",ye="none"};let we=20;e.curveDetail=e=>we=e;let Se,Ce=20;e.bezierDetail=e=>Ce=e;let Qe=[],Me=[];function Pe(e,t,r,n,i,a,o,s,l,d){ve(e,t,l,d),ve(r,n,l,d),ve(o,s,l,d),ve(i,a,l,d),x.push(fe,4)}e.beginShape=()=>{Se=0,Qe=[],Me=[]},e.vertex=(e,t)=>{q&&$(),Qe.push(e,t,A,H),Se++},e.curveVertex=(e,t)=>{q&&$(),Me.push({x:e,y:t})},e.bezierVertex=function(e,t,r,n,i,a){if(0===Se)throw new Error("Shape needs a vertex()");q&&$();let o,s,l=4*(Se-1),d=Qe[l],c=Qe[l+1],h=1/Ce,u=4==arguments.length;u&&(i=r,a=n);let f=1+h;for(let l=h;l<=f;l+=h){let h=l*l,f=1-l,p=f*f;if(u)o=p*d+2*f*l*e+h*i,s=p*c+2*f*l*t+h*a;else{let u=h*l,g=p*f;o=g*d+3*p*l*e+3*f*h*r+u*i,s=g*c+3*p*l*t+3*f*h*n+u*a}Qe.push(o,s,A,H),Se++}},e.quadraticVertex=(t,r,n,i)=>e.bezierVertex(t,r,n,i),e.endShape=t=>{if(Me.length>0){let e=[...Me];if(e.length<4)for(;e.length<4;)e.unshift(e[0]),e.push(e[e.length-1]);let t=1/we;for(let r=0;r<e.length-3;r++){let n=e[r],i=e[r+1],a=e[r+2],o=e[r+3];for(let e=0;e<=1;e+=t){let t=e*e,r=t*e,s=.5*(2*i.x+(-n.x+a.x)*e+(2*n.x-5*i.x+4*a.x-o.x)*t+(-n.x+3*i.x-3*a.x+o.x)*r),l=.5*(2*i.y+(-n.y+a.y)*e+(2*n.y-5*i.y+4*a.y-o.y)*t+(-n.y+3*i.y-3*a.y+o.y)*r);Qe.push(s,l,A,H),Se++}}}if(Se){if(1==Se)return e.point(Qe[0],Qe[1]);if(2==Se)return e.line(Qe[0],Qe[1],Qe[4],Qe[5]);if(t){let e=0,t=4*(Se-1),r=Qe[e],n=Qe[e+1],i=Qe[t],a=Qe[t+1];r===i&&n===a||(Qe.push(r,n,Qe[e+2],Qe[e+3]),Se++)}if(M)if(5==Se)ve(Qe[0],Qe[1],Qe[2],Qe[3]),ve(Qe[4],Qe[5],Qe[6],Qe[7]),ve(Qe[12],Qe[13],Qe[14],Qe[15]),ve(Qe[8],Qe[9],Qe[10],Qe[11]),x.push(fe,4);else{for(let e=1;e<Se-1;e++){let t=0,r=4*e,n=4*(e+1);ve(Qe[t],Qe[t+1],Qe[t+2],Qe[t+3]),ve(Qe[r],Qe[r+1],Qe[r+2],Qe[r+3]),ve(Qe[n],Qe[n+1],Qe[n+2],Qe[n+3])}x.push(fe,3*(Se-2))}if(P){for(let t=0;t<Se-1;t++){let r=4*t,n=4*(t+1);e.line(Qe[r],Qe[r+1],Qe[n],Qe[n+1])}let r=4*(Se-1),n=0;t&&e.line(Qe[r],Qe[r+1],Qe[n],Qe[n+1])}Se=0,Qe=[],Me=[]}},e.curve=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(n,i),e.curveVertex(a,o),e.curveVertex(s,l),e.endShape()},e.bezier=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(n,i,a,o,s,l),e.endShape()},e.triangle=(t,r,n,i,a,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.endShape(!0)},e.quad=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.vertex(s,l),e.endShape(!0)},e.plane=(e,t,r,n)=>{n??=r;let[i,a,o,s]=J(e,t,r,n,"center");q&&$(),Pe(i,o,a,o,a,s,i,s,A,H)};let Ee=5;e._rectShaderCode=e._baseShaderCode+"\nstruct Rect {\n\tcenter: vec2f,\n\textents: vec2f,\n\troundedRadius: f32,\n\tstrokeWeight: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tmatrixIndex: f32,\n\tpadding0: f32, // can't use vec3f for alignment\n\tpadding1: vec2f,\n\tpadding2: vec4f\n};\n\nstruct VertexParams {\n\t@builtin(vertex_index) vertIndex: u32,\n\t@builtin(instance_index) instIndex: u32\n};\n\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) local: vec2f,\n\t@location(1) extents: vec2f,\n\t@location(2) roundedRadius: f32,\n\t@location(3) strokeWeight: f32,\n\t@location(4) fill: vec4f,\n\t@location(5) stroke: vec4f,\n\t@location(6) blend: vec4f\n};\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var<storage, read> rects: array<Rect>;\n\nconst quad = array(\n\tvec2f(-1.0, -1.0),\n\tvec2f( 1.0, -1.0),\n\tvec2f(-1.0, 1.0),\n\tvec2f( 1.0, 1.0)\n);\nconst transparent = vec4f(0.0);\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tlet rect = rects[v.instIndex];\n\n\tlet halfStrokeSize = vec2f(rect.strokeWeight * 0.5);\n\tlet quadSize = rect.extents + halfStrokeSize;\n\tlet pos = (quad[v.vertIndex] * quadSize) + rect.center;\n\n\tlet local = pos - rect.center;\n\n\tvar f: FragParams;\n\tf.position = transformVertex(pos, rect.matrixIndex);\n\n\tf.local = local;\n\tf.extents = rect.extents;\n\tf.roundedRadius = rect.roundedRadius;\n\tf.strokeWeight = rect.strokeWeight;\n\n\tlet fill = colors[i32(rect.fillIndex)];\n\tlet stroke = colors[i32(rect.strokeIndex)];\n\tf.fill = fill;\n\tf.stroke = stroke;\n\n\t// Source-over blend: stroke over fill (pre-multiplied alpha)\n\tif (fill.a != 0.0 && stroke.a != 1.0) {\n\t\tlet outAlpha = stroke.a + fill.a * (1.0 - stroke.a);\n\t\tlet outColor = stroke.rgb * stroke.a + fill.rgb * fill.a * (1.0 - stroke.a);\n\t\tf.blend = vec4f(outColor / max(outAlpha, 1e-5), outAlpha);\n\t}\n\treturn f;\n}\n\nfn sdRoundRect(p: vec2f, extents: vec2f, radius: f32) -> f32 {\n\tlet q = abs(p) - extents + vec2f(radius);\n\treturn length(max(q, vec2f(0.0))) - radius + min(max(q.x, q.y), 0.0);\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\tlet dist = select(\n\t\tmax(abs(f.local.x) - f.extents.x, abs(f.local.y) - f.extents.y), // sharp\n\t\tsdRoundRect(f.local, f.extents, f.roundedRadius), // rounded\n\t\tf.roundedRadius > 0.0\n\t);\n\n\t// fill only\n\tif (f.fill.a != 0.0 && f.strokeWeight == 0.0) {\n\t\tif (dist <= 0.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\treturn transparent;\n\t}\n\n\tlet halfStroke = f.strokeWeight * 0.5;\n\tlet inner = dist + halfStroke;\n\n\tif (f.fill.a != 0.0) {\n\t\tif (inner <= 0.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\tif (dist <= 0.0 && f.stroke.a != 1.0) {\n\t\t\treturn f.blend;\n\t\t}\n\t}\n\n\tlet outer = dist - halfStroke;\n\n\tif (outer <= 0.0 && inner >= 0.0) {\n\t\treturn f.stroke;\n\t}\n\n\treturn transparent;\n}\n\t";let Ie=Q5.device.createShaderModule({label:"rectShader",code:e._rectShaderCode}),Re=new Uint16Array([0,1,2,2,1,3]),Ae=Q5.device.createBuffer({size:Re.byteLength,usage:GPUBufferUsage.INDEX,mappedAtCreation:!0});new Uint16Array(Ae.getMappedRange()).set(Re),Ae.unmap();let Te=Q5.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),ke=Q5.device.createPipelineLayout({label:"rectPipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,Te]});e._pipelineConfigs[5]={label:"rectPipeline",layout:ke,vertex:{module:Ie,entryPoint:"vertexMain",buffers:[]},fragment:{module:Ie,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-list"},multisample:{count:4}},e._pipelines[5]=Q5.device.createRenderPipeline(e._pipelineConfigs[5]);let Oe=new Float32Array(16*Q5.MAX_RECTS),Ge=0,De=Q5.device.createBuffer({size:Oe.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),Be=Q5.device.createBindGroup({layout:Te,entries:[{binding:0,resource:{buffer:De}}]});function Le(e,t,r,n,i,a,o){let s=Oe,l=Ge;s[l]=e,s[l+1]=t,s[l+2]=r,s[l+3]=n,s[l+4]=i,s[l+5]=a,s[l+6]=o,s[l+7]=R,s[l+8]=H,Ge+=16,x.push(Ee,1)}let Fe="corner";e.rectMode=e=>Fe=e,e._getRectMode=()=>Fe;let ze=[0,0,0,0];function Ue(t,r,n,i,a,o,s){let l=n-t,d=i-r,c=Math.hypot(l,d);if(0===c)return;let h=Math.atan2(d,l),u=(t+n)/2,f=(r+i)/2;e._angleMode&&(h*=e._RADTODEG),e.pushMatrix(),e.translate(u,f),e.rotate(h),q&&$(),Le(0,0,c/2+a,a,a,o,s),e.popMatrix()}e.rect=(e,t,r,n,i=0)=>{let a,o;q&&$(),[e,t,a,o]=function(e,t,r,n){let i=r/2,a=n/2;return"center"!=Fe&&("corner"==Fe?(e+=i,t+=a):"radius"==Fe?(i=r,a=n):"corners"==Fe&&(i=Math.abs((r-e)/2),a=Math.abs((n-t)/2),e=(e+r)/2,t=(t+n)/2)),ze[0]=e,ze[1]=t,ze[2]=i,ze[3]=a,ze}(e,t,r,n),Le(e,t,a,o,i,P?O:0,M?A:0)},e.square=(t,r,n,i)=>e.rect(t,r,n,n,i),e.capsule=(e,t,r,n,i)=>{Ue(e,t,r,n,i,P?O:0,M?A:0)},e.line=(e,t,r,n)=>{P&&Ue(e,t,r,n,D,G,0)};e._ellipseShaderCode=e._baseShaderCode+"\nstruct Ellipse {\n\tcenter: vec2f,\n\tsize: vec2f,\n\tstartAngle: f32,\n\tendAngle: f32,\n\tstrokeWeight: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tmatrixIndex: f32,\n\tpadding0: vec2f,\n\tpadding1: vec4f\n};\n\nstruct VertexParams {\n\t@builtin(vertex_index) vertIndex: u32,\n\t@builtin(instance_index) instIndex: u32\n};\n\nstruct FragParams {\n\t@builtin(position) position: vec4f,\n\t@location(0) outerEdge: vec2f,\n\t@location(1) fillEdge: vec2f,\n\t@location(2) innerEdge: vec2f,\n\t@location(3) strokeWeight: f32,\n\t@location(4) fill: vec4f,\n\t@location(5) stroke: vec4f,\n\t@location(6) blend: vec4f\n};\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var<storage, read> ellipses: array<Ellipse>;\n\nconst PI = 3.141592653589793;\nconst segments = 6.0;\nconst expansion = 1.0 / cos(PI / segments);\nconst antiAlias = 0.015625; // 1/64\nconst transparent = vec4f(0.0);\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\n@vertex\nfn vertexMain(v: VertexParams) -> FragParams {\n\tlet ellipse = ellipses[v.instIndex];\n\tvar pos = ellipse.center;\n\tvar local = vec2f(0.0);\n\tlet start = ellipse.startAngle;\n\tlet end = ellipse.endAngle;\n\tlet arc = end - start;\n\tlet halfStrokeSize = vec2f(ellipse.strokeWeight * 0.5);\n\n\tlet fanSize = (ellipse.size + halfStrokeSize) * expansion;\n\n\tif (v.vertIndex != 0) {\n\t\tlet theta = start + (f32(v.vertIndex - 1) / segments) * arc;\n\t\tlocal = vec2f(cos(theta), sin(theta));\n\t\tpos = ellipse.center + local * fanSize;\n\t}\n\n\tlet dist = pos - ellipse.center;\n\n\tvar f: FragParams;\n\tf.position = transformVertex(pos, ellipse.matrixIndex);\n\tf.outerEdge = dist / (ellipse.size + halfStrokeSize);\n\tf.fillEdge = dist / ellipse.size;\n\tf.innerEdge = dist / (ellipse.size - halfStrokeSize);\n\tf.strokeWeight = ellipse.strokeWeight;\n\n\tlet fill = colors[i32(ellipse.fillIndex)];\n\tlet stroke = colors[i32(ellipse.strokeIndex)];\n\tf.fill = fill;\n\tf.stroke = stroke;\n\n\t// Source-over blend: stroke over fill (pre-multiplied alpha)\n\tif (fill.a != 0.0 && stroke.a != 1.0) {\n\t\tlet outAlpha = stroke.a + fill.a * (1.0 - stroke.a);\n\t\tlet outColor = stroke.rgb * stroke.a + fill.rgb * fill.a * (1.0 - stroke.a);\n\t\tf.blend = vec4f(outColor / max(outAlpha, 1e-5), outAlpha);\n\t}\n\treturn f;\n}\n\n@fragment\nfn fragMain(f: FragParams) -> @location(0) vec4f {\n\tlet fillEdge = length(f.fillEdge);\n\n\t// disable AA for very thin strokes\n\tlet aa = select(antiAlias, 0.0, f.strokeWeight <= 1.0);\n\n\tif (f.fill.a != 0.0 && f.strokeWeight == 0.0) {\n\t\tif (fillEdge > 1.0) {\n\t\t\treturn transparent;\n\t\t}\n\t\tlet fillAlpha = 1.0 - smoothstep(1.0 - aa, 1.0, fillEdge);\n\t\treturn vec4f(f.fill.rgb, f.fill.a * fillAlpha);\n\t}\n\n\tlet innerEdge = length(f.innerEdge);\n\t\n\tif (f.fill.a != 0.0 && fillEdge < 1.0) {\n\t\tif (innerEdge < 1.0) {\n\t\t\treturn f.fill;\n\t\t}\n\t\tlet tInner = smoothstep(1.0, 1.0 + aa, innerEdge);\n\t\tlet tOuter = smoothstep(1.0 - aa, 1.0, fillEdge);\n\t\tif (f.stroke.a != 1.0) {\n\t\t\tlet fillBlend = mix(f.fill, f.blend, tInner);\n\t\t\treturn mix(fillBlend, f.stroke, tOuter);\n\t\t} else {\n\t\t\tlet fillBlend = mix(f.fill, f.stroke, tInner);\n\t\t\treturn mix(fillBlend, f.stroke, tOuter);\n\t\t}\n\t}\n\t\n\tif (innerEdge < 1.0) {\n\t\treturn transparent;\n\t}\n\n\tlet outerEdge = length(f.outerEdge);\n\tlet outerAlpha = 1.0 - smoothstep(1.0 - aa, 1.0, outerEdge);\n\tlet innerAlpha = smoothstep(1.0, 1.0 + aa, innerEdge);\n\tlet strokeAlpha = innerAlpha * outerAlpha;\n\treturn vec4f(f.stroke.rgb, f.stroke.a * strokeAlpha);\n}\n\t\t";let Ne=Q5.device.createShaderModule({label:"ellipseShader",code:e._ellipseShaderCode}),Ve=new Uint16Array([0,1,2,0,2,3,0,3,4,0,4,5,0,5,6,0,6,7]),He=Q5.device.createBuffer({size:Ve.byteLength,usage:GPUBufferUsage.INDEX,mappedAtCreation:!0});new Uint16Array(He.getMappedRange()).set(Ve),He.unmap();let qe=Q5.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),We=Q5.device.createPipelineLayout({label:"ellipsePipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,qe]});e._pipelineConfigs[6]={label:"ellipsePipeline",layout:We,vertex:{module:Ne,entryPoint:"vertexMain",buffers:[]},fragment:{module:Ne,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-list"},multisample:{count:4}},e._pipelines[6]=Q5.device.createRenderPipeline(e._pipelineConfigs[6]);let $e=new Float32Array(16*Q5.MAX_ELLIPSES),je=0,Xe=Q5.device.createBuffer({size:$e.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),Ye=Q5.device.createBindGroup({layout:qe,entries:[{binding:0,resource:{buffer:Xe}}]});function Je(e,t,r,n,i,a,o,s){let l=$e,d=je;l[d]=e,l[d+1]=t,l[d+2]=r,l[d+3]=n,l[d+4]=i,l[d+5]=a,l[d+6]=o,l[d+7]=s?A:0,l[d+8]=R,l[d+9]=H,je+=16,x.push(6,1)}let Ke="center";e.ellipseMode=e=>Ke=e,e._getEllipseMode=()=>Ke;let Ze=[0,0,0,0];function et(e,t,r,n){let i,a;return n??=r,"center"==Ke?(i=r/2,a=n/2):"radius"==Ke?(i=r,a=n):"corner"==Ke?(e+=r/2,t+=n/2,i=r/2,a=n/2):"corners"==Ke&&(i=r-(e=(e+r)/2),a=n-(t=(t+n)/2)),Ze[0]=e,Ze[1]=t,Ze[2]=i,Ze[3]=a,Ze}e.ellipse=(e,t,r,n)=>{let i,a;[e,t,i,a]=et(e,t,r,n),q&&$(),Je(e,t,i,a,0,xe,P?O:0,M)},e.circle=(t,r,n)=>e.ellipse(t,r,n,n),e.arc=(t,r,n,i,a,o)=>{if(a===o)return e.ellipse(t,r,n,i);if(e._angleMode&&(a=e.radians(a),o=e.radians(o)),(a%=xe)<0&&(a+=xe),(o%=xe)<0&&(o+=xe),a>o&&(o+=xe),a==o)return e.ellipse(t,r,n,i);let s,l;[t,r,s,l]=et(t,r,n,i),q&&$(),Je(t,r,s,l,a,o,P?O:0,M)},e.point=(e,t)=>{q&&$(),B<=.5?Le(e,t,G,G,0,O,0):Je(e,t,G,G,0,xe,O,0)};let tt=2,rt=3;e._imageShaderCode=e._baseShaderCode+"\n\tstruct VertexParams {\n\t\t@builtin(vertex_index) vertexIndex : u32,\n\t\t@location(0) pos: vec2f,\n\t\t@location(1) texCoord: vec2f,\n\t\t@location(2) tintIndex: f32,\n\t\t@location(3) matrixIndex: f32,\n\t\t@location(4) imageAlpha: f32\n\t}\n\tstruct FragParams {\n\t\t@builtin(position) position: vec4f,\n\t\t@location(0) texCoord: vec2f,\n\t\t@location(1) tintColor: vec4f,\n\t\t@location(2) imageAlpha: f32\n\t}\n\t\n\t@group(0) @binding(0) var<uniform> q: Q5;\n\t@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n\t@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\t\n\t@group(1) @binding(0) var samp: sampler;\n\t@group(1) @binding(1) var tex: texture_2d<f32>;\n\t\n\tfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\t\tvar vert = vec4f(pos, 0f, 1f);\n\t\tvert = transforms[i32(matrixIndex)] * vert;\n\t\tvert.x /= q.halfWidth;\n\t\tvert.y /= q.halfHeight;\n\t\treturn vert;\n\t}\n\t\n\tfn applyTint(texColor: vec4f, tintColor: vec4f) -> vec4f {\n\t\t// apply the tint color to the sampled texture color at full strength\n\t\tlet tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);\n\t\t// mix in the tint using the tint alpha as the blend strength\n\t\treturn mix(texColor, tinted, tintColor.a);\n\t}\n\t\n\t@vertex\n\tfn vertexMain(v: VertexParams) -> FragParams {\n\t\tvar vert = transformVertex(v.pos, v.matrixIndex);\n\t\n\t\tvar f: FragParams;\n\t\tf.position = vert;\n\t\tf.texCoord = v.texCoord;\n\t\tf.tintColor = colors[i32(v.tintIndex)];\n\t\tf.imageAlpha = v.imageAlpha;\n\t\treturn f;\n\t}\n\t\n\t@fragment\n\tfn fragMain(f: FragParams) -> @location(0) vec4f {\n\t\tvar texColor = textureSample(tex, samp, f.texCoord);\n\t\ttexColor.a *= f.imageAlpha;\n\t\treturn applyTint(texColor, f.tintColor);\n\t}\n\t";let nt=Q5.device.createShaderModule({label:"imageShader",code:e._imageShaderCode});e._videoShaderCode=e._imageShaderCode.replace("texture_2d<f32>","texture_external").replace("textureSample","textureSampleBaseClampToEdge");let it=Q5.device.createShaderModule({label:"videoShader",code:e._videoShaderCode}),at=new Float32Array(e._isGraphics?1e3:1e7),ot=0,st={arrayStride:28,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"},{shaderLocation:2,offset:16,format:"float32"},{shaderLocation:3,offset:20,format:"float32"},{shaderLocation:4,offset:24,format:"float32"}]},lt=Q5.device.createBindGroupLayout({label:"textureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]}),dt=Q5.device.createBindGroupLayout({label:"videoTextureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,externalTexture:{}}]}),ct=Q5.device.createPipelineLayout({label:"imagePipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,lt]}),ht=Q5.device.createPipelineLayout({label:"videoPipelineLayout",bindGroupLayouts:[...e._bindGroupLayouts,dt]});e._pipelineConfigs[2]={label:"imagePipeline",layout:ct,vertex:{module:nt,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},st]},fragment:{module:nt,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[2]=Q5.device.createRenderPipeline(e._pipelineConfigs[2]),e._pipelineConfigs[3]={label:"videoPipeline",layout:ht,vertex:{module:it,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},st]},fragment:{module:it,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[3]=Q5.device.createRenderPipeline(e._pipelineConfigs[3]),e._textureBindGroups=[],r&&(r.convertToBlob=async t=>{let r=e._drawStack?.length;r&&(e._render(),e._finishRender());let n=e._texture;r&&e._beginRender();let i=n.width,a=n.height,o=256*Math.ceil(4*i/256),s=Q5.device.createBuffer({size:o*a,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),l=Q5.device.createCommandEncoder();l.copyTextureToBuffer({texture:n},{buffer:s,bytesPerRow:o,rowsPerImage:a},{width:i,height:a}),Q5.device.queue.submit([l.finish()]),await s.mapAsync(GPUMapMode.READ);let d=new Uint8Array(s.getMappedRange()),c=new Uint8Array(i*a*4);for(let e=0;e<a;e++){const t=e*o,r=e*i*4;for(let e=0;e<i;e++){const n=t+4*e,i=r+4*e;c[i+0]=d[n+2],c[i+1]=d[n+1],c[i+2]=d[n+0],c[i+3]=d[n+3]}}s.unmap();let h=e.canvas.colorSpace;c=new Uint8ClampedArray(c.buffer),c=new ImageData(c,i,a,{colorSpace:h});let u=new OffscreenCanvas(i,a);return u.getContext("2d",{colorSpace:h}).putImageData(c,0,0),e._buffers.push(s),await u.convertToBlob(t)});let ut=t=>{e._imageSampler=Q5.device.createSampler({magFilter:t,minFilter:t})};e.smooth=()=>ut("linear"),e.noSmooth=()=>ut("nearest"),e.smooth();let ft=0,pt=0;e._addTexture=(t,r)=>{let n=t.canvas||t;if(!r){if(t._texture)return;let i=[n.width,n.height,1];r=Q5.device.createTexture({size:i,format:"bgra8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_SRC|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),Q5.device.queue.copyExternalImageToTexture({source:n},{texture:r,colorSpace:e.canvas.colorSpace},i)}r.index=ft+pt,t._texture=r,e._textureBindGroups[r.index]=Q5.device.createBindGroup({label:t.src||r.label||"canvas",layout:lt,entries:[{binding:0,resource:e._imageSampler},{binding:1,resource:r.createView()}]}),ft++},e.loadImage=(t,r)=>e._g.loadImage(t,(t=>{e._makeDrawable(t),r&&r(t)})),e._makeDrawable=t=>{e._addTexture(t),t._owner=e},e.createImage=(t,r,n)=>{let i=e._g.createImage(t,r,n);return e._makeDrawable(i),i.modified=!0,i};let gt=e.createGraphics;e.createGraphics=(t,r,n={})=>{if(!Q5.experimental)throw new Error("createGraphics is disabled by default in q5 WebGPU. See issue https://github.com/q5js/q5.js/issues/104 for details.");"string"==typeof n&&(n={renderer:n}),n.renderer??="c2d";let i=gt(t,r,n);return i.canvas.webgpu?(e._addTexture(i,i._frameA),e._addTexture(i,i._frameB),i._beginRender()):(e._makeDrawable(i),i.modified=!0),i};let mt="corner";e.imageMode=e=>mt=e,e._getImageMode=()=>mt,e._uniforms=new Float32Array(13);const xt=(e,t,r,n,i,a,o)=>{let s=at,l=ot;s[l++]=e,s[l++]=t,s[l++]=r,s[l++]=n,s[l++]=i,s[l++]=a,s[l++]=o,ot=l};e.image=(t,r=0,n=0,i,a,o=0,s=0,l,d)=>{if(!t)return;let c;if(null==t._texture){if(c="VIDEO"==t.tagName,!t.width||c&&!t.currentTime)return;t.flipped&&e.scale(-1,1)}q&&$();let h=t.canvas||t,u=h.width,f=h.height,p=t._pixelDensity||1,g=t._isGraphics&&t._drawStack?.length;g&&(t._render(),t._finishRender()),t.modified&&(Q5.device.queue.copyExternalImageToTexture({source:h},{texture:t._texture,colorSpace:e.canvas.colorSpace},[u,f,1]),t.frameCount++,t.modified=!1),i??=t.defaultWidth||t.videoWidth,a??=t.defaultHeight||t.videoHeight,l??=u,d??=f,o*=p,s*=p;let[m,_,v,b]=J(r,n,i,a,mt),y=o/u,w=s/f,S=(o+l)/u,C=(s+d)/f,Q=H,M=T,P=k;if(xt(m,v,y,w,M,Q,P),xt(_,v,S,w,M,Q,P),xt(m,b,y,C,M,Q,P),xt(_,b,S,C,M,Q,P),c){let r=Q5.device.importExternalTexture({source:t});e._textureBindGroups.push(Q5.device.createBindGroup({layout:dt,entries:[{binding:0,resource:e._imageSampler},{binding:1,resource:r}]})),x.push(rt,e._textureBindGroups.length-1),t.flipped&&e.scale(-1,1)}else x.push(tt,t._texture.index),g&&(t.resetMatrix(),t._beginRender(),t.frameCount++)};let _t=4;e._textShaderCode=e._baseShaderCode+"\nstruct VertexParams {\n\t@builtin(vertex_index) vertexIndex : u32,\n\t@builtin(instance_index) instanceIndex : u32\n}\nstruct FragParams {\n\t@builtin(position) position : vec4f,\n\t@location(0) texCoord : vec2f,\n\t@location(1) fillColor : vec4f,\n\t@location(2) strokeColor : vec4f,\n\t@location(3) strokeWeight : f32,\n\t@location(4) edge : f32\n}\nstruct Char {\n\ttexOffset: vec2f,\n\ttexExtent: vec2f,\n\tsize: vec2f,\n\toffset: vec2f,\n}\nstruct Text {\n\tpos: vec2f,\n\tscale: f32,\n\tmatrixIndex: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32,\n\tstrokeWeight: f32,\n\tedge: f32\n}\n\n@group(0) @binding(0) var<uniform> q: Q5;\n@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;\n@group(0) @binding(2) var<storage> colors : array<vec4f>;\n\n@group(1) @binding(0) var fontTexture: texture_2d<f32>;\n@group(1) @binding(1) var fontSampler: sampler;\n@group(1) @binding(2) var<storage> fontChars: array<Char>;\n\n@group(2) @binding(0) var<storage> textChars: array<vec4f>;\n@group(2) @binding(1) var<storage> textMetadata: array<Text>;\n\nconst quad = array(vec2f(0, 1), vec2f(1, 1), vec2f(0, 0), vec2f(1, 0));\nconst uvs = array(vec2f(0, 1), vec2f(1, 1), vec2f(0, 0), vec2f(1, 0));\n\nfn calcPos(i: u32, char: vec4f, fontChar: Char, text: Text) -> vec2f {\n\treturn ((quad[i] * fontChar.size + char.xy + fontChar.offset) *\n\t\ttext.scale) + text.pos;\n}\n\nfn calcUV(i: u32, fontChar: Char) -> vec2f {\n\treturn uvs[i] * fontChar.texExtent + fontChar.texOffset;\n}\n\nfn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(matrixIndex)] * vert;\n\tvert.x /= q.halfWidth;\n\tvert.y /= q.halfHeight;\n\treturn vert;\n}\n\nfn calcDist(texCoord: vec2f, edgeWidth: f32) -> f32 {\n\tlet c = textureSample(fontTexture, fontSampler, texCoord);\n\tlet sigDist = max(min(c.r, c.g), min(max(c.r, c.g), c.b)) - edgeWidth;\n\n\tlet pxRange = 4.0;\n\tlet sz = vec2f(textureDimensions(fontTexture, 0));\n\tlet dx = sz.x * length(vec2f(dpdxFine(texCoord.x), dpdyFine(texCoord.x)));\n\tlet dy = sz.y * length(vec2f(dpdxFine(texCoord.y), dpdyFine(texCoord.y)));\n\tlet toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);\n\treturn sigDist * toPixels;\n}\n\n@vertex\nfn vertexMain(v : VertexParams) -> FragParams {\n\tlet char = textChars[v.instanceIndex];\n\tlet text = textMetadata[i32(char.w)];\n\tlet fontChar = fontChars[i32(char.z)];\n\tlet pos = calcPos(v.vertexIndex, char, fontChar, text);\n\n\tvar vert = transformVertex(pos, text.matrixIndex);\n\n\tvar f : FragParams;\n\tf.position = vert;\n\tf.texCoord = calcUV(v.vertexIndex, fontChar);\n\tf.fillColor = colors[i32(text.fillIndex)];\n\tf.strokeColor = colors[i32(text.strokeIndex)];\n\tf.strokeWeight = text.strokeWeight;\n\tf.edge = text.edge;\n\treturn f;\n}\n\n@fragment\nfn fragMain(f : FragParams) -> @location(0) vec4f {\n\tlet edge = f.edge;\n\tlet dist = calcDist(f.texCoord, edge);\n\n\tif (f.strokeWeight == 0.0) {\n\t\tlet fillAlpha = smoothstep(-edge, edge, dist);\n\t\tlet color = vec4f(f.fillColor.rgb, f.fillColor.a * fillAlpha);\n\t\tif (color.a < 0.01) {\n\t\t\tdiscard;\n\t\t}\n\t\treturn color;\n\t}\n\n\tlet halfStroke = f.strokeWeight / 2.0;\n\tlet fillAlpha = smoothstep(-edge, edge, dist - halfStroke);\n\tlet strokeAlpha = smoothstep(-edge, edge, dist + halfStroke);\n\tvar color = mix(f.strokeColor, f.fillColor, fillAlpha);\n\tcolor = vec4f(color.rgb, color.a * strokeAlpha);\n\tif (color.a < 0.01) {\n\t\tdiscard;\n\t}\n\treturn color;\n}\n";let vt=Q5.device.createShaderModule({label:"textShader",code:e._textShaderCode}),bt=Q5.device.createBindGroupLayout({label:"textBindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage"}}]}),yt=Q5.device.createSampler({minFilter:"linear",magFilter:"linear",mipmapFilter:"linear",maxAnisotropy:16}),wt=Q5.device.createBindGroupLayout({label:"fontBindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:2,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),St=Q5.device.createPipelineLayout({bindGroupLayouts:[...e._bindGroupLayouts,wt,bt]});e._pipelineConfigs[4]={label:"textPipeline",layout:St,vertex:{module:vt,entryPoint:"vertexMain"},fragment:{module:vt,entryPoint:"fragMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs["source-over"]}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[4]=Q5.device.createRenderPipeline(e._pipelineConfigs[4]);class Ct{constructor(e,t,r,n){this.bindGroup=e,this.lineHeight=t,this.chars=r,this.kernings=n;let i=Object.values(r);this.charCount=i.length,this.defaultChar=i[0]}getChar(e){return this.chars[e]??this.defaultChar}getXAdvance(e,t=-1){let r=this.getChar(e);if(t>=0){let n=this.kernings.get(e);if(n)return r.xadvance+(n.get(t)??0)}return r.xadvance}}let Qt,Mt=[],Pt={};e.loadFont=(t="sans-serif",r)=>{if(Qt=!0,t.startsWith("https://fonts.googleapis.com/css"))return e._g.loadFont(t,r);let n=t.slice(t.lastIndexOf(".")+1);if(t==n){let e=t;Pt[e]=null,t=`https://q5js.org/fonts/${e}-msdf.json`,0!=Q5.online&&navigator.onLine||(t=`/node_modules/q5/builtinFonts/${e}-msdf.json`),n="json"}if("json"!=n)return e._g.loadFont(t,r);let i=t.slice(t.lastIndexOf("/")+1,t.lastIndexOf("-")),a={family:i};return a.promise=async function(t,r,n){let i,a,o=t.substring(0,t.lastIndexOf("-"));try{[i,a]=await Promise.all([fetch(t).then((e=>{if(404==e.status)throw new Error("404");return e.json()})),fetch(o+".png").then((e=>e.blob())).then((e=>createImageBitmap(e)))])}catch(e){return console.error("Error loading font:",e),""}let s=[a.width,a.height,1],l=Q5.device.createTexture({label:`MSDF ${r}`,size:s,format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:a},{texture:l},s),"string"==typeof i.chars&&(i.chars=Q5.CSV.parse(i.chars," "),i.kernings=Q5.CSV.parse(i.kernings," "));let d=i.chars.length,c=Q5.device.createBuffer({size:32*d,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),h=new Float32Array(c.getMappedRange()),u=1/i.common.scaleW,f=1/i.common.scaleH,p={},g=0;for(let[e,t]of i.chars.entries())p[t.id]=t,p[t.id].charIndex=e,h[g]=t.x*u,h[g+1]=t.y*f,h[g+2]=t.width*u,h[g+3]=t.height*f,h[g+4]=t.width,h[g+5]=t.height,h[g+6]=t.xoffset,h[g+7]=t.yoffset,g+=8;c.unmap();let m=Q5.device.createBindGroup({label:"fontBindGroup",layout:wt,entries:[{binding:0,resource:l.createView()},{binding:1,resource:yt},{binding:2,resource:{buffer:c}}]}),x=new Map;if(i.kernings)for(let e of i.kernings){let t=x.get(e.first);t||(t=new Map,x.set(e.first,t)),t.set(e.second,e.amount)}let _=new Ct(m,i.common.lineHeight,p,x);return _.index=Mt.length,Mt.push(_),Pt[r]=_,e._font=_,n&&n(r),{family:r}}(t,i,(()=>{delete a.then,a._usedAwait&&(a={family:i}),r&&r(a)})),e._loaders.push(a.promise),a.then=(e,t)=>(a._usedAwait=!0,a.promise.then(e,t)),a};let Et=18,It="left",Rt="alphabetic",At=!1,Tt=22.5,kt=4.5,Ot=1.25,Gt=["serif","sans-serif","monospace","cursive","fantasy","system-ui"];e.textFont=t=>{if(!t)return e._font;Qt=!0,"string"!=typeof t&&(t=t.family);let r=Pt[t];r?e._font=r:(Gt[t]||void 0===r)&&e._g.textFont(t)},e.textSize=e=>{if(null==e)return Et;Et=e,At||(Tt=e*Ot,kt=Tt-e)};let Dt={thin:100,extralight:200,light:300,normal:400,regular:400,medium:500,semibold:600,bold:700,bolder:800,extrabold:800,black:900,heavy:900},Bt=.5;e.textWeight=t=>{if(!t)return e._textWeight;if("string"==typeof t&&!(t=Dt[t.toLowerCase().replace(/[ _-]/g,"")]))throw new Error(`Invalid font weight: ${t}`);Bt=.6875-375e-6*t},e.textLeading=t=>{e._font.lineHeight=Tt=t,kt=Tt-Et,Ot=Tt/Et,At=!0},e.textAlign=(e,t)=>{It=e,t&&(Rt=t)};let Lt=[],Ft=[],zt=new Array(100),Ut=new Float32Array(4*Q5.MAX_CHARS),Nt=new Float32Array(8*Q5.MAX_TEXTS),Vt=(e,t,r)=>{let n=0,i=0,a=0,o=0,s=0,l=zt,d=t.charCodeAt(0);for(let c=0;c<t.length;++c){let h=d;switch(d=c<t.length-1?t.charCodeAt(c+1):-1,h){case 10:l.push(i),o++,n=Math.max(n,i),i=0,a-=e.lineHeight*Ot;break;case 13:break;case 32:i+=e.getXAdvance(h);break;case 9:i+=2*e.getXAdvance(h);break;default:r&&r(i,a,o,e.getChar(h)),i+=e.getXAdvance(h,d),s++}}l[o]=i,n=Math.max(n,i);let c=o+1;return{width:n,height:c*e.lineHeight*Ot,lineWidths:l,lineCount:c,printedCharCount:s}};e.text=(t,r,n,i,a)=>{if(Et<1)return;let o=typeof t;if("string"!=o)"object"==o?t=t.toString():t+="";else if(!t.length)return;if(!e._font){Qt||e.loadFont();let o=e.createTextImage(t,i,a);return e.textImage(o,r,n)}if(t.length>i){let e=[],r=0;for(;r<t.length&&e.length<a;){let n=r+i;if(n>=t.length){e.push(t.slice(r));break}let a=t.lastIndexOf(" ",n);(-1==a||a<r)&&(a=n),e.push(t.slice(r,a)),r=a+1}t=e.join("\n")}let s;for(let e=0;e<t.length;e++){switch(t[e]){case"\n":s=!0;case"\r":case"\t":case" ":0}}let l,d=[],c=It,h=Rt,u=Ft.length,f=0;if("left"!=c||s){l=Vt(e._font,t);let r=0;"alphabetic"==h?n-=Et:"center"==h?r=.5*l.height:"bottom"==h&&(r=l.height),Vt(e._font,t,((e,t,n,i)=>{let a=0;"center"==c?a=-.5*l.width- -.5*(l.width-l.lineWidths[n]):"right"==c&&(a=-l.lineWidths[n]),d[f]=e+a,d[f+1]=-(t+r),d[f+2]=i.charIndex,d[f+3]=u,f+=4}))}else l=Vt(e._font,t,((e,t,r,n)=>{d[f]=e,d[f+1]=-t,d[f+2]=n.charIndex,d[f+3]=u,f+=4})),"alphabetic"==h?n-=Et:"center"==h?n-=.5*Et:"bottom"==h&&(n-=Tt);Lt.push(d);let p=[];q&&$(),p[0]=r,p[1]=n,p[2]=Et/42,p[3]=H,p[4]=M&&E?A:1,p[5]=R,p[6]=P&&I?O:0,p[7]=Bt,Ft.push(p),x.push(_t,l.printedCharCount,e._font.index)},e.textWidth=t=>e._font?Vt(e._font,t).width:0,e.createTextImage=(t,r,n)=>{if(e._g.textSize(Et),M&&E){let t=4*A;e._g.fill(_.slice(t,t+4))}if(P&&I){let t=4*R;e._g.stroke(_.slice(t,t+4))}let i=e._g.createTextImage(t,r,n);return e._makeDrawable(i),i},e.textImage=(t,r,n)=>{"string"==typeof t&&(t=e.createTextImage(t));let i=mt;mt="corner";let a=It;"center"==a?r-=t.canvas.hw:"right"==a&&(r-=t.width);let o=Rt;"alphabetic"==o?n-=t._leading:"center"==o?n-=t._middle:"bottom"==o?n-=t._bottom:"top"==o&&(n-=t._top),e.image(t,r,n),mt=i};let Ht=["frame","shapes","image","video","text"],qt={frame:10,shapes:1e3,image:2e3,video:3e3,text:4e3};e._createShader=(t,r="shapes")=>{t=t.trim();let n=e["_"+r+"ShaderCode"],i=n.indexOf("@vertex"),a=n.indexOf("@fragment");t=t.includes("@fragment")?t.includes("@vertex")?n.slice(0,i)+t:n.slice(0,a)+t:n.slice(0,i)+t+"\n\n"+n.slice(a);let o=Q5.device.createShaderModule({label:r+"Shader",code:t});o.type=r;let s=Ht.indexOf(r),l=Object.assign({},e._pipelineConfigs[s]);l.vertex.module=l.fragment.module=o;let d=qt[r];return e._pipelines[d]=Q5.device.createRenderPipeline(l),e._pipelines[d].shader=o,o.pipelineIndex=d,qt[r]++,o},e.createShader=e.createShapesShader=e._createShader,e.createFrameShader=t=>e._createShader(t,"frame"),e.createImageShader=t=>e._createShader(t,"image"),e.createVideoShader=t=>e._createShader(t,"video"),e.createTextShader=t=>e._createShader(t,"text"),e.shader=e=>{let t=e.type,r=e.pipelineIndex;"frame"==t?e.applyBeforeDraw?g=r:m=r:"shapes"==t?fe=r:"image"==t?tt=r:"video"==t?rt=r:"text"==t&&(_t=r)},e.resetShader=e.resetShapesShader=()=>fe=1,e.resetFrameShader=()=>g=m=0,e.resetImageShader=()=>tt=2,e.resetVideoShader=()=>rt=3,e.resetTextShader=()=>_t=4,e.resetShaders=()=>{g=m=0,fe=1,tt=2,rt=3,_t=4}},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.MAX_TRANSFORMS=1e7,Q5.MAX_RECTS=200200,Q5.MAX_ELLIPSES=200200,Q5.MAX_CHARS=1e5,Q5.MAX_TEXTS=1e4,Q5.initWebGPU=async()=>{if(!navigator.gpu)return console.warn("q5 WebGPU not supported on this browser! Use Google Chrome or Edge."),!1;if(!Q5.requestedGPU){Q5.requestedGPU=!0;let e=await navigator.gpu.requestAdapter();if(!e)return console.warn("q5 WebGPU could not start! No appropriate GPUAdapter found, Vulkan may need to be enabled."),!1;Q5.device=await e.requestDevice(),Q5.device.lost.then((e=>{console.error("WebGPU crashed!"),console.error(e)}))}return!0},Q5.WebGPU=async function(e,t){let r;return e&&"global"!=e||(Q5._hasGlobal=!0),await Q5.initWebGPU()||(r=new Q5(e,t,"webgpu-fallback")),r=new Q5(e,t,"webgpu"),await r.ready,r};