From 563e264983138ea03835eff15c4a8f7200c64299 Mon Sep 17 00:00:00 2001 From: Quinton Ashley Date: Sat, 7 Dec 2024 11:28:54 -0500 Subject: [PATCH] 1.15.0 --- LICENSING.md | 46 ------- README.md | 12 +- docs/-_Contros.html | 14 +- docs/-_KeyBoard.html | 6 +- docs/-_Mouse.html | 20 +-- docs/-_SpriteMouse.html | 12 +- docs/-_Touch.html | 6 +- docs/Ani.html | 46 +++---- docs/Anis.html | 6 +- docs/Camera.html | 24 ++-- docs/Canvas.html | 10 +- docs/Contro.html | 34 ++--- docs/DistanceJoint.html | 6 +- docs/GlueJoint.html | 6 +- docs/Group.html | 157 +++++++++++++++++------ docs/GroupSprite.html | 6 +- docs/HingeJoint.html | 14 +- docs/InputDevice.html | 20 +-- docs/Joint.html | 32 ++--- docs/P5Play.html | 8 +- docs/RopeJoint.html | 8 +- docs/SliderJoint.html | 14 +- docs/Sprite.html | 260 +++++++++++++++++--------------------- docs/Subgroup.html | 6 +- docs/Tiles.html | 6 +- docs/WheelJoint.html | 8 +- docs/World.html | 28 ++-- docs/global.html | 68 +++++----- docs/index.html | 4 +- docs/p5play.js.html | 225 ++++++++++++++++++--------------- lang/en/en.json | 2 +- lang/en/learn/joints.md | 16 +++ lang/es/es.json | 2 +- lang/es/learn/joints.html | 54 +++++++- lang/es/learn/joints.md | 16 +++ lang/ja/ja.json | 9 +- lang/ja/learn/joints.html | 51 +++++++- lang/ja/learn/joints.md | 16 +++ learn/joints.html | 53 +++++++- package.json | 2 +- pro/PRO_LICENSE.md | 125 ++++++++++++++---- teach/EDU_LICENSE.md | 121 ++++++++++++++---- v3/p5play.d.ts | 37 ++++-- v3/p5play.js | 74 ++++++----- v3/p5play.min.js | 8 +- v3/q5.js | 23 ++-- v3/q5.min.js | 2 +- 47 files changed, 1053 insertions(+), 670 deletions(-) delete mode 100644 LICENSING.md diff --git a/LICENSING.md b/LICENSING.md deleted file mode 100644 index dc2a099a..00000000 --- a/LICENSING.md +++ /dev/null @@ -1,46 +0,0 @@ -# LICENSING - -> This file contains a non-legally binding summary of p5play's licenses. - -Typical use of p5play by educators and commercial game developers requires a proprietary license. See the [Pro][] and [Teach][] pages for more information. - -## p5play v3 library - -p5play is open source and multi-licensed. - -Anyone can use p5play for free under the terms of the [AGPLv3][], a copyleft open source license. - -The AGPLv3 requires that any works which incorporate p5play for non-personal use must be made publicly open source. - -Technically, you can use p5play commercially on some platforms without a proprietary license. - -Yet, under the terms of the AGPL, open source commercial use would require that you make potential consumers aware of their ability to download readable (non-obfuscated) source code at or before the point of sale, as a free alternative to making any purchases. Note that your source code must include any requisite material, not limited to program files. - -Closed app stores, like the Apple App Store or Google Play Store, do not allow developers to publish apps that contain software licensed under the AGPL. - -Non-profit organizations not paying for one of p5play's proprietary licenses must also comply with the AGPL, including non-profit schools that charge tuition. https://www.beavandenberk.com/ip/copyright-tm/nonprofits-and-the-fair-use-defense/ - -## p5play.org website - -The example code and non-logo images shown in the mini editors on the p5play website are public domain works licensed under the CC0 license. You are free to copy and modify them for use in your own projects without attribution. - -Everything else in this repository, "p5play-web", is owned by Quinton Ashley, all rights reserved. This content and its source is publicly available, but you may not copy the content to a greater extent than fair use allows. - -The interactive textbook, [_Learn p5play_][], is free for personal use only. - -## p5play logos - -The current p5play logos were created by Quinton Ashley, all rights reserved. The p5play logo can be found in the "assets" folder of this p5play-web repository in a file named "logo.svg". You are encouraged to reference it and/or the "made_with_p5play" images in your own projects to show that your project was made with p5play, but you may not imply that your project is endorsed by Quinton Ashley. - -## p5.play v1 and v2 - -p5.play v1 and v2 are licensed under the LGPLv2 license, a more permissive copyleft license than the AGPLv3. p5play v3 only re-implements portions of the p5.play API, so it doesn't qualify as a derivative of previous versions. APIs are not copyrightable in the United States, as decided by the Supreme Court in the Oracle v Google case. - -## Contributions to p5play - -Currently, if you'd like to make contributions to the p5play library, you can do so on a volunteer basis. Significant contributions to the p5play library will be credited on the home page of p5play.org and in the p5play changelog on GitHub, unless you'd prefer to make contributions anonymously. - -[AGPLv3]: https://github.com/quinton-ashley/p5play/blob/main/LICENSE.md -[Pro]: https://p5play.org/pro/ -[Teach]: https://p5play.org/teach/ -[_Learn p5play_]: https://p5play.org/learn/ diff --git a/README.md b/README.md index ec16843b..758a2acc 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,15 @@ dev ## Licensing -See the [LICENSING.md][] file. +p5play software is multi-licensed for use under the p5play Personal License, p5play Educational License, and p5play Professional License. + +Typical use of p5play by educators and commercial game developers requires a proprietary license. See the [Pro][] and [Teach][] pages for more information. + +q5.js is LGPLv3 licensed. The Ace editor is BSD-3-Clause licensed. planck and marked are MIT licensed. + +The example code and non-logo images shown in the mini editors on the p5play website are public domain works licensed under the CC0 license. You are free to copy and modify them for use in your own projects without attribution. + +Everything else in this repository, "p5play-web", is owned by Quinton Ashley, all rights reserved. This content and its source is publicly available, but you may not copy the content to a greater extent than fair use allows. ## Credits @@ -135,3 +143,5 @@ https://www.pexels.com/video/skater-girl-meeting-with-her-friends-5200356/ [p5play project planning page]: https://github.com/users/quinton-ashley/projects/5 [mie]: https://github.com/quinton-ashley/mie [translations]: /lang/instructions.md +[Pro]: https://p5play.org/pro/ +[Teach]: https://p5play.org/teach/ diff --git a/docs/-_Contros.html b/docs/-_Contros.html index eb3031f2..e497cc61 100644 --- a/docs/-_Contros.html +++ b/docs/-_Contros.html @@ -24,7 +24,7 @@
@@ -105,7 +105,7 @@

new _Contros<
Source:
@@ -232,7 +232,7 @@

onConnectSource:
@@ -399,7 +399,7 @@

onDisconn
Source:
@@ -562,7 +562,7 @@

removeSource:
@@ -697,7 +697,7 @@

swapSource:
@@ -834,7 +834,7 @@
Example

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/-_KeyBoard.html b/docs/-_KeyBoard.html index e12f55a9..6508023e 100644 --- a/docs/-_KeyBoard.html +++ b/docs/-_KeyBoard.html @@ -24,7 +24,7 @@
@@ -106,7 +106,7 @@

new _Keyboar
Source:
@@ -190,7 +190,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/-_Mouse.html b/docs/-_Mouse.html index df110921..7409154e 100644 --- a/docs/-_Mouse.html +++ b/docs/-_Mouse.html @@ -24,7 +24,7 @@
@@ -103,7 +103,7 @@

new _MouseSource:
@@ -221,7 +221,7 @@

cursorSource:
@@ -295,7 +295,7 @@

posSource:
@@ -369,7 +369,7 @@

positionSource:
@@ -448,7 +448,7 @@

visibleSource:
@@ -528,7 +528,7 @@

draggedSource:
@@ -684,7 +684,7 @@

draggingSource:
@@ -840,7 +840,7 @@

dragsSource:
@@ -969,7 +969,7 @@
Returns:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/-_SpriteMouse.html b/docs/-_SpriteMouse.html index c23afb84..76d19b8c 100644 --- a/docs/-_SpriteMouse.html +++ b/docs/-_SpriteMouse.html @@ -24,7 +24,7 @@
@@ -103,7 +103,7 @@

new _Spri
Source:
@@ -218,7 +218,7 @@

hoveredSource:
@@ -322,7 +322,7 @@

hoveringSource:
@@ -426,7 +426,7 @@

hoversSource:
@@ -503,7 +503,7 @@
Returns:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/-_Touch.html b/docs/-_Touch.html index 877597ce..fe2e9c1d 100644 --- a/docs/-_Touch.html +++ b/docs/-_Touch.html @@ -24,7 +24,7 @@
@@ -103,7 +103,7 @@

new _TouchSource:
@@ -187,7 +187,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Ani.html b/docs/Ani.html index 8a38f81b..f31e6a1c 100644 --- a/docs/Ani.html +++ b/docs/Ani.html @@ -24,7 +24,7 @@
@@ -115,7 +115,7 @@

new AniSource:
@@ -299,7 +299,7 @@

frameSource:
@@ -380,7 +380,7 @@

frameDelay<
Source:
@@ -454,7 +454,7 @@

frameImage<
Source:
@@ -528,7 +528,7 @@

hSource:
@@ -602,7 +602,7 @@

heightSource:
@@ -676,7 +676,7 @@

lastFrameSource:
@@ -758,7 +758,7 @@

scaleSource:
@@ -835,7 +835,7 @@

wSource:
@@ -909,7 +909,7 @@

widthSource:
@@ -993,7 +993,7 @@

cloneSource:
@@ -1105,7 +1105,7 @@

drawSource:
@@ -1392,7 +1392,7 @@

goToFrameSource:
@@ -1540,7 +1540,7 @@

loopSource:
@@ -1623,7 +1623,7 @@

nextFrameSource:
@@ -1706,7 +1706,7 @@

noLoopSource:
@@ -1789,7 +1789,7 @@

pauseSource:
@@ -1872,7 +1872,7 @@

playSource:
@@ -1968,7 +1968,7 @@

previous
Source:
@@ -2052,7 +2052,7 @@

rewindSource:
@@ -2149,7 +2149,7 @@

stopSource:
@@ -2201,7 +2201,7 @@

stop
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Anis.html b/docs/Anis.html index 4fd32aa3..8e0bb866 100644 --- a/docs/Anis.html +++ b/docs/Anis.html @@ -24,7 +24,7 @@
@@ -113,7 +113,7 @@

new AnisSource:
@@ -186,7 +186,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Camera.html b/docs/Camera.html index 1d88edb3..d96cf648 100644 --- a/docs/Camera.html +++ b/docs/Camera.html @@ -24,7 +24,7 @@
@@ -115,7 +115,7 @@

new CameraSource:
@@ -217,7 +217,7 @@

posSource:
@@ -291,7 +291,7 @@

positionSource:
@@ -365,7 +365,7 @@

xSource:
@@ -439,7 +439,7 @@

ySource:
@@ -522,7 +522,7 @@

zoomSource:
@@ -606,7 +606,7 @@

moveToSource:
@@ -820,7 +820,7 @@

offSource:
@@ -905,7 +905,7 @@

onSource:
@@ -988,7 +988,7 @@

zoomToSource:
@@ -1143,7 +1143,7 @@
Returns:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Canvas.html b/docs/Canvas.html index 2898173f..1b54d329 100644 --- a/docs/Canvas.html +++ b/docs/Canvas.html @@ -24,7 +24,7 @@
@@ -109,7 +109,7 @@

new CanvasSource:
@@ -385,7 +385,7 @@

resizeSource:
@@ -546,7 +546,7 @@

saveSource:
@@ -650,7 +650,7 @@
Parameters:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Contro.html b/docs/Contro.html index fb844576..c59e2076 100644 --- a/docs/Contro.html +++ b/docs/Contro.html @@ -24,7 +24,7 @@
@@ -107,7 +107,7 @@

new ControSource:
@@ -273,7 +273,7 @@

l1Source:
@@ -338,7 +338,7 @@

l2Source:
@@ -403,7 +403,7 @@

l3Source:
@@ -468,7 +468,7 @@

lbSource:
@@ -532,7 +532,7 @@

leftSt
Source:
@@ -596,7 +596,7 @@

lsSource:
@@ -661,7 +661,7 @@

r1Source:
@@ -726,7 +726,7 @@

r2Source:
@@ -791,7 +791,7 @@

r3Source:
@@ -856,7 +856,7 @@

rbSource:
@@ -920,7 +920,7 @@

right
Source:
@@ -984,7 +984,7 @@

rsSource:
@@ -1049,7 +1049,7 @@

zlSource:
@@ -1114,7 +1114,7 @@

zrSource:
@@ -1153,7 +1153,7 @@

zr
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/DistanceJoint.html b/docs/DistanceJoint.html index 074ff894..636ef8cd 100644 --- a/docs/DistanceJoint.html +++ b/docs/DistanceJoint.html @@ -24,7 +24,7 @@
@@ -100,7 +100,7 @@

new Dist
Source:
@@ -262,7 +262,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/GlueJoint.html b/docs/GlueJoint.html index eed9f978..74beb2ce 100644 --- a/docs/GlueJoint.html +++ b/docs/GlueJoint.html @@ -24,7 +24,7 @@
@@ -99,7 +99,7 @@

new GlueJoin
Source:
@@ -261,7 +261,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Group.html b/docs/Group.html index a52372c8..f0858473 100644 --- a/docs/Group.html +++ b/docs/Group.html @@ -24,7 +24,7 @@
@@ -114,7 +114,7 @@

new GroupSource:
@@ -228,7 +228,7 @@

amountSource:
@@ -302,7 +302,7 @@

aniSource:
@@ -376,7 +376,7 @@

animationSource:
@@ -450,7 +450,7 @@

anisSource:
@@ -520,7 +520,7 @@

diameterSource:
@@ -590,7 +590,7 @@

heightSource:
@@ -664,7 +664,7 @@

imageSource:
@@ -738,7 +738,7 @@

imgSource:
@@ -817,7 +817,7 @@

velocitySource:
@@ -887,7 +887,7 @@

widthSource:
@@ -967,7 +967,7 @@

applyForce<
Source:
@@ -1046,7 +1046,7 @@

apply
Source:
@@ -1125,7 +1125,7 @@

applyTorqu
Source:
@@ -1204,7 +1204,7 @@

attractToSource:
@@ -1288,7 +1288,7 @@

collidedSource:
@@ -1494,7 +1494,7 @@

collidesSource:
@@ -1677,7 +1677,7 @@

collidingSource:
@@ -1886,7 +1886,7 @@

cullSource:
@@ -2204,7 +2204,7 @@

drawSource:
@@ -2283,7 +2283,7 @@

moveSource:
@@ -2362,7 +2362,7 @@

moveAwaySource:
@@ -2441,7 +2441,7 @@

moveToSource:
@@ -2520,7 +2520,7 @@

moveToward
Source:
@@ -2604,7 +2604,7 @@

overlapped<
Source:
@@ -2808,7 +2808,7 @@

overlappin
Source:
@@ -3018,7 +3018,7 @@

overlapsSource:
@@ -3199,7 +3199,7 @@

popSource:
@@ -3313,7 +3313,7 @@

pushSource:
@@ -3497,7 +3497,7 @@

removeSource:
@@ -3663,7 +3663,86 @@

removeAllSource:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +
+ + + +

repelFrom()

+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -3746,7 +3825,7 @@

shiftSource:
@@ -3856,7 +3935,7 @@

sizeSource:
@@ -3946,7 +4025,7 @@

spliceSource:
@@ -4132,7 +4211,7 @@

toStringSource:
@@ -4240,7 +4319,7 @@

unshiftSource:
@@ -4351,7 +4430,7 @@

updateSource:
@@ -4403,7 +4482,7 @@

update
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/GroupSprite.html b/docs/GroupSprite.html index 43d07c12..ba44bea7 100644 --- a/docs/GroupSprite.html +++ b/docs/GroupSprite.html @@ -24,7 +24,7 @@
@@ -95,7 +95,7 @@

new GroupS
Source:
@@ -161,7 +161,7 @@

new GroupS
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/HingeJoint.html b/docs/HingeJoint.html index c1bde420..fd91ee1a 100644 --- a/docs/HingeJoint.html +++ b/docs/HingeJoint.html @@ -24,7 +24,7 @@
@@ -102,7 +102,7 @@

new HingeJo
Source:
@@ -298,7 +298,7 @@

angleSource:
@@ -377,7 +377,7 @@

lowerLimit<
Source:
@@ -457,7 +457,7 @@

rangeSource:
@@ -536,7 +536,7 @@

upperLimit<
Source:
@@ -585,7 +585,7 @@

Type:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/InputDevice.html b/docs/InputDevice.html index 39b7d44e..aad3a922 100644 --- a/docs/InputDevice.html +++ b/docs/InputDevice.html @@ -24,7 +24,7 @@
@@ -111,7 +111,7 @@

new InputD
Source:
@@ -215,7 +215,7 @@

heldSource:
@@ -371,7 +371,7 @@

holdingSource:
@@ -527,7 +527,7 @@

holdsSource:
@@ -687,7 +687,7 @@

pressedSource:
@@ -843,7 +843,7 @@

pressesSource:
@@ -999,7 +999,7 @@

pressingSource:
@@ -1155,7 +1155,7 @@

releasedSource:
@@ -1284,7 +1284,7 @@
Returns:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Joint.html b/docs/Joint.html index b28403cf..120d8c3e 100644 --- a/docs/Joint.html +++ b/docs/Joint.html @@ -24,7 +24,7 @@
@@ -108,7 +108,7 @@

new JointSource:
@@ -348,7 +348,7 @@

colli
Source:
@@ -435,7 +435,7 @@

dampingSource:
@@ -509,7 +509,7 @@

drawSource:
@@ -585,7 +585,7 @@

enableMoto
Source:
@@ -665,7 +665,7 @@

maxPowerSource:
@@ -746,7 +746,7 @@

offsetASource:
@@ -827,7 +827,7 @@

offsetBSource:
@@ -907,7 +907,7 @@

powerSource:
@@ -981,7 +981,7 @@

reaction
Source:
@@ -1045,7 +1045,7 @@

reactio
Source:
@@ -1114,7 +1114,7 @@

speedSource:
@@ -1208,7 +1208,7 @@

springines
Source:
@@ -1293,7 +1293,7 @@

removeSource:
@@ -1345,7 +1345,7 @@

remove
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/P5Play.html b/docs/P5Play.html index e02fbba0..0c1ed3ab 100644 --- a/docs/P5Play.html +++ b/docs/P5Play.html @@ -24,7 +24,7 @@
@@ -101,7 +101,7 @@

new P5PlaySource:
@@ -210,7 +210,7 @@

onImageLoa
Source:
@@ -262,7 +262,7 @@

onImageLoa
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/RopeJoint.html b/docs/RopeJoint.html index bb074a4a..429f3a48 100644 --- a/docs/RopeJoint.html +++ b/docs/RopeJoint.html @@ -24,7 +24,7 @@
@@ -102,7 +102,7 @@

new RopeJoin
Source:
@@ -293,7 +293,7 @@

maxLengthSource:
@@ -332,7 +332,7 @@

maxLength
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/SliderJoint.html b/docs/SliderJoint.html index 2f1a50b3..0ec36116 100644 --- a/docs/SliderJoint.html +++ b/docs/SliderJoint.html @@ -24,7 +24,7 @@
@@ -102,7 +102,7 @@

new Slider
Source:
@@ -298,7 +298,7 @@

angleSource:
@@ -378,7 +378,7 @@

lowerLimit<
Source:
@@ -458,7 +458,7 @@

rangeSource:
@@ -538,7 +538,7 @@

upperLimit<
Source:
@@ -587,7 +587,7 @@

Type:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Sprite.html b/docs/Sprite.html index e2e060ec..0852e527 100644 --- a/docs/Sprite.html +++ b/docs/Sprite.html @@ -24,7 +24,7 @@
@@ -118,7 +118,7 @@

new SpriteSource:
@@ -923,7 +923,7 @@

bearingSource:
@@ -1082,7 +1082,7 @@

(readonly) c
Source:
@@ -1327,7 +1327,7 @@

colourSource:
@@ -1401,7 +1401,7 @@

dSource:
@@ -1480,7 +1480,7 @@

debugSource:
@@ -1559,7 +1559,7 @@

densitySource:
@@ -1633,7 +1633,7 @@

diameterSource:
@@ -1712,7 +1712,7 @@

directionSource:
@@ -1791,7 +1791,7 @@

dragSource:
@@ -1880,7 +1880,7 @@

drawSource:
@@ -1969,7 +1969,7 @@

dynamicSource:
@@ -2048,7 +2048,7 @@

fillSource:
@@ -2080,13 +2080,13 @@
Type:
-

fillColor :p5.Color

+

fillColor

- Alias for sprite.color + Deprecated alias for sprite.fill, will be removed in the future.
@@ -2110,7 +2110,7 @@

fillColorDeprecated:
  • Yes
@@ -2118,16 +2118,13 @@

fillColorDefault Value: -
    -
  • random color
  • -
+
Source:
@@ -2140,16 +2137,6 @@

fillColorType:

-
    -
  • - -p5.Color - - -
  • -
- @@ -2202,7 +2189,7 @@

fixtureSource:
@@ -2267,7 +2254,7 @@

fixtureLis
Source:
@@ -2337,7 +2324,7 @@

frictionSource:
@@ -2416,7 +2403,7 @@

gravitySc
Source:
@@ -2490,7 +2477,7 @@

hSource:
@@ -2564,7 +2551,7 @@

halfHeight<
Source:
@@ -2638,7 +2625,7 @@

halfWidthSource:
@@ -2721,7 +2708,7 @@

headingSource:
@@ -2795,7 +2782,7 @@

heightSource:
@@ -2869,7 +2856,7 @@

hhSource:
@@ -2943,7 +2930,7 @@

hwSource:
@@ -3024,7 +3011,7 @@

imageSource:
@@ -3098,7 +3085,7 @@

imgSource:
@@ -3172,7 +3159,7 @@

isMovingSource:
@@ -3252,7 +3239,7 @@

isSuperFas
Source:
@@ -3331,7 +3318,7 @@

kinematicSource:
@@ -3407,7 +3394,7 @@

layerSource:
@@ -3496,7 +3483,7 @@

lifeSource:
@@ -3570,7 +3557,7 @@

massSource:
@@ -3728,7 +3715,7 @@
Properties:
Source:
@@ -3890,7 +3877,7 @@
Properties:
Source:
@@ -3969,7 +3956,7 @@

opacitySource:
@@ -4051,7 +4038,7 @@

pixelPerf
Source:
@@ -4125,7 +4112,7 @@

posSource:
@@ -4199,7 +4186,7 @@

positionSource:
@@ -4273,7 +4260,7 @@

previ
Source:
@@ -4347,7 +4334,7 @@

previ
Source:
@@ -4421,7 +4408,7 @@

rSource:
@@ -4495,7 +4482,7 @@

radiusSource:
@@ -4574,7 +4561,7 @@

removedSource:
@@ -4656,7 +4643,7 @@

rotationSource:
@@ -4735,7 +4722,7 @@

rotationD
Source:
@@ -4814,7 +4801,7 @@

rotationL
Source:
@@ -4893,7 +4880,7 @@

rotation
Source:
@@ -4979,7 +4966,7 @@

scaleSource:
@@ -5064,7 +5051,7 @@

shapeSource:
@@ -5147,7 +5134,7 @@

sleepingSource:
@@ -5229,7 +5216,7 @@

speedSource:
@@ -5308,7 +5295,7 @@

staticSource:
@@ -5389,7 +5376,7 @@

strokeSource:
@@ -5421,13 +5408,13 @@
Type:
-

strokeColor :p5.Color

+

strokeColor

- Alias for sprite.stroke + Deprecated alias for sprite.stroke, will be removed in the future.
@@ -5451,7 +5438,7 @@

strokeColo - +
Deprecated:
  • Yes
@@ -5459,16 +5446,13 @@

strokeColo -
Default Value:
-
    -
  • undefined
  • -
+
Source:
@@ -5481,16 +5465,6 @@

strokeColo -

Type:
-
    -
  • - -p5.Color - - -
  • -
- @@ -5547,7 +5521,7 @@

strokeWei
Source:
@@ -5626,7 +5600,7 @@

textColorSource:
@@ -5705,7 +5679,7 @@

textFillSource:
@@ -5779,7 +5753,7 @@

textSizeSource:
@@ -5859,7 +5833,7 @@

textStroke<
Source:
@@ -5939,7 +5913,7 @@

textS
Source:
@@ -6013,7 +5987,7 @@

tileSource:
@@ -6096,7 +6070,7 @@

tileSizeSource:
@@ -6178,7 +6152,7 @@

tintSource:
@@ -6257,7 +6231,7 @@

tintColorSource:
@@ -6338,7 +6312,7 @@

updateSource:
@@ -6417,7 +6391,7 @@

velSource:
@@ -6496,7 +6470,7 @@

velocitySource:
@@ -6570,7 +6544,7 @@

verticesSource:
@@ -6652,7 +6626,7 @@

visibleSource:
@@ -6726,7 +6700,7 @@

wSource:
@@ -6800,7 +6774,7 @@

widthSource:
@@ -6874,7 +6848,7 @@

xSource:
@@ -6948,7 +6922,7 @@

ySource:
@@ -7038,7 +7012,7 @@

addAniSource:
@@ -7208,7 +7182,7 @@

addAnisSource:
@@ -7589,7 +7563,7 @@

addD
Source:
@@ -7677,7 +7651,7 @@

addImageSource:
@@ -7765,7 +7739,7 @@

addImagesSource:
@@ -8080,7 +8054,7 @@

angleToSource:
@@ -8277,7 +8251,7 @@

angleToFac
Source:
@@ -8495,7 +8469,7 @@

applyForce<
Source:
@@ -8687,7 +8661,7 @@

apply
Source:
@@ -8874,7 +8848,7 @@

applyTorqu
Source:
@@ -9012,7 +8986,7 @@

attractToSource:
@@ -9306,7 +9280,7 @@

(async) chan
Source:
@@ -9469,7 +9443,7 @@

change
Source:
@@ -9632,7 +9606,7 @@

collidedSource:
@@ -9841,7 +9815,7 @@

collidesSource:
@@ -10027,7 +10001,7 @@

collidingSource:
@@ -10238,7 +10212,7 @@

distanceTo<
Source:
@@ -10406,7 +10380,7 @@

moveSource:
@@ -10665,7 +10639,7 @@

moveAwaySource:
@@ -10883,7 +10857,7 @@

moveToSource:
@@ -11128,7 +11102,7 @@

moveToward
Source:
@@ -11347,7 +11321,7 @@

overlapped<
Source:
@@ -11554,7 +11528,7 @@

overlappin
Source:
@@ -11767,7 +11741,7 @@

overlapsSource:
@@ -11959,7 +11933,7 @@

removeSource:
@@ -12215,7 +12189,7 @@

rese
Source:
@@ -12302,7 +12276,7 @@

resetMassSource:
@@ -12396,7 +12370,7 @@

rotateSource:
@@ -12604,7 +12578,7 @@

rotateMinT
Source:
@@ -12795,7 +12769,7 @@

rotateToSource:
@@ -13056,7 +13030,7 @@

rotateTo
Source:
@@ -13279,7 +13253,7 @@

rotatio
Source:
@@ -13521,7 +13495,7 @@

toStringSource:
@@ -13586,7 +13560,7 @@
Returns:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Subgroup.html b/docs/Subgroup.html index 92dc3d94..53ac68de 100644 --- a/docs/Subgroup.html +++ b/docs/Subgroup.html @@ -24,7 +24,7 @@
@@ -95,7 +95,7 @@

new Subgroup<
Source:
@@ -161,7 +161,7 @@

new Subgroup<
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/Tiles.html b/docs/Tiles.html index 18bddd97..2aaf39d6 100644 --- a/docs/Tiles.html +++ b/docs/Tiles.html @@ -24,7 +24,7 @@
@@ -104,7 +104,7 @@

new TilesSource:
@@ -333,7 +333,7 @@

Classes


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/WheelJoint.html b/docs/WheelJoint.html index e7c430bb..b56748c8 100644 --- a/docs/WheelJoint.html +++ b/docs/WheelJoint.html @@ -24,7 +24,7 @@
@@ -102,7 +102,7 @@

new WheelJo
Source:
@@ -300,7 +300,7 @@

angleSource:
@@ -349,7 +349,7 @@
Type:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/World.html b/docs/World.html index d806d4d6..aaa5559d 100644 --- a/docs/World.html +++ b/docs/World.html @@ -24,7 +24,7 @@
@@ -107,7 +107,7 @@

new WorldSource:
@@ -230,7 +230,7 @@

allowSle
Source:
@@ -388,7 +388,7 @@

Properties:
Source:
@@ -463,7 +463,7 @@

realTimeSource:
@@ -543,7 +543,7 @@

timeScaleSource:
@@ -627,7 +627,7 @@

velo
Source:
@@ -712,7 +712,7 @@

getSpriteA
Source:
@@ -952,7 +952,7 @@

getSprite
Source:
@@ -1029,7 +1029,7 @@

Parameters:
- + x coordinate or position object @@ -1253,7 +1253,7 @@

rayCastSource:
@@ -1468,7 +1468,7 @@

rayCastAll<
Source:
@@ -1749,7 +1749,7 @@

stepSource:
@@ -1937,7 +1937,7 @@
Parameters:

- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/global.html b/docs/global.html index e943fefb..8af9405d 100644 --- a/docs/global.html +++ b/docs/global.html @@ -24,7 +24,7 @@
@@ -154,7 +154,7 @@

allSprites<
Source:
@@ -228,7 +228,7 @@

cameraSource:
@@ -302,7 +302,7 @@

canvasSource:
@@ -379,7 +379,7 @@

controSource:
@@ -453,7 +453,7 @@

controller
Source:
@@ -527,7 +527,7 @@

controsSource:
@@ -601,7 +601,7 @@

kbSource:
@@ -675,7 +675,7 @@

keyboardSource:
@@ -752,7 +752,7 @@

loadAnim
Source:
@@ -819,7 +819,7 @@

loadImageSource:
@@ -883,7 +883,7 @@

logSource:
@@ -958,7 +958,7 @@

mouseSource:
@@ -1032,7 +1032,7 @@

p5playSource:
@@ -1106,7 +1106,7 @@

touchesSource:
@@ -1180,7 +1180,7 @@

worldSource:
@@ -1264,7 +1264,7 @@

EmojiImage<
Source:
@@ -1457,7 +1457,7 @@

animationSource:
@@ -1723,7 +1723,7 @@

background<
Source:
@@ -1806,7 +1806,7 @@

colorPalSource:
@@ -2000,7 +2000,7 @@

createCan
Source:
@@ -2112,7 +2112,7 @@

createGrou
Source:
@@ -2220,7 +2220,7 @@

createSpr
Source:
@@ -2326,7 +2326,7 @@

createTile
Source:
@@ -2412,7 +2412,7 @@

delaySource:
@@ -2582,7 +2582,7 @@

fillSource:
@@ -2672,7 +2672,7 @@

getFPSSource:
@@ -2780,7 +2780,7 @@

playSource:
@@ -2945,7 +2945,7 @@

renderStat
Source:
@@ -3106,7 +3106,7 @@

resizeCan
Source:
@@ -3192,7 +3192,7 @@

sleepSource:
@@ -3363,7 +3363,7 @@

spriteArtSource:
@@ -3594,7 +3594,7 @@

strokeSource:
@@ -3646,7 +3646,7 @@

stroke
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/index.html b/docs/index.html index 23b88a21..8a9d6ed1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,7 +24,7 @@
@@ -57,7 +57,7 @@
- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/docs/p5play.js.html b/docs/p5play.js.html index 360a1d10..97a2d812 100644 --- a/docs/p5play.js.html +++ b/docs/p5play.js.html @@ -24,7 +24,7 @@
@@ -41,9 +41,8 @@

p5play.js

/**
  * p5play
- * @version 3.24
+ * @version 3.25
  * @author quinton-ashley
- * @license AGPL-3.0
  */
 
 if (typeof planck != 'object') {
@@ -75,12 +74,13 @@ 

p5play.js

}; gtag('js', new Date()); gtag('config', 'G-EHXNCTSYLK'); - gtag('event', 'p5play_v3_24'); + gtag('event', 'p5play_v3_25'); }; } - // the p5play default angle mode is degrees - $.angleMode('degrees'); + // in p5play the default angle mode is degrees + const DEGREES = $.DEGREES; + $.angleMode(DEGREES); // scale to planck coordinates from p5 coordinates const scaleTo = (x, y, tileSize) => @@ -92,12 +92,13 @@

p5play.js

new pl.Vec2((x / tileSize) * $.world.meterSize, (y / tileSize) * $.world.meterSize); const scaleXFrom = (x, tileSize) => (x / tileSize) * $.world.meterSize; - const isSlop = (val) => Math.abs(val) <= pl.Settings.linearSlop; - const fixRound = (val, slop) => - Math.abs(val - Math.round(val)) <= (slop || pl.Settings.linearSlop) ? Math.round(val) : val; + const linearSlop = pl.Settings.linearSlop; + const angularSlop = pl.Settings.angularSlop / 60; + const isSlop = (val) => Math.abs(val) <= linearSlop; + const fixRound = (val, slop) => (Math.abs(val - Math.round(val)) <= (slop || linearSlop) ? Math.round(val) : val); const minAngleDist = (ang, rot) => { - let full = $._angleMode == 'degrees' ? 360 : $.TWO_PI; + let full = $._angleMode == DEGREES ? 360 : $.TWO_PI; let dist1 = (ang - rot) % full; let dist2 = (full - Math.abs(dist1)) * -Math.sign(dist1); return (Math.abs(dist1) < Math.abs(dist2) ? dist1 : dist2) || 0; @@ -164,17 +165,14 @@

p5play.js

this.friendlyRounding = true; /** - * Set to the latest version of p5play v3's - * minor version number. For example to enable - * v3.16 features, set this to 16. - * - * Some features are not backwards compatible - * with older versions of p5play, so this - * variable is used to enable them. - * @type {Number} - * @default 0 + * Groups that are removed using `group.remove()` are not + * fully deleted from `p5play.groups` by default, so their data + * is still accessible. Set to false to permanently delete + * removed groups, which reduces memory usage. + * @type {Boolean} + * @default true */ - this.targetVersion = 0; + this.storeRemovedGroupRefs = true; /** * Information about the operating system being used to run @@ -624,14 +622,16 @@

p5play.js

x ??= group.x; if (x === undefined) { - if ($.canvas?.renderer == '2d') x = $.canvas.hw / this.tileSize; - else x = 0; + if ($.canvas?.renderer == '2d' && !$._webgpuFallback) { + x = $.canvas.hw / this.tileSize; + } else x = 0; if (w) this._vertexMode = true; } y ??= group.y; if (y === undefined) { - if ($.canvas?.renderer == '2d') y = $.canvas.hh / this.tileSize; - else y = 0; + if ($.canvas?.renderer == '2d' && !$._webgpuFallback) { + y = $.canvas.hh / this.tileSize; + } else y = 0; } let forcedBoxShape = false; @@ -1587,7 +1587,6 @@

p5play.js

return this._color; } set color(val) { - // TODO: check if the color is the same as the current color if (this.watch) this.mod[9] = true; this._color = this._parseColor(val); } @@ -1602,7 +1601,6 @@

p5play.js

set colour(val) { this.color = val; } - /** * Alias for sprite.fillColor * @type {p5.Color} @@ -1614,11 +1612,9 @@

p5play.js

set fill(val) { this.color = val; } - /** - * Alias for sprite.color - * @type {p5.Color} - * @default random color + * Deprecated alias for sprite.fill, will be removed in the future. + * @deprecated */ get fillColor() { return this._color; @@ -1642,9 +1638,8 @@

p5play.js

this._stroke = this._parseColor(val); } /** - * Alias for sprite.stroke - * @type {p5.Color} - * @default undefined + * Deprecated alias for sprite.stroke, will be removed in the future. + * @deprecated */ get strokeColor() { return this._stroke; @@ -2269,12 +2264,13 @@

p5play.js

get rotation() { if (!this.body) return this._rotation || 0; let val = this.body.getAngle(); - if ($._angleMode == 'degrees') val = $.degrees(val); - return $.p5play.friendlyRounding ? fixRound(val, pl.Settings.angularSlop) : val; + val = $.p5play.friendlyRounding ? fixRound(val, angularSlop) : val; + if ($._angleMode == DEGREES) val = $.degrees(val); + return val; } set rotation(val) { if (this.body) { - if ($._angleMode == 'degrees') { + if ($._angleMode == DEGREES) { val = $.radians(val % 360); } this.body.setAngle(val); @@ -2319,7 +2315,7 @@

p5play.js

get rotationSpeed() { if (this.body) { let val = this.body.getAngularVelocity() / 60; - if ($._angleMode == 'degrees') return $.degrees(val); + if ($._angleMode == DEGREES) return $.degrees(val); return val; } return this._rotationSpeed; @@ -2327,7 +2323,7 @@

p5play.js

set rotationSpeed(val) { if (this.body) { val *= 60; - if ($._angleMode == 'degrees') val = $.radians(val); + if ($._angleMode == DEGREES) val = $.radians(val); this.body.setAngularVelocity(val); } else this._rotationSpeed = val; } @@ -2438,7 +2434,7 @@

p5play.js

return this._tint; } set tint(val) { - if (this.watch) this.mod[42] = true; + if (this.watch) this.mod[38] = true; this._tint = this._parseColor(val); } @@ -3042,7 +3038,7 @@

p5play.js

if (this._removed) { if (Object.keys(this._collisions).length == 0 && Object.keys(this._overlappers).length == 0) { if (this._isSprite) delete $.p5play.sprites[this._uid]; - else if ($.p5play.targetVersion >= 16) delete $.p5play.groups[this._uid]; + else if (!$.p5play.storeRemovedGroupRefs) delete $.p5play.groups[this._uid]; // remove contact events for (let eventType in eventTypes) { @@ -3754,7 +3750,7 @@

p5play.js

} if (angle == this.rotation) return; - let full = $._angleMode == 'degrees' ? 360 : $.TWO_PI; + let full = $._angleMode == DEGREES ? 360 : $.TWO_PI; angle = (angle - this.rotation) % full; if (angle < 0 && speed > 0) angle += full; if (angle > 0 && speed < 0) angle -= full; @@ -4464,6 +4460,7 @@

p5play.js

$.Sprite.propsAll = $.Sprite.props.concat([ 'autoDraw', 'autoUpdate', + 'colour', 'd', 'diameter', 'dynamic', @@ -4475,6 +4472,8 @@

p5play.js

'speed', 'spriteSheet', 'static', + 'textColour', + 'textFill', 'width' ]); @@ -6365,6 +6364,14 @@

p5play.js

return this.length; } + /** + */ + repelFrom() { + for (let s of this) { + s.repelFrom(...arguments); + } + } + /** * Alias for group.length * @deprecated @@ -6869,7 +6876,7 @@

p5play.js

/** * Returns the sprites at a position, ordered by layer. - * @param {Number} x + * @param {Number} x - x coordinate or position object * @param {Number} y * @param {Group} [group] - limit results to a specific group, * allSprites by default @@ -6878,6 +6885,10 @@

p5play.js

* @returns {Sprite[]} an array of sprites */ getSpritesAt(x, y, group, cameraActiveWhenDrawn = true) { + if (typeof x == 'object') { + y = x.y; + x = x.x; + } const convertedPoint = new pl.Vec2(x / $.world.meterSize, y / $.world.meterSize); const aabb = new pl.AABB(); aabb.lowerBound = new pl.Vec2(convertedPoint.x - 0.001, convertedPoint.y - 0.001); @@ -7738,10 +7749,7 @@

p5play.js

} this._springiness = val; - if (this.type != 'wheel') { - this._j.setFrequency(val); - return; - } + if (this.type != 'wheel') return this._j.setFrequency(val); this._j.setSpringFrequencyHz(val); } @@ -7961,7 +7969,7 @@

p5play.js

new pl.Vec2(0, 1) ); this._createJoint(j); - this._angle = $._angleMode == 'degrees' ? 90 : 1.5707963267948966; + this._angle = $._angleMode == DEGREES ? 90 : 1.5707963267948966; } _display() { @@ -8074,7 +8082,7 @@

p5play.js

} this.spriteA.body.setAwake(true); this.spriteB.body.setAwake(true); - if ($._angleMode == 'degrees') val = $.radians(val); + if ($._angleMode == DEGREES) val = $.radians(val); this._j.m_lowerAngle = val; } @@ -8094,7 +8102,7 @@

p5play.js

} this.spriteA.body.setAwake(true); this.spriteB.body.setAwake(true); - if ($._angleMode == 'degrees') val = $.radians(val); + if ($._angleMode == DEGREES) val = $.radians(val); this._j.m_upperAngle = val; } @@ -8254,6 +8262,49 @@

p5play.js

} }; + this.GrabberJoint = class extends this.Joint { + constructor(spriteA, pos) { + if (typeof pos != 'object') pos = $.mouse; + + super(spriteA, spriteA, 'grab'); + + this._target = { x: pos.x, y: pos.y }; + this.__target = new pl.Vec2(pos.x / $.world.meterSize, pos.y / $.world.meterSize); + + let j = pl.MouseJoint( + { + maxForce: 1000, + frequencyHz: 3, + dampingRatio: 0.9, + target: spriteA.body.getPosition() + }, + spriteA.body, + spriteA.body, + this.__target + ); + this._createJoint(j); + } + + _draw() { + $.line(this.spriteA.x, this.spriteA.y, this._target.x, this._target.y); + } + + get target() { + return this._target; + } + set target(pos) { + this._target.x = pos.x; + this._target.y = pos.y; + this.__target.x = pos.x / $.world.meterSize; + this.__target.y = pos.y / $.world.meterSize; + this._j.setTarget(this.__target); + } + + set maxForce(val) { + this._j.setMaxForce(val); + } + }; + class Scale { constructor() { let _this = this; @@ -8305,43 +8356,6 @@

p5play.js

} } - // source: https://stackoverflow.com/a/8796597/3792062 - function decodeFloat16(b) { - let e = (b & 0x7c00) >> 10, - f = b & 0x03ff; - return ( - (b >> 15 ? -1 : 1) * - (e ? (e === 0x1f ? (f ? NaN : Infinity) : Math.pow(2, e - 15) * (1 + f / 0x400)) : 6.103515625e-5 * (f / 0x400)) - ); - } - - // source: https://stackoverflow.com/a/32633586/3792062 - const encodeFloat16 = (function () { - let fv = new Float32Array(1); - let iv = new Int32Array(fv.buffer); - return function toHalf(v) { - fv[0] = v; - let x = iv[0]; - let b = (x >> 16) & 0x8000; - let m = (x >> 12) & 0x07ff; - let e = (x >> 23) & 0xff; - if (e < 103) return b; - if (e > 142) { - b |= 0x7c00; - b |= (e == 255 ? 0 : 1) && x & 0x007fffff; - return b; - } - if (e < 113) { - m |= 0x0800; - b |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); - return b; - } - b |= ((e - 112) << 10) | (m >> 1); - b += m & 1; - return b; - }; - })(); - function isArrowFunction(fn) { return !/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test( fn.toString() @@ -8833,17 +8847,19 @@

p5play.js

c.hw = c.w * 0.5; c.hh = c.h * 0.5; c.mouse = { x: $.mouseX, y: $.mouseY }; - if (c.renderer == '2d') { + if (c.renderer == '2d' && !$._webgpuFallback) { $.camera.x = $.camera.ogX = c.hw; $.camera.y = $.camera.ogY = c.hh; } else { $.camera.x = 0; $.camera.y = 0; if (c.renderer == 'webgl') $._textCache = false; - $.p5play._renderStats = { - x: -c.hw + 10, - y: -c.hh + 20 - }; + if (!$._webgpuFallback) { + $.p5play._renderStats = { + x: -c.hw + 10, + y: -c.hh + 20 + }; + } } if (!userDisabledP5Errors) p5.disableFriendlyErrors = false; @@ -9069,7 +9085,7 @@

p5play.js

} if (img) { // if not finished loading, add callback to the list - if ((img.width == 1 && img.height == 1) || !img.pixels.length) { + if ((img.width <= 1 && img.height <= 1) || !img.pixels.length) { if (cb) { img.cbs.push(cb); img.calls++; @@ -9095,13 +9111,17 @@

p5play.js

}); } - for (let cb of _img.cbs) { - cb(_img); - } - for (let i = 1; i < _img.calls; i++) { - $._decrementPreload(); + // server side use of p5play makes images load synchronously + if (_img.cbs) { + for (let cb of _img.cbs) { + cb(_img); + } + for (let i = 1; i < _img.calls; i++) { + $._decrementPreload(); + } + _img.cbs = []; } - _img.cbs = []; + $.p5play.onImageLoad(img); }; img = _loadImage.call($, url, _cb); @@ -9127,7 +9147,7 @@

p5play.js

// if the user isn't using q5.js // add a backwards compatibility layer for p5.js - if (!$.displayMode) { + if (!$.displayMode && typeof document == 'object') { document.head.insertAdjacentHTML( 'beforeend', `<style> @@ -9135,6 +9155,9 @@

p5play.js

margin: 0; padding: 0; } +body.hasFrameBorder { + display: block; +} .p5Canvas { outline: none; -webkit-touch-callout: none; @@ -10672,6 +10695,8 @@

p5play.js

*/ this.contro = new $.Contro('mock0'); + if ($._webgpuFallback) $._beginRender = false; + /** * FPS, amongst the gaming community, refers to how fast a computer * can generate frames per second, not including the delay between when @@ -10893,7 +10918,7 @@

p5play.js


- Generated by JSDoc 4.0.2 on Fri Nov 08 2024 12:40:26 GMT-0500 (Colombia Standard Time) using the Minami theme. + Generated by JSDoc 4.0.2 on Sat Dec 07 2024 10:37:00 GMT-0500 (Colombia Standard Time) using the Minami theme.
diff --git a/lang/en/en.json b/lang/en/en.json index 2753d926..5dc032e4 100644 --- a/lang/en/en.json +++ b/lang/en/en.json @@ -56,7 +56,7 @@ "Draw and Update" ], "input": ["Detecting Input", "Keyboard", "Mouse", "Sprite Mouse", "Game Controllers", "Touch"], - "joints": ["GlueJoint", "DistanceJoint", "WheelJoint", "HingeJoint", "SliderJoint"], + "joints": ["GlueJoint", "DistanceJoint", "WheelJoint", "HingeJoint", "SliderJoint", "GrabberJoint"], "sound": ["Using Sounds"], "sprite": [ "Basic Properties", diff --git a/lang/en/learn/joints.md b/lang/en/learn/joints.md index f9a0892a..fcc8e2ba 100644 --- a/lang/en/learn/joints.md +++ b/lang/en/learn/joints.md @@ -83,3 +83,19 @@ The joint's `range` determines how far apart the connected sprites can be from e By default the joint's motor is enabled with a `speed` of 0, so `maxPower` determines how much the joint can resist sliding. Try dropping boxes on the scale by clicking with your mouse. How many boxes can you stack on the scale before it reaches its limit? Try changing its angle too. + +# 5-0 + +## GrabberJoint + +Grab sprites and move them with a max force towards a target position using a `GrabberJoint`. + +Try clicking and dragging sprites around the canvas in this example. + +Note the use of `world.getSpriteAt` to get the sprite at the mouse position, if any. + +Continuously set the `target` property to move the sprite towards a target position. This can be any object with x and y properties. + +Remove the joint to release the sprite that was grabbed. + +Try changing `maxForce` from the default value of 1000. diff --git a/lang/es/es.json b/lang/es/es.json index 5a8ca1f8..e94b6783 100644 --- a/lang/es/es.json +++ b/lang/es/es.json @@ -55,7 +55,7 @@ "Dibujar y actualizar" ], "input": ["Detección de Entrada", "Teclado", "Ratón", "Ratón de Sprite", "Controladores de Juego", "Táctil"], - "joints": ["pegamento", "distancia", "rueda", "bisagra", "deslizador"], + "joints": ["pegamento", "distancia", "rueda", "bisagra", "deslizador", "agarrador"], "sound": ["Usando sonidos"], "sprite": [ "Propiedades Básicas", diff --git a/lang/es/learn/joints.html b/lang/es/learn/joints.html index 14b42b72..9fe1aeee 100644 --- a/lang/es/learn/joints.html +++ b/lang/es/learn/joints.html @@ -116,15 +116,15 @@

DistanceJoint

@@ -266,6 +266,49 @@

SliderJoint

+
+ +

GrabberJoint

+

Agarra sprites y muévelos con una fuerza máxima hacia una posición objetivo usando un + GrabberJoint.

+

Intenta hacer clic y arrastrar sprites por el lienzo en este ejemplo.

+

Ten en cuenta el uso de world.getSpriteAt para obtener el sprite en la posición del + ratón, si existe.

+

Establece continuamente la propiedad target para mover el sprite hacia una posición + objetivo. Esto puede ser cualquier objeto con propiedades x e y.

+

Elimina el joint para soltar el sprite que fue agarrado.

+

Intenta cambiar maxForce desde su valor predeterminado de 1000.

+
+ +
@@ -276,6 +319,7 @@

SliderJoint

rueda bisagra deslizador + agarrador
Siguiente página

diff --git a/lang/es/learn/joints.md b/lang/es/learn/joints.md index bec5c630..d5e07ff9 100644 --- a/lang/es/learn/joints.md +++ b/lang/es/learn/joints.md @@ -82,3 +82,19 @@ El `range` (rango) de la articulación determina cuán separados pueden estar lo Por defecto, el motor de la articulación está activado con una `speed` (velocidad) de 0, por lo que `maxPower` (poder maximo) determina cuánto puede resistir la articulación al deslizamiento. Prueba soltar cajas en la balanza haciendo clic con el ratón. ¿Cuántas cajas puedes apilar en la balanza antes de que alcance su límite? Intenta cambiar su ángulo también. + +# 5-0 + +## GrabberJoint + +Agarra sprites y muévelos con una fuerza máxima hacia una posición objetivo usando un `GrabberJoint`. + +Intenta hacer clic y arrastrar sprites por el lienzo en este ejemplo. + +Ten en cuenta el uso de `world.getSpriteAt` para obtener el sprite en la posición del ratón, si existe. + +Establece continuamente la propiedad `target` para mover el sprite hacia una posición objetivo. Esto puede ser cualquier objeto con propiedades x e y. + +Elimina el joint para soltar el sprite que fue agarrado. + +Intenta cambiar `maxForce` desde su valor predeterminado de 1000. diff --git a/lang/ja/ja.json b/lang/ja/ja.json index 74cc3683..3f846130 100644 --- a/lang/ja/ja.json +++ b/lang/ja/ja.json @@ -56,7 +56,14 @@ "グループの描画と画面更新" ], "input": ["入力の検知", "キーボード", "マウス", "スプライトマウス", "ゲームコントローラー", "タッチ"], - "joints": ["グルージョイント", "ディスタンスジョイント", "ホイールジョイント", "ヒンジジョイント", "スライダージョイント"], + "joints": [ + "グルージョイント", + "ディスタンスジョイント", + "ホイールジョイント", + "ヒンジジョイント", + "スライダージョイント", + "グラバージョイント" + ], "sound": ["サウンド"], "sprite": [ "基本的なプロパティ", diff --git a/lang/ja/learn/joints.html b/lang/ja/learn/joints.html index 1b86b7f0..b3a1831a 100644 --- a/lang/ja/learn/joints.html +++ b/lang/ja/learn/joints.html @@ -112,15 +112,15 @@

ディスタンスジョイント

collideConnected を true に設定して、接続されたスプライトが互いに衝突するようにします。

@@ -252,6 +252,46 @@

スライダージョイント

+
+ +

GrabberJoint

+

GrabberJointを使用して、スプライトを掴んで最大の力で目標位置まで移動させることができます。

+

この例では、スプライトをクリックしてドラッグしてみましょう。

+

マウス位置にあるスプライトを取得するためにworld.getSpriteAtを使用していることに注目してください。

+

スプライトを目標位置に移動させるために、継続的にtargetプロパティを設定します。これは x と y のプロパティを持つどのようなオブジェクトでも可能です。

+

掴んだスプライトを解放するには、ジョイントを削除します。

+

デフォルト値 1000 からmaxForceを変更してみましょう。

+
+ +
次へ

diff --git a/lang/ja/learn/joints.md b/lang/ja/learn/joints.md index bb125bd5..12b3ca93 100644 --- a/lang/ja/learn/joints.md +++ b/lang/ja/learn/joints.md @@ -82,3 +82,19 @@ Joint はコンストラクタ引数として、 2 つのスプライトを受 デフォルトでは、このジョイントのモーターは有効で、 `speed` は 0 です。 `maxPower` は、このジョイントがスライドにどれだけ抵抗できるかを決定します。 コードサンプルでマウスをクリックし、ばね秤に箱を落としてみてください。ばね秤が限界に達するまでに、あなたは箱をいくつ積み重ねることができるでしょうか? angle を変えることも試してくださいね。 + +# 5-0 + +## GrabberJoint + +`GrabberJoint`を使用して、スプライトを掴んで最大の力で目標位置まで移動させることができます。 + +この例では、スプライトをクリックしてドラッグしてみましょう。 + +マウス位置にあるスプライトを取得するために`world.getSpriteAt`を使用していることに注目してください。 + +スプライトを目標位置に移動させるために、継続的に`target`プロパティを設定します。これは x と y のプロパティを持つどのようなオブジェクトでも可能です。 + +掴んだスプライトを解放するには、ジョイントを削除します。 + +デフォルト値 1000 から`maxForce`を変更してみましょう。 diff --git a/learn/joints.html b/learn/joints.html index c06d6acd..2c8965d3 100644 --- a/learn/joints.html +++ b/learn/joints.html @@ -112,15 +112,15 @@

DistanceJoint

Set collideConnected to true to make connected sprites collide with each other.

@@ -257,6 +257,48 @@

SliderJoint

+
+ +

GrabberJoint

+

Grab sprites and move them with a max force towards a target position using a + GrabberJoint.

+

Try clicking and dragging sprites around the canvas in this example.

+

Note the use of world.getSpriteAt to get the sprite at the mouse position, if any.

+

Continuously set the target property to move the sprite towards a target position. This + can be any object with x and y properties.

+

Remove the joint to release the sprite that was grabbed.

+

Try changing maxForce from the default value of 1000.

+
+ +
@@ -267,6 +309,7 @@

SliderJoint

WheelJoint HingeJoint SliderJoint + GrabJoint
Next Page

diff --git a/package.json b/package.json index 4c915336..6d6331cc 100644 --- a/package.json +++ b/package.json @@ -31,5 +31,5 @@ "version": "git add -A", "postversion": "git push" }, - "version": "1.14.6" + "version": "1.15.0" } diff --git a/pro/PRO_LICENSE.md b/pro/PRO_LICENSE.md index ba6c80a8..fb8961ae 100644 --- a/pro/PRO_LICENSE.md +++ b/pro/PRO_LICENSE.md @@ -1,61 +1,136 @@ # p5play Professional License -This License Agreement ("Agreement") is made between Quinton Ashley, the sole copyright owner of p5play ("Licensor") and an individual or group actively paying license fees ("Licensee"). +This License Agreement ("Agreement") is made between Quinton Ashley, the sole copyright owner of p5play ("Licensor") and an individual, organization, or company ("Licensee") actively paying Pro license fees on a subscription basis. + +https://p5play.org/pro + +For educational use, see the [p5play Educational License](https://p5play.org/teach). ## 1. License Grant -This Agreement covers the p5play and p5play-pro software libraries ("Content") and any proprietary supplemental materials ("Supplemental Materials") provided privately to Licensees only. +This Agreement ("License") primarily governs the use of the p5play and p5play-pro software libraries (collectively, the "Content"). + +The Licensor grants to the Licensee a non-exclusive, non-transferable, and non-perpetual worldwide license to use the Content, subject to the following restrictions. + +### 1a. Educational Use Limitation -The Licensee is also granted the right to use the [p5play.org Learn pages](https://p5play.org/learn) on an individual basis, not for teaching. Educators or educational institutions must pay p5play Educational License fees on a per-student basis, see https://p5play.org/teach for more information. +The Licensee is expressly forbidden from using the Content for educational purposes, such as in class or coursework. -The Licensor grants to the Licensee a non-exclusive, non-transferable, and non-perpetual worldwide license to use the Content and Supplemental Materials in closed-source commercial projects, subject to the following restrictions: +Users must purchase a [p5play Educational License](https://p5play.org/teach) subscription for educational use of the Content, even if it's used indirectly through a third-party provider, unless their use is covered by a p5play Educational licensee. -1. No Closed Source Modifications: The Licensee is expressly forbidden from creating a closed source fork of the Content or using modified versions of the Content in closed source projects. +As an exception, the Content can be used in interactive art that is educational in nature, but the topics covered must not be related to computer programming or game development. For example, a game that teaches players how to cook is permitted. -2. Limited Redistribution: The Licensee is only allowed to redistribute the Supplemental Materials to their team members or co-workers. The Licensee can not sublicense or sell the Content or Supplemental Materials to anyone. The Licensee is expressly forbidden from redistributing the Supplemental Materials in any way that would allow the general public to access them. +### 1b. Derivative Work Restrictions -3. No Military Use: The Licensee is expressly forbidden from using the Content in projects that are directly sponsored by military organizations or military contractors. +Any modification, enhancement, or adaptation of the Content ("Derivative Work") shall be owned by the Licensor. Derivative Works must be created for the sole purpose of improving the Content, for the benefit of all users of p5play. -Licensees retain the option to use the p5play library under the terms of the AGPLv3. +By creating a Derivative Work, the Licensee hereby: -## 2. Licensee Eligibility +- Assigns all rights, title, and interest in the Derivative Work to the Licensor +- Waives any moral rights in the Derivative Work +- Grants the Licensor exclusive rights to use, modify, and distribute the Derivative Work +- Agrees to execute any documents necessary to perfect such rights -The Licensee must be a current, paying subscriber to the Licensor's [GitHub Sponsors](https://github.com/sponsors/quinton-ashley) or [Patreon](https://www.patreon.com/p5play) at the appropriate tier, as determined by the Licensor. +The Licensee must notify and distribute Derivative Works to the Licensor via GitHub PR, email (info@p5play.org), or Discord post/message and not by any other means. -Individuals over the age of 18 can pay licensing fees for their own individual use. Parental guardians or other adults can make purchases on behalf of a user that's a minor, and are responsible for ensuring compliance with this Agreement. +### 1c. Limited Redistribution -If Licensees have any concerns about what tier is appropriate for their use, they must contact the Licensor at info@p5play.org and explain their planned use of the Content. +The Licensee may host verbatim, unmodified copies of the Content only. "Verbatim copies" means exact duplicates of the Content as provided by the Licensor, without changes. The Licensee may not sell or sublicense the Content. -Renewal of this Agreement can only be achieved through payments on a monthly or yearly basis, depending on the tier or payment plan chosen by the Licensee. +### 1d. No Military Use -A Licensee can pay more than the appropriate tier amount if they wish to support the Licensor's work to a greater extent. +The Content shall not be used in any projects commissioned by, endorsed by, or developed for military organizations or their contractors. -Note that the Licensor reserves the right to change the tier costs at any time, but will give at least a one month notice to Licensees before doing so. +### 1e. Portfolio Project Exception -## 3. Attribution Required +Former Licensees maintain the right to use the Content under the terms of this license in portfolio projects that satisfy all of the following conditions: + +- Active development occurred during an active Pro License term +- No substantial modifications for over 3 months +- Project only receives maintenance updates + +### 1f. Attribution Required The Licensee must publicly display appropriate credit to the Licensor for the Content, but not in any way that suggests the Licensor endorses the Licensee or the Licensee's use, unless the Licensor has given prior written consent. -Attribution can be accomplished by maintaining the "made with p5play" Loading Screen, which is enabled by default, or in any reasonable manner, such as displaying the "made with p5play" image in a website's footer or game's credits section. +Use of the "made with p5play" Loading Screen is required for all published work that uses p5play, unless the work is published on an online code editing platform or other web app that was approved by the Licensor to be exempt from this requirement, in which case the loading screen will not appear. Attribution can then be made at the top of the primary script file or in a README file. The following is an example of acceptable attribution: + +```js +/** + * Made with p5play! + * https://p5play.org + */ +``` + +## 2. Licensee Eligibility Requirements + +Active subscription status must be maintained through the Licensor's authorized payment platforms ([GitHub Sponsors](https://github.com/sponsors/quinton-ashley) or [Patreon](https://www.patreon.com/p5play)) at the designated tier level. + +Eligible Licensees must either be: + +- Individuals aged 18 or older purchasing for their own use +- Legal guardians/adults purchasing on behalf of minors (accepting full responsibility for license compliance) + +The Licensee shall contact info@p5play.org to verify appropriate tier selection prior to use. License renewal requires continuous monthly or annual payments at the selected tier level. + +Voluntary contributions exceeding the minimum tier requirements are permitted and appreciated. + +Note: Portfolio projects meeting Section 1e criteria retain limited usage rights post-subscription. All other rights require active subscription status. -## 4. No Warranty +## 3. Licensee Consent + +Licensees optionally consent to p5play using Google Analytics to track how they use p5play. To revoke this consent, you can use a browser extension to block Google Analytics or set `window._p5play_gtagged = false;` before loading p5play. + +## 4. "Learn p5play" Interactive Textbook Access + +The Licensee is granted access to the [p5play.org Learn pages](https://p5play.org/learn) for their own learning and evaluation only. + +## 5. Supplemental Materials + +Supplemental Materials, such as the p5play-ios app template and p5play Game Design Fundamentals curriculum, are provided exclusively to authorized Licensees. These materials are intended to enhance the use of the Content and are not to be redistributed or used outside the scope of this Agreement. + +## 6. Revenue Share + +The Licensee must pay the Licensor 10% of gross revenue when the lifetime combined revenue from all projects using the Content exceeds $1000 USD (one thousand United States Dollars). This threshold calculation includes all historical revenue since first use of the Content. "Gross revenue" includes but is not limited to: + +- Direct sales +- In-app purchases +- Subscription fees +- Advertising revenue +- Crowdfunding +- Donations related to projects using the Content + +The Licensee shall: + +- Track lifetime revenue across all projects using the Content +- Report total combined revenue quarterly +- Begin revenue sharing immediately upon exceeding threshold +- Make payments within 30 days of each quarter end +- Pay retroactive share on all past revenue upon exceeding threshold +- Maintain accurate financial records for audit purposes + +## 7. No Warranty The Content is provided "as is." The Licensor makes no warranties, express or implied, including without limitation any implied warranty of merchantability or fitness for a particular purpose, concerning the Content. -## 5. Limitation of Liability +If the Licensee has any issues with the Content, they must contact the Licensor. -If Licensee has any issues with the Content, they must contact the Licensor at info@p5play.org. The Licensor will make a reasonable effort to resolve the issue in a timely manner. +If the Licensee is not satisfied with the Content, it is their responsibility to discontinue use of the Content. -If the Licensee is not satisfied with the Content, it is their responsibility to discontinue use of the Content and terminate their renewal of this Agreement. +## 8. Limitation of Liability The Licensor shall not be liable for any damages suffered by the Licensee resulting from the use or inability to use the Content. -## 6. Termination +Licensees must comply with all applicable laws and regulations when using p5play. It is illegal to create content that infringes on the rights of others. Licensees are fully liable for any content they create with p5play. + +## 9. Termination Termination of the Agreement will occur if the Licensee fails to comply with any term(s) of this Agreement. Therefore, termination can occur automatically, without notice from the Licensor. -Any lapse in licensing payments will result in the immediate termination of this Agreement. +Note that the Licensor reserves the right to change the cost of renewing this license at any time. Any lapse in licensing payments will result in the immediate termination of this Agreement. + +## 10. Entire Agreement -## 7. Entire Agreement +This Agreement constitutes the entire agreement between the parties and supersedes all prior understandings and agreements, whether written or oral, relating to the subject matter of this Agreement. -This Agreement constitutes the entire agreement between the parties and supersedes all prior understandings and agreements, whether written or oral, relating to the subject matter of this Agreement. This Agreement can be amended by the Licensor at any time. If any provision of this Agreement is found to be invalid or unenforceable, the remaining provisions will remain in full force and effect. +This Agreement can be amended by the Licensor at any time. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. diff --git a/teach/EDU_LICENSE.md b/teach/EDU_LICENSE.md index 181b0c53..96f478ae 100644 --- a/teach/EDU_LICENSE.md +++ b/teach/EDU_LICENSE.md @@ -2,62 +2,133 @@ This License Agreement ("Agreement") is made between Quinton Ashley, the sole copyright owner of p5play ("Licensor") and an educator, adult student, or an educational institution and its staff ("Licensee") that paid license fees determined by the Licensor. -Contact to request a custom invoice to use p5play in an educational setting. +https://p5play.org/teach + +For commercial use, see the [p5play Professional License](https://p5play.org/pro). ## 1. License Grant -The Licensee is granted the right to use the [p5play.org Learn pages](https://p5play.org/learn) for educational purposes in class or coursework and in educational settings, including but not limited to schools, home schools, universities, coding bootcamps, and online tutoring. +This Agreement ("License") governs the use of the p5play and p5play-pro software libraries (collectively, the "Content"). + +The rights granted by this license extend to all students for whom the Licensee has paid the appropriate per-student fees. After the licensing term expires, students may continue to use p5play for free under the terms of the p5play Personal License. + +If the Licensee solely paid for its own use of p5play, third-parties must obtain their own license to use the Content for educational purposes, even if their use is through the Licensee. + +The Licensor grants to the Licensee a non-exclusive, non-transferable, and non-perpetual worldwide license to use the Content, subject to the following restrictions. -This Agreement also covers the p5play and p5play-pro software libraries ("Content") and any proprietary supplemental materials ("Supplemental Materials") provided privately to Licensees only. +### 1a. Limited Commercial Use -The Licensor grants to the Licensee a non-exclusive, non-transferable, and non-perpetual worldwide license to use the Content and Supplemental Materials in closed-source commercial projects, subject to the following restrictions: +The Licensee may use the Content for educational business purposes, including: -1. No Closed Source Modifications: The Licensee is expressly forbidden from creating a closed source fork of the Content or using modified versions of the Content in closed source projects. +- Paid courses or tutorials +- Educational platforms and learning management systems +- For-profit educational institutions +- Private tutoring services -2. Limited Redistribution: The Licensee is only allowed to redistribute the Supplemental Materials to their staff and students. The Licensee can not sublicense or sell the Content or Supplemental Materials to anyone. The Licensee is expressly forbidden from redistributing the Supplemental Materials in any way that would allow the general public to access them. +The Licensee may not use the Content for commercial purposes that are not directly related to education, such as: -3. No Military Use: The Licensee is expressly forbidden from using the Content in projects that are directly sponsored by military organizations or military contractors. +- Game development for profit +- Commercial software development +- Commercial web development +- Commercial art or design +- Marketing or advertising not related to the Licensee's educational services -Licensees retain the option to use the p5play and p5play-pro libraries under the terms of the AGPLv3. +The Licensee must purchase a [p5play Professional License](https://p5play.org/pro) to use p5play for commercial purposes not related to education. -## 2. Licensee Eligibility +### 1b. Derivative Work Restrictions -Licensing fees are based on the scale of the Licensee's use of the Content at a per student rate. The Licensee must pay the appropriate amount for the number of students that will be using the Content. +Any modification, enhancement, or adaptation of the Content ("Derivative Work") shall be owned by the Licensor. Derivative Works must be created for the sole purpose of improving the Content, for the benefit of all users of p5play. -Individuals over the age of 18 can pay licensing fees for their own individual use. Parental guardians or other adults can make purchases on behalf of a user that's a minor, and are responsible for ensuring compliance with this Agreement. +By creating a Derivative Work, the Licensee hereby: -If Licensees have any concerns about what amount is appropriate for their use, they must contact the Licensor at info@p5play.org and explain their planned use of the Content. +- Assigns all rights, title, and interest in the Derivative Work to the Licensor +- Waives any moral rights in the Derivative Work +- Grants the Licensor exclusive rights to use, modify, and distribute the Derivative Work +- Agrees to execute any documents necessary to perfect such rights -Renewal of this Agreement can only be achieved through payments on a monthly or yearly basis, depending on the payment plan chosen by the Licensee. +The Licensee must notify and distribute Derivative Works to the Licensor via GitHub PR, email (info@p5play.org), or Discord post/message and not by any other means. -A Licensee can pay more than the appropriate amount if they wish to support the Licensor's work to a greater extent. +### 1c. Limited Redistribution -Note that the Licensor reserves the right to change the cost of renewing this license agreement at any time, but will give at least a one month notice to Licensees before doing so. +The Licensee may host verbatim, unmodified copies of the Content only. "Verbatim copies" means exact duplicates of the Content as provided by the Licensor, without changes. The Licensee may not sell or sublicense the Content. -## 3. Attribution Required +### 1d. No Military Use + +The Content shall not be used in any projects commissioned by, endorsed by, or developed for military organizations or their contractors. + +### 1e. Attribution Required The Licensee must publicly display appropriate credit to the Licensor for the Content, but not in any way that suggests the Licensor endorses the Licensee or the Licensee's use, unless the Licensor has given prior written consent. -Attribution can be accomplished by maintaining the "made with p5play" Loading Screen, which is enabled by default, or in any reasonable manner. +Use of the "made with p5play" Loading Screen is required for all published work that uses p5play, unless the work is published on an online code editing platform or other web app that was approved by the Licensor to be exempt from this requirement, in which case the loading screen will not appear. Attribution can then be made at the top of the primary script file or in a README file. The following is an example of acceptable attribution: + +```js +/** + * Made with p5play! + * https://p5play.org + */ +``` + +## 2. Licensee Eligibility Requirements + +The License is granted on a subscription basis through one of the following payment plans: + +- Per-semester payments (default) +- Annual payments +- Custom payment arrangements + +Renewal requires: + +- Additional payment before the end of the current term +- Updated student enrollment numbers +- Compliance with all license terms + +Custom payment arrangements must be negotiated directly with the Licensor and the Licensor will define what use is permitted under the custom arrangement. -## 4. No Warranty +The Licensee must pay the appropriate amount, as determined by the Licensor, for the quantity of students that will be using the Content. If Licensees have any concerns about what amount is appropriate for their use, they must contact the Licensor. + +Individuals over the age of 18 can pay licensing fees for their own educational use. + +Parental guardians or other adults can make purchases on behalf of a user that's a minor, and are responsible for ensuring compliance with this Agreement. + +A Licensee can pay more than the required amount if they wish to support the Licensor's work to a greater extent, which is greatly appreciated. + +Note that the Licensor reserves the right to change the cost of renewing this license agreement at any time. + +## 3. Licensee Consent + +Licensees optionally consent to p5play using Google Analytics to track how they use p5play. To revoke this consent, you can use a browser extension to block Google Analytics or set `window._p5play_gtagged = false;` before loading p5play. + +## 4. "Learn p5play" Interactive Textbook Access + +The Licensee is also granted the right to use the [p5play.org Learn pages](https://p5play.org/learn) for instructional purposes in class or coursework and in educational settings, including but not limited to schools, home schools, universities, coding bootcamps, and online tutoring. + +## 5. Supplemental Materials + +Supplemental Materials, such as the p5play-ios app template and p5play Game Design Fundamentals curriculum, are provided exclusively to authorized Licensees. These materials are intended to enhance the use of the Content and are not to be redistributed or used outside the scope of this Agreement. + +## 6. No Warranty The Content is provided "as is." The Licensor makes no warranties, express or implied, including without limitation any implied warranty of merchantability or fitness for a particular purpose, concerning the Content. -## 5. Limitation of Liability +If the Licensee has any issues with the Content, they must contact the Licensor. -If Licensee has any issues with the Content, they must contact the Licensor at info@p5play.org. The Licensor will make a reasonable effort to resolve the issue in a timely manner. +If the Licensee is not satisfied with the Content, it is their responsibility to discontinue use of the Content. -If the Licensee is not satisfied with the Content, it is their responsibility to discontinue use of the Content and terminate their renewal of this Agreement. +## 7. Limitation of Liability The Licensor shall not be liable for any damages suffered by the Licensee resulting from the use or inability to use the Content. -## 6. Termination +Licensees must comply with all applicable laws and regulations when using p5play. It is illegal to create content that infringes on the rights of others. Licensees are fully liable for any content they create with p5play. + +## 8. Termination Termination of the Agreement will occur if the Licensee fails to comply with any term(s) of this Agreement. Therefore, termination can occur automatically, without notice from the Licensor. -Any lapse in licensing payments will result in the immediate termination of this Agreement. +Note that the Licensor reserves the right to change the cost of renewing this license at any time. Any lapse in licensing payments will result in the immediate termination of this Agreement. + +## 9. Entire Agreement -## 7. Entire Agreement +This Agreement constitutes the entire agreement between the parties and supersedes all prior understandings and agreements, whether written or oral, relating to the subject matter of this Agreement. -This Agreement constitutes the entire agreement between the parties and supersedes all prior understandings and agreements, whether written or oral, relating to the subject matter of this Agreement. This Agreement can be amended by the Licensor at any time. If any provision of this Agreement is found to be invalid or unenforceable, the remaining provisions will remain in full force and effect. +This Agreement can be amended by the Licensor at any time. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. diff --git a/v3/p5play.d.ts b/v3/p5play.d.ts index ff669099..4944d3bf 100644 --- a/v3/p5play.d.ts +++ b/v3/p5play.d.ts @@ -2678,17 +2678,32 @@ class RopeJoint extends Joint { */ get maxLength(): number; } -class GrabJoint extends Joint { - constructor(spriteA: any, pos: any); - set target(pos: { - x: any; - y: any; - }); - get target(): { - x: any; - y: any; - }; - set maxForce(val: any); +/** + * @class + * @extends Joint + */ +class GrabberJoint extends Joint { + /** + * A Grabber joint enables you to grab sprites and move them with + * a max force towards a target position. + * + * @param {Sprite} sprite - the sprite to grab + */ + constructor(sprite: Sprite); + set target(pos: any); + /** + * The target position of the joint that the sprite will be + * moved towards. Must be an object with x and y properties. + * @type {Object} + */ + get target(): any; + set maxForce(val: number); + /** + * The maximum force that the joint can exert on the sprite. + * @type {Number} + * @default 1000 + */ + get maxForce(): number; } class Scale { valueOf(): any; diff --git a/v3/p5play.js b/v3/p5play.js index bd3d7a83..6f31c35b 100644 --- a/v3/p5play.js +++ b/v3/p5play.js @@ -1,8 +1,7 @@ /** * p5play - * @version 3.24 + * @version 3.25 * @author quinton-ashley - * @license AGPL-3.0 */ if (typeof planck != 'object') { @@ -34,10 +33,7 @@ p5.prototype.registerMethod('init', function p5playInit() { }; gtag('js', new Date()); gtag('config', 'G-EHXNCTSYLK'); - gtag('event', 'p5play_v3_24'); - if (location.hostname == 'codehs.com' || location.hostname == 'static1.codehs.com') { - gtag('event', 'codehs'); - } + gtag('event', 'p5play_v3_25'); }; } @@ -8225,41 +8221,64 @@ p5.prototype.registerMethod('init', function p5playInit() { } }; - this.GrabJoint = class extends this.Joint { - constructor(spriteA, pos) { - if (typeof pos != 'object') pos = mouse; + /** + * @class + * @extends Joint + */ + this.GrabberJoint = class extends this.Joint { + /** + * A Grabber joint enables you to grab sprites and move them with + * a max force towards a target position. + * + * @param {Sprite} sprite - the sprite to grab + */ + constructor(sprite) { + super(sprite, sprite, 'grab'); - super(spriteA, spriteA, 'grab'); + this._target = { x: 0, y: 0 }; + this.__target = new pl.Vec2(0, 0); let j = pl.MouseJoint( { - maxForce: 1e3, + maxForce: 1000, frequencyHz: 3, dampingRatio: 0.9, - target: spriteA.body.getPosition() + target: sprite.body.getPosition() }, - spriteA.body, - spriteA.body, - new pl.Vec2(pos.x / $.world.meterSize, pos.y / $.world.meterSize) + sprite.body, + sprite.body ); this._createJoint(j); - - this._target = { x: pos.x, y: pos.y }; } _draw() { $.line(this.spriteA.x, this.spriteA.y, this._target.x, this._target.y); } + /** + * The target position of the joint that the sprite will be + * moved towards. Must be an object with x and y properties. + * @type {Object} + */ get target() { return this._target; } set target(pos) { - let x = (this._target.x = pos.x); - let y = (this._target.y = pos.y); - this._j.setTarget(new pl.Vec2(x / $.world.meterSize, y / $.world.meterSize)); + this._target.x = pos.x; + this._target.y = pos.y; + this.__target.x = pos.x / $.world.meterSize; + this.__target.y = pos.y / $.world.meterSize; + this._j.setTarget(this.__target); } + /** + * The maximum force that the joint can exert on the sprite. + * @type {Number} + * @default 1000 + */ + get maxForce() { + return this._j.getMaxForce(); + } set maxForce(val) { this._j.setMaxForce(val); } @@ -10700,21 +10719,6 @@ p5.prototype.registerMethod('post', function p5playPostDraw() { // called after each draw function call $.p5play._inPostDraw = true; - if (window?.location?.hostname.endsWith('codehs.com')) { - $.background('yellow'); - $.fill('black'); - $.textSize(14); - $.textAlign($.LEFT, $.BASELINE); - $.text( - "CodeHS is currently prohibited from using p5play.\n\nCodeHS has failed to comply with p5play's AGPL license since January 11, 2024. CodeHS was notified on September 13, 2024 and acknowledged that their closed source, commercial use of p5play on codehs.com requires a proprietary license. Since then, CodeHS has tried to avoid or delay making a deal for too long.\n\nSoftware theft is a violation of the Digital Millennium Copyright Act.\n\nContact CodeHS Support to voice your frustration with this disruption in service. Contact info@p5play.org for more information.", - 12, - 12, - 300 - ); - $.noLoop(); - return; - } - if ($.allSprites.autoCull) { $.allSprites.cull(10000); } diff --git a/v3/p5play.min.js b/v3/p5play.min.js index b67e6212..a0824890 100644 --- a/v3/p5play.min.js +++ b/v3/p5play.min.js @@ -1,7 +1 @@ -/** - * p5play - * @version 3.24 - * @author quinton-ashley - * @license AGPL-3.0 - */ -if("object"!=typeof planck){if("object"!=typeof process)throw"planck.js must be loaded before p5play";global.planck=require("./planck.min.js")}p5.prototype.registerMethod("init",(function(){const t=this,e=planck;if("object"!=typeof process&&0!=window._p5play_gtagged){let t=document.createElement("script");t.src="https://www.googletagmanager.com/gtag/js?id=G-EHXNCTSYLK",t.async=!0,document.head.append(t),window._p5play_gtagged=!0,t.onload=()=>{window.dataLayer??=[],window.gtag=function(){dataLayer.push(arguments)},gtag("js",new Date),gtag("config","G-EHXNCTSYLK"),gtag("event","p5play_v3_24"),"codehs.com"!=location.hostname&&"static1.codehs.com"!=location.hostname||gtag("event","codehs")}}const i=t.DEGREES;t.angleMode(i);const s=(i,s,r)=>new e.Vec2(i*r/t.world.meterSize,s*r/t.world.meterSize),r=(i,s,r)=>new e.Vec2(i/r*t.world.meterSize,s/r*t.world.meterSize),o=e.Settings.linearSlop,h=e.Settings.angularSlop/60,a=t=>Math.abs(t)<=o,n=(t,e)=>Math.abs(t-Math.round(t))<=(e||o)?Math.round(t):t,l=(e,s)=>{let r=t._angleMode==i?360:t.TWO_PI,o=(e-s)%r,h=(r-Math.abs(o))*-Math.sign(o);return(Math.abs(o)-1){let e=navigator.userAgent.substring(t+10,t+12);this.os.platform="iOS",this.os.version=e}else{let t=navigator.userAgentData?.platform;!t&&navigator.platform&&(t=navigator.platform.slice(3),"Mac"==t?t="macOS":"Win"==t?t="Windows":"Lin"==t&&(t="Linux")),this.os.platform=t}}this.renderStats=!1,this._renderStats={x:10,y:20,font:"monospace"},this._fps=60,this._fpsArr=[60],this._collides={},this._colliding={},this._collided={},this._overlaps={},this._overlapping={},this._overlapped={}}onImageLoad(){}},this.p5play=new t.P5Play,delete t.P5Play;const p=console.log;this.log=console.log,this.Sprite=class{constructor(i,s,r,o,h){this._isSprite=!0,this.idNum;let a,l,d=[...arguments];if(void 0!==d[0]&&d[0]._isGroup&&(a=d[0],d=d.slice(1)),void 0!==d[0]&&("string"==typeof d[0]||d[0]instanceof t.Ani||d[0]instanceof p5.Image)&&(l=d[0],d=d.slice(1)),1==d.length&&"number"==typeof d[0])throw new C("Sprite",0,[d[0]]);if(Array.isArray(d[0])){if(i=void 0,s=void 0,r=d[0],o=void 0,h=d[1],Array.isArray(h))throw new C("Sprite",1,[`[[${r}], [${o}]]`])}else i=d[0],s=d[1],r=d[2],o=d[3],h=d[4];"string"==typeof r&&(h=r,r=void 0),"string"==typeof o&&(!function(t){if("d"==t||"s"==t||"k"==t||"n"==t)return!0;let e=t.slice(0,2);return"dy"==e||"st"==e||"ki"==e||"no"==e}(o)?r=_(r,o):h=o,o=void 0),this.idNum=t.p5play.spritesCreated,this._uid=1e3+this.idNum,t.p5play.sprites[this._uid]=this,t.p5play.spritesCreated++,this.groups=[],this.animations=new t.Anis,this.joints=[],this.joints.removeAll=()=>{for(;this.joints.length;)this.joints.at(-1).remove()},this.watch,this.mod={},this._removed=!1,this._life=2147483647,this._visible=!0,this._pixelPerfect=!1,this._aniChangeCount=0,this._draw=()=>this.__draw(),this._hasOverlap={},this._collisions={},this._overlappers={},a??=t.allSprites,this._tile="",this.tileSize=a.tileSize||1;let p=this;this._position={x:0,y:0},this._pos=t.createVector.call(t),Object.defineProperty(this._pos,"x",{get(){if(!p.body)return p._position.x;let e=p.body.getPosition().x/p.tileSize*t.world.meterSize;return t.p5play.friendlyRounding?n(e):e},set(i){if(p.body){let s=new e.Vec2(i*p.tileSize/t.world.meterSize,p.body.getPosition().y);p.body.setPosition(s)}p._position.x=i}}),Object.defineProperty(this._pos,"y",{get(){if(!p.body)return p._position.y;let e=p.body.getPosition().y/p.tileSize*t.world.meterSize;return t.p5play.friendlyRounding?n(e):e},set(i){if(p.body){let s=new e.Vec2(p.body.getPosition().x,i*p.tileSize/t.world.meterSize);p.body.setPosition(s)}p._position.y=i}}),this._canvasPos=t.createVector.call(t),Object.defineProperty(this._canvasPos,"x",{get(){let e=p._pos.x-t.camera.x;return"2d"==t.canvas.renderer&&(e+=t.canvas.hw/t.camera._zoom),e}}),Object.defineProperty(this._canvasPos,"y",{get(){let e=p._pos.y-t.camera.y;return"2d"==t.canvas.renderer&&(e+=t.canvas.hh/t.camera._zoom),e}}),this._velocity={x:0,y:0},this._direction=0,this._vel=t.createVector.call(t),Object.defineProperties(this._vel,{x:{get(){let e;return e=p.body?p.body.getLinearVelocity().x:p._velocity.x,e/=p.tileSize,t.p5play.friendlyRounding?n(e):e},set(t){t*=p.tileSize,p.body?p.body.setLinearVelocity(new e.Vec2(t,p.body.getLinearVelocity().y)):p._velocity.x=t,(t||this.y)&&(p._direction=this.heading())}},y:{get(){let e;return e=p.body?p.body.getLinearVelocity().y:p._velocity.y,e/=p.tileSize,t.p5play.friendlyRounding?n(e):e},set(t){t*=p.tileSize,p.body?p.body.setLinearVelocity(new e.Vec2(p.body.getLinearVelocity().x,t)):p._velocity.y=t,(t||this.x)&&(p._direction=this.heading())}}}),this._mirror={_x:1,_y:1,get x(){return this._x<0},set x(t){p.watch&&(p.mod[20]=!0),this._x=t?-1:1},get y(){return this._y<0},set y(t){p.watch&&(p.mod[20]=!0),this._y=t?-1:1}},this._heading="right",this._layer=a._layer,this._layer??=t.allSprites._getTopLayer()+1,a.dynamic&&(h??="dynamic"),a.kinematic&&(h??="kinematic"),a.static&&(h??="static"),h??=a.collider,h&&"string"==typeof h||(h="dynamic"),this.collider=h,i??=a.x,void 0===i&&(i="2d"!=t.canvas?.renderer||t._webgpuFallback?0:t.canvas.hw/this.tileSize,r&&(this._vertexMode=!0)),s??=a.y,void 0===s&&(s="2d"!=t.canvas?.renderer||t._webgpuFallback?0:t.canvas.hh/this.tileSize);let g=!1;if(void 0===r&&(r=a.w||a.width||a.d||a.diameter||a.v||a.vertices,o||a.d||a.diameter||(o=a.h||a.height,g=!0)),"function"==typeof i&&(i=i(a.length)),"function"==typeof s&&(s=s(a.length)),"function"==typeof r&&(r=r(a.length)),"function"==typeof o&&(o=o(a.length)),this.x=i,this.y=s,!a._isAllSpritesGroup&&!l){for(let t in a.animations){l=t;break}l||(l=a._img,"function"==typeof l&&(l=l(a.length)),l&&(this._img=!0))}for(let e=a;e;e=t.p5play.groups[e.parent])this.groups.push(e);if(this.groups.reverse(),l){let e=this.tileSize;this._img||l instanceof p5.Image?(this.image="string"!=typeof l?l:new t.EmojiImage(l,r),r||1==this._img.w&&1==this._img.h||(r=(this._img.defaultWidth||this._img.w)/e,o??=(this._img.defaultHeight||this._img.h)/e)):("string"==typeof l?this._changeAni(l):this._ani=l.clone(),r||1==this._ani.w&&1==this._ani.h||(r=(this._ani.defaultWidth||this._ani.w)/e,o??=(this._ani.defaultHeight||this._ani.h)/e))}if(this.groups=[],this.mouse=new t._SpriteMouse,this._rotation=0,this._rotationSpeed=0,this._bearing=0,this._scale=new u,Object.defineProperty(this._scale,"x",{get(){return this._x},set(t){if(t==this._x)return;p.watch&&(p.mod[26]=!0);let e=Math.abs(t/this._x);p._w*=e,p._hw*=e,p._resizeColliders({x:e,y:1}),this._x=t,this._avg=.5*(this._x+this._y)}}),Object.defineProperty(this._scale,"y",{get(){return this._y},set(t){if(t==this._y)return;p.watch&&(p.mod[26]=!0);let e=Math.abs(t/this._y);p._h&&(this._h*=e,this._hh*=e),p._resizeColliders({x:1,y:e}),this._y=t,this._avg=.5*(this._x+this._y)}}),this._offset={_x:0,_y:0,get x(){return this._x},set x(t){t!=this._x&&(p.watch&&(p.mod[21]=!0),p._offsetCenterBy(t-this._x,0))},get y(){return this._y},set y(t){t!=this._y&&(p.watch&&(p.mod[21]=!0),p._offsetCenterBy(0,t-this._y))}},this._massUndef=!0,void 0===r&&(this._dimensionsUndef=!0,this._widthUndef=!0,r=this.tileSize>1?1:50,void 0===o&&(this._heightUndef=!0)),g&&(o??=this.tileSize>1?1:50),this._shape=a.shape,3!=this.__collider)this._vertexMode?this.addCollider(r):this.addCollider(0,0,r,o),this.shape=this._shape;else{if(this.w=r,Array.isArray(r))throw new Error('Cannot set the collider type of a sprite with a polygon or chain shape to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');void 0!==r&&void 0===o?this.shape="circle":(this.shape="box",this.h=o)}this.prevPos={x:i,y:s},this.prevRotation=0,this._dest={x:i,y:s},this._destIdx=0,this._debug=!1,this.text,a._isAllSpritesGroup||t.allSprites.push(this),a.push(this);let f=a.vel.x||0,m=a.vel.y||0;"function"==typeof f&&(f=f(a.length-1)),"function"==typeof m&&(m=m(a.length-1)),this.vel.x=f,this.vel.y=m;let y=["ani","collider","x","y","w","h","d","diameter","dynamic","height","kinematic","static","vel","width"];for(let e of t.Sprite.propsAll){if(y.includes(e))continue;let i=a[e];void 0!==i&&("function"==typeof i&&c(i)&&(i=i(a.length-1)),"object"==typeof i?i instanceof p5.Color?this[e]=t.color(...i.levels):this[e]=Object.assign({},i):this[e]=i)}y=["add","animation","animations","autoCull","contains","GroupSprite","Group","idNum","length","mod","mouse","p","parent","Sprite","Subgroup","subgroups","velocity"];for(let e=0;e1?1:50,h??=o,d=s(o-.08,h-.08,this.tileSize)),"box"==l)p=e.Box(d.x/2,d.y/2,s(i,r,this.tileSize),0);else if("circle"==l)p=e.Circle(s(i,r,this.tileSize),d.x/2);else if(n){let c,g,f=[{x:0,y:0}],m={x:0,y:0},y={x:0,y:0},w={x:0,y:0},v=Array.isArray(n[0]);function x(){m.xw.x&&(w.x=m.x),m.y>w.y&&(w.y=m.y)}if(v){this._vertexMode&&(c=n[0][0],g=n[0][1],this.fixture&&this._relativeOrigin?(c=this.x-this._relativeOrigin.x,g=this.y-this._relativeOrigin.y,f.pop()):(this.x=c,this.y=g));for(let S=0;S0?1:-1;A=Math.abs(A);let k=0;for(let M=0;Me.Settings.maxPolygonVertices||"chain"==this._shape)&&(l="chain"),"polygon"==l?p=e.Polygon(f):"chain"==l&&(p=e.Chain(f,!1))}if(this.shape??=l,this.fixtureList){this._extents??={t:this.hh,b:this.hh,l:this._hw,r:this._hw};let G=this._extents,N=i-.5*o,E=i+.5*o,R=r-.5*h,U=r+.5*h;NG.r&&(G.r=E),RG.b&&(G.b=U),this._totalWidth=G.r-G.l,this._totalHeight=G.b-G.t;let V=Math.abs;this._largestExtent=Math.max(V(G.l),V(G.r),V(G.t),V(G.b))}else this._w=o,this._hw=.5*o,1!=this.__shape&&(this._h=h,this._hh=.5*h);return p}removeColliders(){this.body&&(this._removeContacts(0),this._removeFixtures(0))}removeSensors(){this.body&&(this._removeContacts(1),this._removeFixtures(1),this._hasSensors=!1)}_removeFixtures(e){let i;for(let s=this.fixtureList;s;s=s.getNext())if(void 0===e||s.m_isSensor==e){let e=s.m_next;s.destroyProxies(t.world.m_broadPhase),i?i.m_next=e:this.body.m_fixtureList=e}else i=s}_removeContacts(e){if(!this.body)return;let i=this.body.m_contactList;for(;i;){let s=i.contact;i=i.next,void 0!==e&&s.m_fixtureA.m_isSensor!=e||t.world.destroyContact(s)}}_offsetCenterBy(t,e){if(!t&&!e)return;if(this._offset._x+=t,this._offset._y+=e,!this.body)return;let i=s(t,e,this.tileSize);this.__offsetCenterBy(i.x,i.y)}__offsetCenterBy(t,e){for(let i=this.body.m_fixtureList;i;i=i.m_next){let s=i.m_shape;if("circle"!=s.m_type){let i=s.m_vertices;for(let s of i)s.x+=t,s.y+=e}else s.m_p.x+=t,s.m_p.y+=e}}_cloneBodyProps(){let t={},e=["bounciness","density","drag","friction","heading","isSuperFast","rotation","rotationDrag","rotationLock","rotationSpeed","scale","vel","x","y"];this._massUndef&&this._dimensionsUndef||e.push("mass");for(let i of e)"object"==typeof this[i]?t[i]=Object.assign({},this[i]):t[i]=this[i];return t}get animation(){return this._ani}set animation(t){this.changeAni(t)}get ani(){return this._ani}set ani(t){this.changeAni(t)}get anis(){return this.animations}get autoDraw(){return this._autoDraw}set autoDraw(t){this._autoDraw=t}get allowSleeping(){return this.body?.isSleepingAllowed()}set allowSleeping(t){this.watch&&(this.mod[5]=!0),this.body&&this.body.setSleepingAllowed(t)}get autoUpdate(){return this._autoUpdate}set autoUpdate(t){this._autoUpdate=t}get bounciness(){if(this.fixture)return this.fixture.getRestitution()}set bounciness(t){this.watch&&(this.mod[7]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setRestitution(t)}get collider(){return this._collider}set collider(e){if(e==this._collider)return;let i=(e=e.toLowerCase())[0];if("d"==i&&(e="dynamic"),"s"==i&&(e="static"),"k"==i&&(e="kinematic"),"n"==i&&(e="none"),e==this._collider)return;if("none"==e&&("chain"==this._shape||"polygon"==this._shape))return void console.error('Cannot set the collider type of a polygon or chain collider to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');if(this._removed)throw new Error("Cannot change the collider type of a sprite that was removed.");let s=this.__collider;this._collider=e,this.__collider=["d","s","k","n"].indexOf(i),this.watch&&(this.mod[8]=!0),void 0!==s&&(3!=this.__collider?(this.body&&this.body.setType(e),3==s&&(this.addCollider(),this.x=this._position.x,this.y=this._position.y,this.vel.x=this._velocity.x,this.vel.y=this._velocity.y,this.rotation=this._rotation,this.rotationSpeed=this._rotationSpeed)):(this.removeColliders(),this.fixture?.m_isSensor?this.body.m_gravityScale=0:(this._position.x=this.x,this._position.y=this.y,this._velocity.x=this.vel.x,this._velocity.y=this.vel.y,this._rotation=this.rotation,this._rotationSpeed=this.rotationSpeed,t.world.destroyBody(this.body),this.body=null)))}_parseColor(e){return e instanceof p5.Color?e:"object"!=typeof e?1==e.length?t.colorPal(e):t.color(e):t.color(...e.levels)}get color(){return this._color}set color(t){this.watch&&(this.mod[9]=!0),this._color=this._parseColor(t)}get colour(){return this._color}set colour(t){this.color=t}get fill(){return this._color}set fill(t){this.color=t}get fillColor(){return this._color}set fillColor(t){this.color=t}get stroke(){return this._stroke}set stroke(t){this.watch&&(this.mod[29]=!0),this._stroke=this._parseColor(t)}get strokeColor(){return this._stroke}set strokeColor(t){this.stroke=t}get strokeWeight(){return this._strokeWeight}set strokeWeight(t){this.watch&&(this.mod[30]=!0),this._strokeWeight=t}get textColor(){return this._textFill}set textColor(t){this.watch&&(this.mod[32]=!0),this._textFill=this._parseColor(t)}get textColour(){return this._textFill}set textColour(t){this.textColor=t}get textFill(){return this._textFill}set textFill(t){this.textColor=t}get textSize(){return this._textSize}set textSize(t){this.watch&&(this.mod[33]=!0),this._textSize=t}get textStroke(){return this._textStroke}set textStroke(t){this.watch&&(this.mod[34]=!0),this._textStroke=this._parseColor(t)}get textStrokeWeight(){return this._textStrokeWeight}set textStrokeWeight(t){this.watch&&(this.mod[35]=!0),this._textStrokeWeight=t}get tile(){return this._tile}set tile(t){this.watch&&(this.mod[36]=!0),this._tile=t}get tileSize(){return this._tileSize}set tileSize(t){this.watch&&(this.mod[37]=!0),this._tileSize=t}get bearing(){return this._bearing}set bearing(t){this.watch&&(this.mod[6]=!0),this._bearing=t}get debug(){return this._debug}set debug(t){this.watch&&(this.mod[10]=!0),this._debug=t}get density(){if(this.fixture)return this.fixture.getDensity()}set density(t){this.watch&&(this.mod[11]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setDensity(t)}_getDirectionAngle(e){e=e.toLowerCase().replaceAll(/[ _-]/g,"");let i={up:-90,down:90,left:180,right:0,upright:-45,rightup:-45,upleft:-135,leftup:-135,downright:45,rightdown:45,downleft:135,leftdown:135,forward:this.rotation,backward:this.rotation+180}[e];return"radians"==t._angleMode&&(i=t.radians(i)),i}get direction(){return 0!==this.vel.x||0!==this.vel.y?t.atan2(this.vel.y,this.vel.x):this._isTurtleSprite?this.rotation:this._direction}set direction(e){this.watch&&(this.mod[12]=!0),"string"==typeof e&&(this._heading=e,e=this._getDirectionAngle(e)),this._direction=e,this._isTurtleSprite&&(this.rotation=e);let i=this.speed;this.vel.x=t.cos(e)*i,this.vel.y=t.sin(e)*i}get drag(){return this.body?.getLinearDamping()}set drag(t){this.watch&&(this.mod[13]=!0),this.body&&this.body.setLinearDamping(t)}get draw(){return this._display}set draw(t){this._userDefinedDraw=!0,this._draw=t}get dynamic(){return this.body?.isDynamic()}set dynamic(t){this.collider=t?"dynamic":"kinematic"}get fixture(){return this.fixtureList}get fixtureList(){return this.body?this.body.m_fixtureList:null}get friction(){if(this.fixture)return this.fixture.getFriction()}set friction(t){this.watch&&(this.mod[14]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setFriction(t)}get heading(){return this._heading}set heading(t){this.direction=t}get img(){return this._img||this._ani?.frameImage}set img(t){this.image=t}get image(){return this._img||this._ani?.frameImage}set image(e){"string"==typeof e&&(e=e.includes(".")?t.loadImage(e):new t.EmojiImage(e,this.w)),this._img=this._extendImage(e)}_extendImage(t){return t.offset??={x:0,y:0},t._scale??={x:1,y:1},t.scale||Object.defineProperty(t,"scale",{get:()=>t._scale,set:e=>{"number"==typeof e&&(e={x:e,y:e}),t._scale=e}}),t}get isMoving(){return 0!=this.vel.x||0!=this.vel.y}get isSuperFast(){return this.body?.isBullet()}set isSuperFast(t){this.watch&&(this.mod[16]=!0),this.body&&this.body.setBullet(t)}get kinematic(){return this.body?.isKinematic()}set kinematic(t){this.collider=t?"kinematic":"dynamic"}get layer(){return this._layer}set layer(t){this.watch&&(this.mod[17]=!0),this._layer=t}get life(){return this._life}set life(t){this.watch&&(this.mod[18]=!0),this._life=t}get mass(){return this.body?.getMass()}set mass(t){if(!this.body)return;this.watch&&(this.mod[19]=!0);const i={I:0,center:new e.Vec2(this.body.getLocalCenter()),mass:0};this.body.getMassData(i),i.mass=t>0?t:1e-8,this.body.setMassData(i),delete this._massUndef}resetMass(){if(!this.body)return;let t=new e.Vec2(this.body.getLocalCenter());this.watch&&(this.mod[19]=!0),this.body.resetMassData(),this.body.setMassData({mass:this.body.getMass(),center:t,I:this.body.getInertia()})}resetCenterOfMass(){this.watch&&(this.mod[19]=!0),this.body.resetMassData();let{x:t,y:e}=this.body.getLocalCenter();if(0==t&&0==e)return;this.__offsetCenterBy(-t,-e),this.body.resetMassData();let i=this.body.getPosition();this.body.setPosition({x:i.x+t,y:i.y+e})}get mirror(){return this._mirror}set mirror(t){this.watch&&(this.mod[20]=!0),void 0!==t.x&&(this._mirror.x=t.x),void 0!==t.y&&(this._mirror.y=t.y)}get offset(){return this._offset}set offset(t){t.x??=this._offset._x,t.y??=this._offset._y,t.x==this._offset._x&&t.y==this._offset._y||(this.watch&&(this.mod[21]=!0),this._offsetCenterBy(t.x-this._offset._x,t.y-this._offset._y))}get opacity(){return this._opacity??1}set opacity(t){this.watch&&(this.mod[41]=!0),this._opacity=t}get previousPosition(){return this.prevPos}set previousPosition(t){this.prevPos=t}get previousRotation(){return this.prevRotation}set previousRotation(t){this.prevRotation=t}get pixelPerfect(){return this._pixelPerfect}set pixelPerfect(t){this.watch&&(this.mod[22]=!0),this._pixelPerfect=t}get removed(){return this._removed}set removed(t){t&&!this._removed&&(this.watch&&(this.mod[23]=!0),this._removed=!0,this._remove())}get rotation(){if(!this.body)return this._rotation||0;let e=this.body.getAngle();return e=t.p5play.friendlyRounding?n(e,h):e,t._angleMode==i&&(e=t.degrees(e)),e}set rotation(e){this.body?(t._angleMode==i&&(e=t.radians(e%360)),this.body.setAngle(e),this.body.synchronizeTransform()):this._rotation=e}get rotationDrag(){return this.body?.getAngularDamping()}set rotationDrag(t){this.body&&(this.watch&&(this.mod[24]=!0),this.body.setAngularDamping(t))}get rotationLock(){return this.body?.isFixedRotation()}set rotationLock(t){if(!this.body)return;this.watch&&(this.mod[25]=!0);let e=this.mass;this.body.setFixedRotation(t),this.mass=e}get rotationSpeed(){if(this.body){let e=this.body.getAngularVelocity()/60;return t._angleMode==i?t.degrees(e):e}return this._rotationSpeed}set rotationSpeed(e){this.body?(e*=60,t._angleMode==i&&(e=t.radians(e)),this.body.setAngularVelocity(e)):this._rotationSpeed=e}get scale(){return this._scale}set scale(t){if(0==t&&(t=.01),"number"==typeof t?t={x:t,y:t}:(t.x??=this._scale._x,t.y??=this._scale._y),t.x==this._scale._x&&t.y==this._scale._y)return;this.watch&&(this.mod[26]=!0);let e={x:Math.abs(t.x/this._scale._x),y:Math.abs(t.y/this._scale._y)};this._w*=e.x,this._hw*=e.x,this._h&&(this._h*=e.y,this._hh*=e.y),this._resizeColliders(e),this._scale._x=t.x,this._scale._y=t.y,this._scale._avg=t.x}get sleeping(){if(this.body)return!this.body.isAwake()}set sleeping(t){this.body&&(this.watch&&(this.mod[28]=!0),this.body.setAwake(!t))}get speed(){return t.createVector(this.vel.x,this.vel.y).mag()}set speed(e){let i=this.direction;this.vel.x=t.cos(i)*e,this.vel.y=t.sin(i)*e}get static(){return this.body?.isStatic()}set static(t){this.collider=t?"static":"dynamic"}get tint(){return this._tint}set tint(t){this.watch&&(this.mod[38]=!0),this._tint=this._parseColor(t)}get tintColor(){return this._tint}set tintColor(t){this.tint=t}set vertices(t){if(3==this.__collider)throw new Error('Cannot set vertices of a sprite with collider type of "none".');this.watch&&(this.mod[27]=!0),this._removeFixtures(),this._originMode="start",this.addCollider(t),this._hasSensors&&this.addDefaultSensors()}get vertices(){return this._getVertices()}_getVertices(e){let i=this.fixture.getShape(),s=[...i.m_vertices];"polygon"==i.m_type&&s.unshift(s.at(-1));let r=this.x,o=this.y;for(let i=0;i=2)return void console.error('Cannot set the collider shape to chain or polygon if the sprite has a collider type of "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');let s,r,o=this.__shape;if(this.__shape=i,this._shape=e,this.watch&&(this.mod[27]=!0),void 0===o)return;if(0==this.__shape?(this._h=this._w,this._hh=this._hw):(this._h=void 0,this._hh=void 0),1!=o&&1!=this.__shape?s=this._getVertices(!0):r=this._w,this._removeFixtures(),3!=this.__collider)if(s)this._originMode??="center",this.addCollider(s);else if(1==o){let t=this._w*Math.sin(Math.PI/12);this.addCollider(0,0,[t,-30,12])}else this.addCollider();this._hasSensors&&this.addDefaultSensors();let h=this._offset._x,a=this._offset._y;(h||a)&&(this._offset._x=0,this._offset._y=0,this._offsetCenterBy(h,a))}get update(){return this._update}set update(t){this._customUpdate=t}get vel(){return this._vel}set vel(t){this.vel.x=t.x,this.vel.y=t.y}get velocity(){return this._vel}set velocity(t){this.vel=t}get gravityScale(){return this.body?.getGravityScale()}set gravityScale(t){this.body&&(this.watch&&(this.mod[42]=!0),this.body.setGravityScale(t))}_update(){this._ani?.update&&this._ani.update();for(let t in this.mouse)-1==this.mouse[t]&&(this.mouse[t]=0);this._customUpdate&&this._customUpdate(),this.autoUpdate&&(this.autoUpdate=null)}_step(){this.life-=t.world.timeScale,2147483647!=this._life&&this._life<=0&&this.remove(),this.body||this._removed||(this.rotation+=this._rotationSpeed,this.x+=this.vel.x,this.y+=this.vel.y),this.watch&&(this.x!=this.prevX&&(this.mod[0]=this.mod[2]=!0),this.y!=this.prevY&&(this.mod[1]=this.mod[2]=!0),this.rotation!=this.prevRotation&&(this.mod[3]=this.mod[4]=!0)),(this.body||this._removed)&&this.__step()}__step(){let e,i=this;for(let s in d)for(let r in this[s]){if(r>=1e3){if(i._isGroup||i._uid>=r)continue;e=t.p5play.sprites[r]}else{if(i._isGroup&&i._uid>=r)continue;e=t.p5play.groups[r]}let o=i[s][r]+1;e&&0!=o&&-2!=o?(this[s][r]=o,e[s][i._uid]=o):(delete i[s][r],e&&delete e[s][i._uid])}}___step(){let e,i,s,r,o=this,h=!0;for(let a in d){for(let n in this[a]){if(n>=1e3){if(o._isGroup||o._uid>=n)continue;e=t.p5play.sprites[n]}else{if(o._isGroup&&o._uid>=n)continue;e=t.p5play.groups[n]}if(o._isGroup||e?._isGroup)continue;if(s=o._hasOverlap[e._uid]??e._hasOverlap[o._uid],h&&!1!==s||!h&&!0!==s)continue;let l=o[a][n];for(let s=0;s<3;s++){if(0==s&&1!=l&&-3!=l)continue;if(1==s&&-1==l)continue;if(2==s&&l>=1)continue;i=d[a][s];let h=t.p5play[i][o._uid];if(h){r=h[e._uid],r&&r.call(o,o,e,l);for(let t of e.groups)r=h[t._uid],r&&r.call(o,o,e,l)}let n=t.p5play[i][e._uid];if(n){r=n[o._uid],r&&r.call(e,e,o,l);for(let t of o.groups)r=n[t._uid],!r||h&&r==h[t._uid]||r.call(e,e,o,l)}}}h=!1}if(this._removed&&0==Object.keys(this._collisions).length&&0==Object.keys(this._overlappers).length){this._isSprite?delete t.p5play.sprites[this._uid]:t.p5play.storeRemovedGroupRefs||delete t.p5play.groups[this._uid];for(let e in d)for(let i of d[e])delete t.p5play[i][this._uid]}}__draw(){if(!t.p5play.disableImages)if(this._ani)this._ani.draw(this._offset._x,this._offset._y,0,this._scale._x,this._scale._y);else if(this._img){let e=this._img,i=1!=this._scale._x||1!=this._scale._y||1!=e.scale.x||1!=e.scale.y;i&&(t.push(),t.scale(this._scale._x*e.scale.x,this._scale._y*e.scale.y)),t.image(e,this._offset._x+e.offset.x,this._offset._y+e.offset.y),i&&t.pop()}if(!this._ani&&!this._img||this.debug||t.p5play.disableImages)if(this.debug&&(t.noFill(),t.stroke(0,255,0),t.line(0,-2,0,2),t.line(-2,0,2,0)),3!=this.__collider){this.debug||0===this._strokeWeight?t.noStroke():2==this.__shape?t.stroke(this.stroke||this.color):this._stroke&&t.stroke(this._stroke);for(let e=this.fixtureList;e;e=e.getNext()){if(this.debug)e.m_isSensor?t.stroke(255,255,0,127):t.stroke(0,255,0,127);else if(e.m_isSensor)continue;this._drawFixture(e)}}else 0!==this._strokeWeight&&t.stroke(this._stroke||120),0==this.__shape?t.rect(this._offset._x,this._offset._y,this.w*this.tileSize,this.h*this.tileSize):1==this.__shape&&t.circle(this._offset._x,this._offset._y,this.d*this.tileSize);void 0!==this.text&&(t.textAlign(t.CENTER,t.CENTER),t.fill(this._textFill),this._textStrokeWeight&&t.strokeWeight(this._textStrokeWeight),this._textStroke?t.stroke(this._textStroke):t.noStroke(),t.textSize(this.textSize*this.tileSize),t.text(this.text,0,0))}_display(){let e,i=this.x*this.tileSize+t.world.origin.x,s=this.y*this.tileSize+t.world.origin.y;if(!this._userDefinedDraw){let e;if(e=this._totalWidth?Math.max(this._totalWidth,this._totalHeight):void 0!==this._h?Math.max(this._w,this._h):this._w,this.ani&&!t.p5play.disableImages&&(e=Math.max(e,this.ani.w,this.ani.h)),"chain"!=this.shape&&t.camera.isActive&&(i+et.camera.bound.max.x||s+et.camera.bound.max.y))return void(this._visible=null)}if(this._visible=!0,t.p5play.spritesDrawn++,this._pixelPerfect){let e,r;this.ani&&this.ani.length&&!t.p5play.disableImages?(e=this.ani[this.ani._frame].w,r=this.ani[this.ani._frame].h):(e=this._w,r=this._h),i=e%2==0?Math.round(i):Math.round(i-.5)+.5,s=r%2==0?Math.round(s):Math.round(s-.5)+.5}else i=n(i),s=n(s);for(let t of this.joints)t.visible?this._uid==t.spriteA._uid?(!t.spriteB._visible||this.layer<=t.spriteB.layer)&&t._display():(!t.spriteA._visible||this.layer{let s,r;do{if(await t.sleep(),c!=this._destIdx)return!1;let o=this.direction<0?this.direction+360:this.direction;if(u&&(o<=n||o>=l)||Math.abs(this.vel.x)<=d&&Math.abs(this.vel.y)<=d)return!1;e&&(s=this.vel.x>0?this._dest.x-this.x:this.x-this._dest.x),i&&(r=this.vel.y>0?this._dest.y-this.y:this.y-this._dest.y)}while(e&&s>p||i&&r>p);return this.x=this._dest.x,this.y=this._dest.y,this.vel.x=0,this.vel.y=0,!0})()}rotateTowards(t,e){if(1==this.__collider)return void new C(0);let i,s,r,o=arguments;"number"!=typeof o[0]?(i=o[0].x,s=o[0].y,e=o[1],r=o[2]):arguments.length>2&&(i=o[0],s=o[1],e=o[2],r=o[3]),void 0!==i?t=this.angleToFace(i,s,r):t-=this.rotation,e??=.1,this.rotationSpeed=t*e}angleTo(e,i){if("object"==typeof e){let s=e;if(s==t.mouse&&!t.mouse.isActive)return 0;if(void 0===s.x||void 0===s.y)return console.error("sprite.angleTo ERROR: rotation destination not defined, object given with no x or y properties"),0;i=s.y,e=s.x}return t.atan2(i-this.y,e-this.x)}rotationToFace(t,e,i){return"object"==typeof t&&(i=e,e=t.y,t=t.x),Math.abs(t-this.x)<.01&&Math.abs(e-this.y)<.01?0:this.angleTo(t,e)+(i||0)}angleToFace(t,e,i){let s=this.rotationToFace(t,e,i);return l(s,this.rotation)}rotateTo(e,s,r){if(1==this.__collider)return void new C(0);let o=arguments;if("number"!=typeof o[0]?e=this.rotationToFace(o[0].x,o[0].y,r):o.length>2&&(r=o[3],s=o[2],e=this.rotationToFace(o[0],o[1],r)),e==this.rotation)return;let h=t._angleMode==i?360:t.TWO_PI;return(e=(e-this.rotation)%h)<0&&s>0&&(e+=h),e>0&&s<0&&(e-=h),s??=this.rotationSpeed||Math.sign(e),this.rotate(e,s)}rotateMinTo(t,e,i){if(1==this.__collider)return void new C(0);let s=arguments;return"number"!=typeof s[0]?t=this.rotationToFace(s[0].x,s[0].y,i):s.length>2&&(i=s[3],e=s[2],t=this.rotationToFace(s[0],s[1],i)),t!=this.rotation?(t=l(t,this.rotation),e??=this.rotationSpeed>.1?this.rotationSpeed:1,e=Math.abs(e)*Math.sign(t),this.rotate(t,e)):void 0}rotate(e,i){if(1==this.__collider)return void new C(0);if(isNaN(e))return void new C(1,[e]);if(0==e)return;i??=this.rotationSpeed||1;let s=e>0&&i>0;s||(e=-Math.abs(e),i=-Math.abs(i)),this.rotationSpeed=i;let r=Math.abs(i),o=this.rotation+e;this._rotateIdx??=0,this._rotateIdx++;let h=this._rotateIdx;return(async()=>{let e=.01;do{let a=Math.abs(o-this.rotation);if(r>a&&(this.rotationSpeed=a*Math.sign(i)),await t.sleep(),this._rotateIdx!=h)return!1;if(s&&this.rotationSpeed-.01)return!1}while((s&&o>this.rotation||!s&&o1)e=[...arguments];else if(e instanceof t.Ani){if(e==this._ani)return;e=[e]}else if(!Array.isArray(e)){if(e==this._ani?.name)return;e=[e]}let i,s;this._aniChangeCount++;for(let r=0;r1&&("!"==o.name[0]&&(o.name=o.name.slice(1),o.start=-1,o.end=0),"<"!=o.name[0]&&">"!=o.name[0]||(o.name=o.name.slice(1),o.flipX=!0),"^"==o.name[0]&&(o.name=o.name.slice(1),o.flipY=!0),"**"==o.name&&(i=!0,e=e.slice(0,-1)),";;"==o.name&&(s=!0,e=e.slice(0,-1)))}let r=this._aniChangeCount;do{for(let t=0;t1&&(i.start=0),await this._playSequencedAni(i)}}while(i&&r==this._aniChangeCount);1!=e.length&&s&&this._ani.stop()}_playSequencedAni(t){return new Promise((e=>{let{name:i,start:s,end:r,flipX:o,flipY:h}=t;this._changeAni(i),o&&(this._ani.scale.x=-this._ani.scale.x),h&&(this._ani.scale.y=-this._ani.scale.y),s<0&&(s=this._ani.length+s),void 0!==s&&(this._ani._frame=s),void 0!==r?this._ani.goToFrame(r):this._ani._frame==this._ani.lastFrame&&e(),this._ani._onComplete=this._ani._onChange=()=>{o&&(this._ani.scale.x=-this._ani.scale.x),h&&(this._ani.scale.y=-this._ani.scale.y),this._ani._onComplete=this._ani._onChange=null,e()}}))}changeAnimation(){return this.changeAni(...arguments)}_changeAni(e){this._ani?._onChange&&this._ani._onChange(),this._ani?.onChange&&this._ani.onChange();let i=this.animations[e];if(!i)for(let t=this.groups.length-1;t>=0;t--){if(i=this.groups[t].animations[e],i){i=i.clone();break}}if(!i)throw t.noLoop(),new C("Sprite.changeAnimation",[e]);this._ani=i,this._ani.name=e,this.resetAnimationsOnChange&&(this._ani._frame=0)}remove(){this.removed=!0}_remove(){this.body&&t.world.destroyBody(this.body),this.body=null;for(let t of this.groups)t.remove(this)}toString(){return"s"+this.idNum}_setContactCB(e,i,s,r){let o;o=0==s?d._collisions[r]:d._overlappers[r];let h=t.p5play[o],a=h[this._uid]??={};a[e._uid]!=i&&(a[e._uid]=i,a=h[e._uid],a&&a[this._uid]&&(delete a[this._uid],0==Object.keys(a).length&&delete h[e._uid]))}_validateCollideParams(t,e){if(!t)throw new C("Sprite.collide",2);if(!t._isSprite&&!t._isGroup)throw new C("Sprite.collide",0,[t]);if(e&&"function"!=typeof e)throw new C("Sprite.collide",1,[e])}_ensureCollide(t,e,i){if(!1!==this._hasOverlap[t._uid]&&(this._hasOverlap[t._uid]=!1),!1!==t._hasOverlap[this._uid]&&(t._hasOverlap[this._uid]=!1,t._isGroup))for(let e of t)e._hasOverlap[this._uid]=!1,this._hasOverlap[e._uid]=!1}collide(t,e){return this.collides(t,e)}collides(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,0),1==this._collisions[t._uid]||this._collisions[t._uid]<=-3}colliding(t,e){this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,1);let i=this._collisions[t._uid];return i<=-3?1:i>0?i:0}collided(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,2),this._collisions[t._uid]<=-1}_validateOverlapParams(t,e){if(!t)throw new C("Sprite.overlap",2);if(!t._isSprite&&!t._isGroup)throw new C("Sprite.overlap",0,[t]);if(e&&"function"!=typeof e)throw new C("Sprite.overlap",1,[e])}_ensureOverlap(t){if(this._hasSensors||this.addDefaultSensors(),!t._hasSensors)if(t._isSprite)t.addDefaultSensors();else{for(let e of t)e._hasSensors||e.addDefaultSensors();t._hasSensors=!0}if(this._hasOverlap[t._uid]||(this._removeContactsWith(t),this._hasOverlap[t._uid]=!0),!t._hasOverlap[this._uid]&&(t._removeContactsWith(this),t._hasOverlap[this._uid]=!0,t._isGroup))for(let e of t)e._hasOverlap[this._uid]=!0,this._hasOverlap[e._uid]=!0}overlap(t,e){return this.overlaps(t,e)}overlaps(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,0),1==this._overlappers[t._uid]||this._overlappers[t._uid]<=-3}overlapping(t,e){this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,1);let i=this._overlappers[t._uid];return i<=-3?1:i>0?i:0}overlapped(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,2),this._overlappers[t._uid]<=-1}_removeContactsWith(t){if(t._isGroup)for(let e of t)this._removeContactsWith(e);else this.__removeContactsWith(t)}__removeContactsWith(e){if(this.body)for(let i=this.body.getContactList();i;i=i.next){let s=i.contact;s.m_fixtureA.m_body.sprite._uid!=e._uid&&s.m_fixtureB.m_body.sprite._uid!=e._uid||t.world.destroyContact(s)}}_sortFixtures(){let t,e,i=null,s=null;for(let r=this.fixtureList;r;r=r.getNext())r.m_isSensor?(s?s.m_next=r:s=r,e=r):(i?i.m_next=r:i=r,t=r);s&&(e.m_next=null),i&&(t.m_next=s),this.body.m_fixtureList=i||s}addDefaultSensors(){let t;if(this.body&&this.fixtureList){for(let e=this.fixtureList;e;e=e.getNext())e.m_isSensor||(t=e.m_shape,this.body.createFixture({shape:t,isSensor:!0}));this._sortFixtures()}else this.addSensor();this._hasSensors=!0}distanceTo(e){return t.dist(this.x,this.y,e.x,e.y)}},t.Sprite.propTypes={x:"Float64",y:"Float64",vel:"Vec2",rotation:"number",rotationSpeed:"number",allowSleeping:"boolean",bearing:"number",bounciness:"number",collider:"Uint8",color:"color",debug:"boolean",density:"number",direction:"number",drag:"number",friction:"number",h:"number",isSuperFast:"boolean",layer:"number",life:"Int32",mass:"number",mirror:"Vec2_boolean",offset:"Vec2",pixelPerfect:"boolean",removed:"boolean",rotationDrag:"number",rotationLock:"boolean",scale:"Vec2",shape:"Uint8",sleeping:"boolean",stroke:"color",strokeWeight:"number",text:"string",textColor:"color",textSize:"number",textStroke:"color",textStrokeWeight:"number",tile:"string",tileSize:"number",tint:"color",visible:"boolean",w:"number",opacity:"number",gravityScale:"number"},t.Sprite.props=Object.keys(t.Sprite.propTypes),t.Sprite.propsAll=t.Sprite.props.concat(["autoDraw","autoUpdate","colour","d","diameter","dynamic","fill","height","heading","kinematic","resetAnimationsOnChange","speed","spriteSheet","static","textColour","textFill","width"]),t.Sprite.colliderTypes=["d","s","k","n"],t.Sprite.shapeTypes=["box","circle","chain","polygon"],t.Turtle=function(e){if(t.allSprites.tileSize>1)throw new Error("Turtle can't be used when allSprites.tileSize is greater than 1.");e??=25;let i=new t.Sprite(e,e,[[e,.4*e],[-e,.4*e],[0,.8*-e]]);i.color="green",i._isTurtleSprite=!0,i._prevPos={x:i.x,y:i.y};let s=i.move;return i.move=function(){return this._prevPos.x=this.x,this._prevPos.y=this.y,s.call(this,...arguments)},i},this.Ani=class extends Array{constructor(){super();let e,i=[...arguments];if(this.name="default","object"==typeof i[0]&&(i[0]._isSprite||i[0]._isGroup)&&(e=i[0],i=i.slice(1),this._addedToSpriteOrGroup=!0),e??=t.allSprites,"string"!=typeof i[0]||1!=i[0].length&&i[0].includes(".")||(this.name=i[0],i=i.slice(1)),this._frame=0,this._cycles=0,this.targetFrame=-1,this.offset={x:e.anis.offset.x??0,y:e.anis.offset.y??0},this._frameDelay=e.anis.frameDelay||4,this.demoMode=e.anis.demoMode??!1,this.playing=!0,this.visible=!0,this.looping=e.anis.looping??!0,this.endOnFirstFrame=e.anis.endOnFirstFrame??!1,this.frameChanged=!1,this.onComplete=this.onChange=null,this._onComplete=this._onChange=null,this.rotation=e.anis.rotation??0,this._scale=new u,0!=i.length&&"number"!=typeof i[0]){if(e.animations[this.name]=this,e._ani=this,Array.isArray(i[0])&&"string"==typeof i[0][0]&&(i=[...i[0]]),2!=i.length||"string"!=typeof i[0]||"string"!=typeof i[1]&&"number"!=typeof i[1])if("string"==typeof i.at(-1)||i.at(-1)instanceof p5.Image)for(let s=0;s=3)throw new C("Ani",1);o=i[0],r=i[1]}else r=i[0];let h=this;if(o instanceof p5.Image&&1!=o.width&&1!=o.height)this.spriteSheet=o,a();else{let n;n="string"==typeof o?o:o.url,t._incrementPreload(),this.spriteSheet=t.loadImage(n,(()=>{a(),t._decrementPreload()})),"string"==typeof o&&(e.spriteSheet=this.spriteSheet)}function a(){Array.isArray(r)&&(r="object"==typeof r[0]?{frames:r}:4==r.length?{pos:r.slice(0,2),size:r.slice(2)}:{pos:r});let{w:i,h:s,width:o,height:a,size:n,row:l,col:d,line:p,x:u,y:c,pos:_,frames:g,frameCount:f,frameDelay:m,frameSize:y,delay:w,rotation:v}=r;y??=n||e.anis.frameSize,w&&(h.frameDelay=w),m&&(h.frameDelay=m),v&&(h.rotation=v),g&&Array.isArray(g)?f=g.length:f??=g||1,i??=o||e.anis.w,s??=a||e.anis.h,u??=d||0,c??=p||l||0,_&&(u=_[0],c=_[1]),"number"==typeof y?i=s=y:y&&(i=y[0],s=y[1]);let x=e.tileSize;if(i&&s?(i*=x,s*=x):!e._dimensionsUndef&&e.w&&e.h?(i??=e.w*x,s??=e.h*x):1!=x?(i??=x,s??=x):f?(i??=h.spriteSheet.width/f,s??=h.spriteSheet.height):i=s=h.spriteSheet.width=h.spriteSheet.width&&(u=0,c+=s,c>=h.spriteSheet.height&&(c=0))}}}}else{let l,d,p=i[0];isNaN(i[1])?l=i[1]:d=Number(i[1]);let c=p.lastIndexOf("."),_=0,g=0;for(let w=c-1;w>=0&&!isNaN(p.charAt(w));w--)_++;if(l)for(let v=l.length-5;v>=0&&!isNaN(l.charAt(v));v--)g++;let f,m=p.slice(c),y=p.slice(0,c-_);if(l&&(f=l.slice(0,c-g)),l&&y!=f)this.push(t.loadImage(p)),this.push(t.loadImage(l));else{let x,b=parseInt(p.slice(c-_,c),10);if(d??=parseInt(l.slice(c-g,c),10),d=this.length)throw new C("Ani.frame",[t,this.length]);this._frame=t,this._cycles=0}get frameDelay(){return this._frameDelay}set frameDelay(t){t<=0&&(t=1),this._frameDelay=t}get scale(){return this._scale}set scale(t){"number"==typeof t&&(t={x:t,y:t}),this._scale._x=t.x,this._scale._y=t.y,this._scale._avg=t.x}clone(){this.length||console.error(`The animation named "${this.name}" must be loaded before it can be properly copied. Sprites need their own copy of a group's animation. Try loading the animation in the preload function and creating new group sprites in the setup function.`);let e=new t.Ani;e.spriteSheet=this.spriteSheet;for(let t=0;tthis._frame&&-1!==this.targetFrame?this._frame++:this.targetFrame=this.lastFrame?this._frame=0:this._frame++:this._frame{this._onComplete=()=>{this._onComplete=null,t()}}))}pause(t){this.playing=!1,t&&(this._frame=t)}stop(t){this.playing=!1,t&&(this._frame=t)}rewind(){return this.looping=!1,this.goToFrame(0)}loop(){this.looping=!0,this.playing=!0}noLoop(){this.looping=!1}nextFrame(){this._frame0?this._frame=this._frame-1:this.looping&&(this._frame=this.length-1),this.targetFrame=-1,this.playing=!1,this._cycles=0}goToFrame(t){if(!(t<0||t>=this.length))return this.targetFrame=t,this._cycles=0,this.targetFrame!==this._frame&&(this.playing=!0),new Promise((t=>{this._onComplete=()=>{this._onComplete=null,t()}}))}get lastFrame(){return this.length-1}get frameImage(){let e=this[this._frame];if(e instanceof p5.Image)return e;let{x:i,y:s,w:r,h:o}=e,h=t.createImage(r,o);return h.copy(this.spriteSheet,this.offset.x,this.offset.y,r,o,i,s,r,o),h}get w(){return this.width}get width(){let t=this[this._frame];return t instanceof p5.Image?t.width:t?t.w:1}get defaultWidth(){return this[this._frame].defaultWidth}get h(){return this.height}get height(){let t=this[this._frame];return t instanceof p5.Image?t.height:t?t.h:1}get defaultHeight(){return this[this._frame].defaultHeight}},t.Ani.props=["demoMode","endOnFirstFrame","frameDelay","frameSize","looping","offset","rotation","scale"],t.SpriteAnimation=t.Ani,this.Anis=class{#t={};constructor(){let e=this,i=[...t.Ani.props,"w","h"],s=["offset","scale"];for(let t of i)Object.defineProperty(this,t,{get:()=>e.#t[t],set(i){e.#t[t]=i;for(let s in e){let r=e[s];r instanceof Ani&&(r[t]=i)}}});for(let t of s){this.#t[t]={_x:0,_y:0};for(let i of["x","y"])Object.defineProperty(this.#t[t],i,{get:()=>e.#t[t]["_"+i],set(s){e.#t[t]["_"+i]=s;for(let r in e){let o=e[r];o instanceof Ani&&(o[t][i]=s)}}})}}get width(){return this.w}set width(t){this.w=t}get height(){return this.h}set height(t){this.h=t}},this.Group=class extends Array{constructor(...e){let i;if(e[0]instanceof t.Group&&(i=e[0],e=e.slice(1)),super(...e),"number"==typeof e[0])return;for(let e of this)if(!(e instanceof t.Sprite))throw new Error("A group can only contain sprites");if(this._isGroup=!0,this.x,this.y,this.vel,this.rotation,this.rotationSpeed,this.autoDraw,this.allowSleeping,this.autoUpdate,this.bounciness,this.collider,this.color,this.debug,this.density,this.direction,this.drag,this.friction,this.h,this.isSuperFast,this.layer,this.life,this.mass,this.mirror,this.offset,this.pixelPerfect,this.removed,this.rotationDrag,this.rotationLock,this.scale,this.shape,this.sleeping,this.stroke,this.strokeWeight,this.text,this.textColor,this.tile,this.tileSize,this.visible,this.w,this.bearing,this.d,this.dynamic,this.heading,this.kinematic,this.resetAnimationsOnChange,this.speed,this.static,this.idNum,t.p5play.groupsCreated<999)this.idNum=t.p5play.groupsCreated;else{for(let e=1;et&&(t=e._layer);return t}get ani(){return this._ani}set ani(t){this.addAni(t);for(let e of this)e.changeAni(t)}get animation(){return this._ani}set animation(t){this.ani=t}get anis(){return this.animations}get img(){return this._img}set img(t){this.image=t}get image(){return this._img}set image(e){"function"!=typeof e?("string"==typeof e&&(e=e.includes(".")?t.loadImage(e):new t.EmojiImage(e,this.w||this.width||this.d||this.diameter)),this._img=t.Sprite.prototype._extendImage(e)):this._img=e}get amount(){return this.length}set amount(t){let e=t-this.length,i=e>0;e=Math.abs(e);for(let t=0;t0?i:0}collided(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,2),this._collisions[t._uid]<=-1}_validateOverlapParams(t,e){if(e&&"function"!=typeof e)throw new C("Group.overlap",1,[e]);if(!t)throw new C("Group.overlap",2);if(!t._isGroup&&!t._isSprite)throw new C("Group.overlap",0,[t])}_ensureOverlap(t){if(!this._hasSensors){for(let t of this)t._hasSensors||t.addDefaultSensors();this._hasSensors=!0}if(!t._hasSensors)if(t._isSprite)t.addDefaultSensors();else{for(let e of t)e._hasSensors||e.addDefaultSensors();t._hasSensors=!0}if(1!=this._hasOverlap[t._uid]){this._removeContactsWith(t),this._hasOverlap[t._uid]=!0;for(let e of this)if(e._hasOverlap[t._uid]=!0,t._hasOverlap[e._uid]=!0,this._uid==t._uid)for(let i of t)e._hasOverlap[i._uid]=!0,i._hasOverlap[e._uid]=!0}if(1!=t._hasOverlap[this._uid]&&(t._removeContactsWith(this),t._hasOverlap[this._uid]=!0,t._isGroup))for(let e of t){e._hasOverlap[this._uid]=!0,this._hasOverlap[e._uid]=!0;for(let t of this)e._hasOverlap[t._uid]=!0,t._hasOverlap[e._uid]=!0}}overlap(t,e){return this.overlaps(t,e)}overlaps(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,0),1==this._overlappers[t._uid]||this._overlappers[t._uid]<=-3}overlapping(t,e){this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,1);let i=this._overlappers[t._uid];return i<=-3?1:i>0?i:0}overlapped(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,2),this._overlappers[t._uid]<=-1}_removeContactsWith(t){for(let e of this)e._removeContactsWith(t)}applyForce(){for(let t of this)t.applyForce(...arguments)}applyForceScaled(){for(let t of this)t.applyForceScaled(...arguments)}attractTo(){for(let t of this)t.attractTo(...arguments)}applyTorque(){for(let t of this)t.applyTorque(...arguments)}move(t,e,i){let s=[];for(let r of this)s.push(r.move(t,e,i));return Promise.all(s)}moveTo(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}let r=this._resetCentroid(),o=[];for(let t of this){let h={x:t.x-r.x+e,y:t.y-r.y+i};o.push(t.moveTo(h.x,h.y,s))}return Promise.all(o)}moveTowards(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}if(void 0!==e||void 0!==i){this._resetCentroid();for(let t of this){void 0===t.distCentroid&&this._resetDistancesFromCentroid();let r={x:t.distCentroid.x+e,y:t.distCentroid.y+i};t.moveTowards(r.x,r.y,s)}}}moveAway(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}if(void 0!==e||void 0!==i){this._resetCentroid();for(let t of this){void 0===t.distCentroid&&this._resetDistancesFromCentroid();let r={x:t.distCentroid.x+e,y:t.distCentroid.y+i};t.moveAway(r.x,r.y,s)}}}push(...e){this.removed&&(console.warn("Adding a sprite to a group that was removed. Use `group.removeAll()` to remove all of a group's sprites without removing the group itself. Restoring the group in p5play's memory."),t.p5play.groups[this._uid]=this,this.removed=!1);for(let i of e){if(!(i instanceof t.Sprite))throw new Error("You can only add sprites to a group, not "+typeof i);if(i.removed){console.error("Can't add a removed sprite to a group");continue}let e;for(let s in this._hasOverlap){let r=this._hasOverlap[s];r&&!i._hasSensors&&i.addDefaultSensors(),e=s>=1e3?t.p5play.sprites[s]:t.p5play.groups[s],e&&!e.removed&&(r?e._ensureOverlap(i):e._ensureCollide(i))}for(let e in d){let s=d[e];for(let e of s){let s=t.p5play[e],r=s[this._uid];if(!r)continue;let o=s[i._uid]??={};for(let t in r)o[t]=r[t]}}super.push(i),this.parent&&t.p5play.groups[this.parent].push(i),i.groups.push(this)}return this.length}repelFrom(){for(let t of this)t.repelFrom(...arguments)}size(){return this.length}toString(){return"g"+this.idNum}cull(e,i,s,r,o){if(void 0===s){o=i,e=i=s=r=e}if(isNaN(e)||isNaN(i)||isNaN(s)||isNaN(r))throw new TypeError("The culling boundary must be defined with numbers");if(o&&"function"!=typeof o)throw new TypeError("The callback to group.cull must be a function");let h=t.camera.x-t.canvas.hw/t.camera.zoom,a=t.camera.y-t.canvas.hh/t.camera.zoom,n=-s+h,l=-e+a,d=t.width+r+h,p=t.height+i+a,u=0;for(let t=0;td||e.y>p)&&(u++,o?o(e,u):e.remove(),e.removed&&t--))}return u}remove(t){if(void 0===t)return this.removeAll(),void(this._isAllSpritesGroup||(this.removed=!0));let e;if(e="number"==typeof t?t>=0?t:this.length+t:this.indexOf(t),-1==e)return;let i=this[e];return this.splice(e,1),i}splice(e,i){let s=super.splice(e,i);if(!s)return;let r=[];for(let t of s){if(t.removed)continue;let e=this._uid;do{r.push(e);let i=t.groups.findIndex((t=>t._uid==e)),s=t.groups.splice(i,1);e=s[0].parent}while(e)}for(let e of r){let i=t.p5play.groups[e];for(let e in d)for(let s in i[e]){if(0==i[e][s])continue;let r;r=s>=1e3?t.p5play.sprites[s]:t.p5play.groups[s];let o=!1;for(let t of i)if(t[e][r._uid]>0){o=!0;break}o||(i[e][r._uid]=-2,r[e][i._uid]=-2)}}return s}pop(){return this.remove(this.length-1)}shift(){return this.remove(0)}unshift(){return console.error("unshift is not supported for groups"),this.length}removeAll(){for(;this.length>0;)this.at(-1).remove()}_step(){this.__step()}draw(){let e=[...this];e.sort(((t,e)=>t._layer-e._layer));for(let i=0;i2)return console.error("world.timeScale must be between 0 and 2");this._timeScale!=t&&(this._timeScale=t,this._updateTimeStep())}_updateTimeStep(){this._timeStep=1/(t._targetFrameRate||60)*this._timeScale}get velocityThreshold(){return e.Settings.velocityThreshold}set velocityThreshold(t){e.Settings.velocityThreshold=t}step(e,i,s){for(let e of t.allSprites)e.prevPos.x=e.x,e.prevPos.y=e.y,e.prevRotation=e.rotation;super.step(e||this._timeStep,i||this.velocityIterations,s||this.positionIterations),this.physicsTime+=e||this._timeStep;let r=Object.values(t.p5play.sprites),o=Object.values(t.p5play.groups);for(let t of r)t._step();for(let t of o)t._step();for(let t of r)t.___step();for(let t of o)t.___step();t.canvas.dispatchEvent&&t.canvas.dispatchEvent(this.steppedEvent),this.autoStep&&(this.autoStep=null)}get realTime(){return t.millis()/1e3}getSpritesAt(i,s,r,o=!0){"object"==typeof i&&(s=i.y,i=i.x);const h=new e.Vec2(i/t.world.meterSize,s/t.world.meterSize),a=new e.AABB;a.lowerBound=new e.Vec2(h.x-.001,h.y-.001),a.upperBound=new e.Vec2(h.x+.001,h.y+.001);let n=[];if(this.queryAABB(a,(t=>(t.getShape().testPoint(t.getBody().getTransform(),h)&&n.push(t),!0))),0==n.length)return[];r??=t.allSprites;let l=[];for(let t of n){const e=t.m_body.sprite;e._cameraActiveWhenDrawn==o&&(l.find((t=>t._uid==e._uid))||l.push(e))}return l.sort(((t,e)=>-1*(t._layer-e._layer))),l}getSpriteAt(t,e,i){return this.getSpritesAt(t,e,i)[0]}getMouseSprites(){let e=this.getSpritesAt(t.mouse.x,t.mouse.y);if(t.camera._wasOff){let i=this.getSpritesAt(t.mouse.canvasPos.x,t.mouse.canvasPos.y,t.allSprites,!1);i.length&&(e=[...i,...e])}return e}_beginContact(t){let e=t.m_fixtureA,i=t.m_fixtureB,s="_collisions";e.m_isSensor&&(s="_overlappers"),e=e.m_body.sprite,i=i.m_body.sprite,e[s][i._uid]=0,i[s][e._uid]=0;for(let t of i.groups)(!e[s][t._uid]||e[s][t._uid]<0)&&(e[s][t._uid]=0,t[s][e._uid]=0);for(let t of e.groups){(!i[s][t._uid]||i[s][t._uid]<0)&&(i[s][t._uid]=0,t[s][i._uid]=0);for(let e of i.groups)(!t[s][e._uid]||t[s][e._uid]<0)&&(t[s][e._uid]=0,e[s][t._uid]=0)}}_endContact(t){let e=t.m_fixtureA,i=t.m_fixtureB,s="_collisions";e.m_isSensor&&(s="_overlappers"),e=e.m_body.sprite,i=i.m_body.sprite,e[s][i._uid]=0!=e[s][i._uid]?-2:-4,i[s][e._uid]=0!=i[s][e._uid]?-2:-4;for(let t of i.groups){let i=!1;for(let r of t)if(r[s][e._uid]>=0){i=!0;break}i||(t[s][e._uid]=0!=t[s][e._uid]?-2:-4,e[s][t._uid]=0!=e[s][t._uid]?-2:-4)}for(let t of e.groups){let e=!1;for(let r of t)if(r[s][i._uid]>=0){e=!0;break}if(!e){t[s][i._uid]=0!=t[s][i._uid]?-2:-4,i[s][t._uid]=0!=i[s][t._uid]?-2:-4;for(let e of i.groups)t[s][e._uid]=0!=t[s][e._uid]?-2:-4,e[s][t._uid]=0!=e[s][t._uid]?-2:-4}}}_findContact(t,e,i){let s=e[t][i._uid];if(s)return s;for(let r of i.groups)if(s=e[t][r._uid],s)return s;for(let r of e.groups){if(s=r[t][i._uid],s)return s;for(let e of i.groups)if(r._uid==e._uid&&(s=r[t][e._uid],s))return s}return!1}get allowSleeping(){return this.getAllowSleeping()}set allowSleeping(t){this.setAllowSleeping(t)}rayCast(t,e,i){return this.rayCastAll(t,e,i,(()=>!0))[0]}rayCastAll(e,i,r,o){let h,a=t.allSprites.tileSize,n=s(e.x,e.y,a);if("number"==typeof arguments[1])h=s(e.x+r*t.cos(i),e.y+r*t.sin(i),a);else{let t=arguments[1];o??=arguments[2],h=s(t.x,t.y,a)}let l=[],d=1;super.rayCast(n,h,(function(t,e,i,s){let r=t.getBody().sprite,h=o&&o(r);return l.push({sprite:r,fraction:s}),h?(st.fraction-e.fraction));let p=[];for(let t of l)t.fraction<=d&&p.push(t.sprite);return p}},this.Camera=class{constructor(){this._pos=t.createVector.call(t),this.__pos={x:0,y:0,rounded:{}},this.isActive=!1,this.bound={min:{x:0,y:0},max:{x:0,y:0}},this._zoomIdx=-1,this._zoom=1,this._destIdx=0}get pos(){return this._pos}set pos(t){this.x=t.x,this.y=t.y}get position(){return this._pos}set position(t){this.x=t.x,this.y=t.y}_calcBoundsX(e){let i=t.canvas.hw/this._zoom;this.bound.min.x=e-i,this.bound.max.x=e+i}_calcBoundsY(e){let i=t.canvas.hh/this._zoom;this.bound.min.y=e-i,this.bound.max.y=e+i}get x(){return this._pos.x}set x(e){if(void 0===e||isNaN(e))return;this._pos.x=e;let i=-e;"2d"==t.canvas.renderer&&(i+=t.canvas.hw/this._zoom),this.__pos.x=i,t.allSprites.pixelPerfect&&(this.__pos.rounded.x=Math.round(i)),this._calcBoundsX(e)}get y(){return this._pos.y}set y(e){if(void 0===e||isNaN(e))return;this._pos.y=e;let i=-e;"2d"==t.canvas.renderer&&(i+=t.canvas.hh/this._zoom),this.__pos.y=i,t.allSprites.pixelPerfect&&(this.__pos.rounded.y=Math.round(i)),this._calcBoundsY(e)}moveTo(e,i,s){if(void 0===e)return;if(isNaN(e)&&(s=i,i=e.y,e=e.x),s??=1,s<=0)return console.warn("camera.moveTo: speed should be a positive number"),Promise.resolve(!1);let r=i-this.y,o=e-this.x,h=Math.sqrt(r*r+o*o),a=s/h,n=o*a,l=r*a;this._destIdx++;let d=this._destIdx,p=Math.ceil(h/s);return(async()=>{for(let e=0;e{for(let e=0;e0&&(e=e<.1?t.map(e,0,.1,30,4):e<.5?t.map(e,.1,.5,4,2.5):e<.8?t.map(e,.5,.8,2.5,1):e<.9?t.map(e,.8,.9,1,.5):t.map(e,.9,1,.5,.2)),this._springiness=e,"wheel"!=this.type)return this._j.setFrequency(e);this._j.setSpringFrequencyHz(e)}get damping(){return"wheel"!=this.type?this._j.getDampingRatio():this._j.getSpringDampingRatio()}set damping(t){"wheel"==this.type?this._j.setSpringDampingRatio(t):this._j.setDampingRatio(t)}get speed(){return this._j.getJointSpeed()}set speed(t){this._j.isMotorEnabled()||this._j.enableMotor(!0),this._j.setMotorSpeed(t)}get motorSpeed(){return this._j.getMotorSpeed()}get enableMotor(){return this._j.isMotorEnabled()}set enableMotor(t){this._j.enableMotor(t)}get maxPower(){return this._j.getMaxMotorTorque()}set maxPower(t){!this._j.isMotorEnabled()&&t&&this._j.enableMotor(!0),this._j.setMaxMotorTorque(t),t||this._j.enableMotor(!1)}get power(){return this._j.getMotorTorque()}get collideConnected(){return this._j.getCollideConnected()}set collideConnected(t){this._j.m_collideConnected=t}get reactionForce(){return this._j.getReactionForce(t.world._timeStep)}get reactionTorque(){return this._j.getReactionTorque(t.world._timeStep)}remove(){this._removed||(this.spriteA.joints.splice(this.spriteA.joints.indexOf(this),1),this.spriteB.joints.splice(this.spriteB.joints.indexOf(this),1),t.world.destroyJoint(this._j),this._removed=!0)}},this.GlueJoint=class extends t.Joint{constructor(t,e){super(...arguments,"glue")}},this.DistanceJoint=class extends t.Joint{constructor(t,i){super(...arguments,"distance");let s=e.DistanceJoint({},t.body,i.body,t.body.getWorldCenter(),i.body.getWorldCenter());this._createJoint(s)}_display(){let t,e;(this.offsetA.x||this.offsetA.y)&&(t=this.spriteA.body.getWorldPoint(this._j.m_localAnchorA),t=r(t.x,t.y,this.spriteA.tileSize)),(this.offsetB.x||this.offsetB.y)&&(e=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB),e=r(e.x,e.y,this.spriteB.tileSize)),this._draw(t?t.x:this.spriteA.x,t?t.y:this.spriteA.y,e?e.x:this.spriteB.x,e?e.y:this.spriteB.y),this.visible=null}},this.WheelJoint=class extends t.Joint{constructor(s,r){super(...arguments,"wheel");let o=e.WheelJoint({maxMotorTorque:1e3,frequencyHz:4,dampingRatio:.7},s.body,r.body,r.body.getWorldCenter(),new e.Vec2(0,1));this._createJoint(o),this._angle=t._angleMode==i?90:1.5707963267948966}_display(){let e,i,s=this.spriteA.x,o=this.spriteA.y;if(this.offsetB.x||this.offsetB.y){let t=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB);t=r(t.x,t.y,this.spriteB.tileSize),e=t.x,i=t.y}else e=this.spriteB.x,i=this.spriteB.y;let h=t.tan(this.spriteA.rotation),a=t.tan(this._angle+this.spriteA.rotation),n=(i-o+h*s-a*e)/(h-a),l=h*(n-s)+o;this._draw(n,l,e,i),this.visible=null}get angle(){return this._angle}set angle(i){i!=this._angle&&(this._angle=i,this._j.m_localXAxisA=new e.Vec2(t.cos(i),t.sin(i)),this._j.m_localXAxisA.normalize(),this._j.m_localYAxisA=e.Vec2.crossNumVec2(1,this._j.m_localXAxisA))}},this.HingeJoint=class extends t.Joint{constructor(t,i){super(...arguments,"hinge");let s=e.RevoluteJoint({},t.body,i.body,t.body.getWorldCenter());this._createJoint(s)}_display(){const e=this.offsetA.x,i=this.offsetA.y,s=this.spriteA.rotation,r=e*t.cos(s)-i*t.sin(s),o=e*t.sin(s)+i*t.cos(s);this._draw(this.spriteA.x+r,this.spriteA.y+o),this.visible=null}get range(){return this.upperLimit-this.lowerLimit}set range(t){t/=2,this.upperLimit=t,this.lowerLimit=-t}get lowerLimit(){let e=this._j.getLowerLimit();return"radians"==t._angleMode?e:t.degrees(e)}set lowerLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),this.spriteA.body.setAwake(!0),this.spriteB.body.setAwake(!0),t._angleMode==i&&(e=t.radians(e)),this._j.m_lowerAngle=e}get upperLimit(){let e=this._j.getUpperLimit();return"radians"==t._angleMode?e:t.degrees(e)}set upperLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),this.spriteA.body.setAwake(!0),this.spriteB.body.setAwake(!0),t._angleMode==i&&(e=t.radians(e)),this._j.m_upperAngle=e}get angle(){let e=this._j.getJointAngle();return"radians"==t._angleMode?e:t.radians(e)}},t.RevoluteJoint=t.HingeJoint,this.SliderJoint=class extends t.Joint{constructor(t,i){super(...arguments,"slider");let s=e.PrismaticJoint({lowerTranslation:-1,upperTranslation:1,enableLimit:!0,maxMotorForce:50,motorSpeed:0,enableMotor:!0},t.body,i.body,t.body.getWorldCenter(),new e.Vec2(1,0));this._createJoint(s),this._angle=0}get angle(){return this._angle}set angle(i){i!=this._angle&&(this._angle=i,this._j.m_localXAxisA=new e.Vec2(t.cos(i),t.sin(i)),this._j.m_localXAxisA.normalize(),this._j.m_localYAxisA=e.Vec2.crossNumVec2(1,this._j.m_localXAxisA))}get range(){return this.upperLimit-this.lowerLimit}set range(t){t/=2,this.upperLimit=t,this.lowerLimit=-t}get lowerLimit(){return this._j.getLowerLimit()/this.spriteA.tileSize*t.world.meterSize}set lowerLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),e=e*this.spriteA.tileSize/t.world.meterSize,this._j.setLimits(e,this._j.getUpperLimit())}get upperLimit(){return this._j.getUpperLimit()/this.spriteA.tileSize*t.world.meterSize}set upperLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),e=e*this.spriteA.tileSize/t.world.meterSize,this._j.setLimits(this._j.getLowerLimit(),e)}},t.PrismaticJoint=t.SliderJoint,this.RopeJoint=class extends t.Joint{constructor(t,i){super(...arguments,"rope");let s=e.RopeJoint({maxLength:1},t.body,i.body,t.body.getWorldCenter());this._createJoint(s),this._j.m_localAnchorB.x=0,this._j.m_localAnchorB.y=0}get maxLength(){return e=this._j.getMaxLength(),i=this.spriteA.tileSize,e/i*t.world.meterSize;var e,i}set maxLength(e){var i,s;this._j.setMaxLength((i=e,s=this.spriteA.tileSize,i*s/t.world.meterSize))}},this.GrabJoint=class extends this.Joint{constructor(i,s){"object"!=typeof s&&(s=mouse),super(i,i,"grab");let r=e.MouseJoint({maxForce:1e3,frequencyHz:3,dampingRatio:.9,target:i.body.getPosition()},i.body,i.body,new e.Vec2(s.x/t.world.meterSize,s.y/t.world.meterSize));this._createJoint(r),this._target={x:s.x,y:s.y}}_draw(){t.line(this.spriteA.x,this.spriteA.y,this._target.x,this._target.y)}get target(){return this._target}set target(i){let s=this._target.x=i.x,r=this._target.y=i.y;this._j.setTarget(new e.Vec2(s/t.world.meterSize,r/t.world.meterSize))}set maxForce(t){this._j.setMaxForce(t)}};class u{constructor(){let t=this;Object.defineProperties(this,{x:{get:()=>t._x,set(e){e!=t._x&&(t._x=e,t._avg=.5*(t._x+t._y))},configurable:!0,enumerable:!0},y:{get:()=>t._y,set(e){e!=t._y&&(t._y=e,t._avg=.5*(t._x+t._y))},configurable:!0,enumerable:!0},_x:{value:1,enumerable:!1,writable:!0},_y:{value:1,enumerable:!1,writable:!0},_avg:{value:1,enumerable:!1,writable:!0}})}valueOf(){return this._avg}}function c(t){return!/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test(t.toString())}function _(t,e){let i=t,s=e.toLowerCase();if("triangle"==s?i=[i,-120,3]:"square"==s?i=[i,-90,4]:"pentagon"==s?i=[i,-72,5]:"hexagon"==s?i=[i,-60,6]:"septagon"==s?i=[i,-51.4285714286,7]:"octagon"==s?i=[i,-45,8]:"enneagon"==s?i=[i,-40,9]:"decagon"==s?i=[i,-36,10]:"hendecagon"==s?i=[i,-32.7272727273,11]:"dodecagon"==s&&(i=[i,-30,12]),i==t)throw new Error("Invalid, not a regular polygon: "+e);return i}if(t.p5play.palettes=[{a:"aqua",b:"black",c:"crimson",d:"darkviolet",e:"peachpuff",f:"olive",g:"green",h:"hotpink",i:"indigo",j:"navy",k:"khaki",l:"lime",m:"magenta",n:"brown",o:"orange",p:"pink",q:"turquoise",r:"red",s:"skyblue",t:"tan",u:"blue",v:"violet",w:"white",x:"gold",y:"yellow",z:"gray"}],this.colorPal=(e,i)=>{if(e instanceof p5.Color)return e;"number"==typeof i&&(i=t.p5play.palettes[i]),i??=t.p5play.palettes[0];let s=i[e];return s?t.color(s):t.color(0,0,0,0)},this.EmojiImage=function(e,i){t.push(),t.textSize(i);let s=t.createGraphics(i,1.25*i);s.textSize(i),s.textAlign(t.CENTER),s.text(e,i/2,i);let r=s.drawingContext,o=s._pixelDensity||1,h=s.canvas.width,a=s.canvas.height,n=r.getImageData(0,0,h,a).data,l=h,d=0,p=a,u=0,c=3;for(let t=0;td&&(d=e),tu&&(u=t)),c+=4;return p=Math.floor(p/o),u=Math.floor(u/o),l=Math.floor(l/o),d=Math.floor(d/o),s=s.get(l,p,d-l+1,u-p+1),t.pop(),s.url=e,s},this.spriteArt=(e,i,s)=>{i??=1,"number"==typeof s&&(s=t.p5play.palettes[s]),s??=t.p5play.palettes[0];let r=e;"string"==typeof e&&(r=(e=(e=(e=e.trim()).replace(/\r*\n\t+/g,"\n")).replace(/\s+$/g,"")).split("\n"));let o=0;for(let t of r)t.length>o&&(o=t.length);let h=r.length,a=t.createImage(o*i,h*i);a.loadPixels();for(let t=0;tnew Promise(t?e=>{setTimeout(e,t)}:requestAnimationFrame),this.sleep=e=>e?t.delay(e):new Promise((e=>{if(t.canvas.dispatchEvent){t.canvas.addEventListener("p5play_worldStepped",(function i(){t.canvas.removeEventListener("p5play_worldStepped",i),e()}))}else setTimeout(e,1e3*t.world._timeStep)})),this.play=t=>{if(!t?.play)throw new Error("Tried to play your sound but it wasn't a sound object.");return new Promise((e=>{t.play(),t.onended((()=>e()))}))},window.location){let e=location.hostname;switch(e){case"":case"127.0.0.1":case"localhost":case"p5play.org":case"editor.p5js.org":case"codepen.io":case"codera.app":case"aug4th.com":case"cdpn.io":case"glitch.com":case"replit.com":case"stackblitz.com":case"jsfiddle.net":case"aijs.io":case"preview-aijs.web.app":case"quinton-ashley.github.io":break;default:if(/^[\d\.]+$/.test(e)||e.endsWith("stackblitz.io")||e.endsWith("glitch.me")||e.endsWith("replit.dev")||e.endsWith("codehs.com")||e.endsWith("openprocessing.org")||location.origin.endsWith("preview.p5js.org"))break;!async function(){if(document.getElementById("p5play-intro"))return;t._incrementPreload();let e=document.createElement("div");e.id="p5play-intro",e.style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; background-color: black;";let i=document.createElement("img");i.style="position: absolute; top: 50%; left: 50%; width: 80vmin; height: 40vmin; margin-left: -40vmin; margin-top: -20vmin; z-index: 1001; opacity: 1; scale: 1; transition: scale 1.5s, opacity 0.4s ease-in-out;",i.onerror=()=>{i.style.imageRendering="pixelated",i.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABACAYAAADS1n9/AAABbGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAACiRfZC/S0JhGIWfm4VgNkQNDg13igYr0SCXBjWQIkisQG26Xn+C2sfVCKMtWkPoP8igOWgoIgxaGhqCqCGitqamgpaSL+69hS51lvfhcDgcXujxaEKUeoFypWbEo2E1kUypzhcUFCxpelWEYrEFk39vlxT4uLezt+Nm12u7uRvciV6Wj88XNx88k/wvVyZb1YEvwKcLowaKF4ht1ITJW8CwkUimQGmYnLf5wOS0zSdWZjkeAeUaUPWClgHlFfCmu/x8F5dL6/rPMnO9O1tZWTJ7gBFmKVJFUEKjjkqMwB/5KSsfYQ1BHYMieQrUUAkhrIYsKnNU0JnAi4ofH3785p/tuo+7n/95O972M8y0pJRnHW++BUfT4DrteGNBGOyHq1OhGZplOYCeXA7eDmEgCUM34Fqt5gJ+e707DH1PUr6PgnMP2g0pP/elbDfB8QgXlW8Y/mq9pjC8gwAABSxJREFUeJztnb9y2zAMxulcpnbNntfJ3D5n97xO966Z3aNP9NHgBxAgQVmO8bvLNZZIiCI+gH8kpyl4bk7P3gErOJ/PZ0+zp9NpmZ9CAM54O7+wSgQhAEdWOb+wQgSvzZHAj5+/50x9/WkOeRMZwIkm+medXyAi8M4CL82R4KkIATjQRL8nJJN4XysEsAKv9L8DIYAnJyaBk8CUTDLA51/bbP7jHWSQRZPByADeTDp/tM4ozT4AVHSwO1kEMBMY/dTLFNcMcN5oSgTHYHBi2fPrS4qo98Mh/a+C8/ErdyJYw8cbb/bzH/ncGQY8aOYAnpThZ4XGerZdrn209fxIe6rVQw52Oif4NquAfF+d+Y6NSeej9C9F/714WAHkyP5uoxcSCBKSic5WMhwCciTlcnUaRSmVRlw5x0UiVx6VqW1Ru1zbaHl6TXS9Efae3GmuNzpXYDMA7VT6OxKE9nhPKNy1ZlHbEdL/qPNRdHsy2i5WAIk41yt6emM1Jw5OcL12eg4VR1rWmRCGAVEAGjhncseLQ7SOebZV6t4TxWEBcFHHOayO7PoHUcpy/y5FSP+jWJ06KoKRDAUngZxDUXrVlOsdR0jX8vjsxaqI1dilG0ciWdjgHcN4GqgERdcR1/VayjwgBFDzQG/yJEaASKgSIYBnAgg8BKAARRWKvkcjDwMhgAKIjkcACREJlgOuAu5K7Qgwaz0KeQaOOn9vTCsBwLwApMiZdOBROpnj3u2bdX5aPQfwaOBuDIr1HveYryldl30wBO4RZ4AS1aXCbFr2skezTa5b2+7Z7Z2nNjZKh3Jja3HGHtlAcnwyOj+/HIIFUACd0TizbhzTQU1ddAzYg+WYY5d0TM5dXql6A2VzO7n0jUS6kTtXuseVQ4Im01icXxgfApgOuvy8pevPjD3VuRrhRpu29trG2GI7eWPFkKCJerZdzH2UV8NUAsiqR8pnG5YdJjjNZA+8aYvqIq6dQqNfC9N5YofvDNuO3HbQ/tNG+dwVQOmwS8QAg/kY26lABF17Aqq65DgSlSkzMR2ZpM53hmsve32mvehLIvIcoFyIaUB9vhZB3bBmbJ6cLJkfrb4PRj+FmSAeCsbxiXF+0mSAG5WhDtjSfT32S3TtUb6wsMS6Qkd4TtKQoI62b0FTPkW3EQQ6G908KgcB5aA9BKir4WFf59q4ZNneF0eYZ/4SUxtB4lg88rVoLnqEa7CAOqz9J0Y9Caw/N44FnX0zYQPHRXsI4RqQ0Zk/B1iNUB5RYKohgN4svNG8GiApCpbr2QN2uHN08nmBGSK4ttyLkd1D1TBgxGUV4F1OOk/PSWUTENsRqJ3ovo1M5gHo+4A13/YPRd4sS2c7V/m1795WMJvZlNvIUv1RTtzXw2mqncXbnsSSqCJwIuCua3GetX4zBBj+ntDlBCeCYGNg2Vo7UXIeR6nv9fSPE0EIoAdwfs095xis85NeAC/SyWDSCQLXJ6cT9T2Ajo+MQOhkgWTMBMh55iecPSxDQHBLEwCG7WfJkd13CYS6mvpXrJPAoKURQdILATnSkrKbjTJLugc7piGAQWZEkDS7dMIj5utWulQf2SNIzk8hgD6zIoBQRy36n0U0k/sQgAIogjT/Z9saHO1pV3YhACUuImCcNWRPsGVZ1ocAjEAh9JwmOAsyaG9kPycEMAAUQWIcp3CWt71gB84SP34JJ7Gzm0I1A/a0hGomsTigF6VWZ3pEfQjAAY3jLM7yticRAnAEOW7GUd72ECEAZ2qneTjL294NKaX/gKttC9Kft4MAAAAASUVORK5CYII="};let s=window._p5play_intro_image;""==s||s?.includes("made_with_p5play")?((s.includes("bit.")||s.includes("pixel"))&&(i.style.imageRendering="pixelated"),i.src=s):i.src="https://p5play.org/assets/made_with_p5play.webp",await new Promise((t=>i.onload=t)),e.append(i),document.body.append(e),await t.delay(),i.offsetHeight,i.style.scale=1.2,await t.delay(1100),i.style.opacity=0,await t.delay(400),e.style.display="none",e.remove(),document.getElementById("p5play-intro")?.remove(),t._decrementPreload()}()}}let g=p5.disableFriendlyErrors;p5.disableFriendlyErrors=!0;const f=t.createCanvas;this.createCanvas=function(){let e,i,s,r=[...arguments];if("string"==typeof r[0])if(r[0].includes(":")){let t=r[0].split(":"),i=Number(t[0]),s=Number(t[1]),o=window.innerWidth,h=window.innerWidth*(s/i);h>window.innerHeight&&(o=window.innerHeight*(i/s),h=window.innerHeight),r[0]=Math.round(o),r.splice(1,0,Math.round(h)),e="fullscreen"}else r=[0,0,...r];if(r[0]||(r[0]=window.innerWidth,r[1]=window.innerHeight,e="fullscreen"),"string"==typeof r[2]){let t=r[2].toLowerCase().split(" ");"pixelated"==t[0]?(i="pixelated",t[1]?(e="centered",s=Number(t[1].slice(1))):e="fullscreen",r.splice(2,1)):"fullscreen"==t[0]&&(e="fullscreen",r.splice(2,1))}let o=f.call(t,...r);t.ctx=t.drawingContext;let h=o.canvas||o;return o.GL&&(h.renderer="webgl"),"webgpu"!=h.renderer&&(h.renderer="2d"),h.tabIndex=0,h.w=r[0],h.h=r[1],h.addEventListener&&(h.addEventListener("keydown",(function(t){" "!=t.key&&"/"!=t.key&&"ArrowUp"!=t.key&&"ArrowDown"!=t.key&&"ArrowLeft"!=t.key&&"ArrowRight"!=t.key||t.preventDefault()})),h.addEventListener("mouseover",(()=>{this.mouse.isOnCanvas=!0,this.mouse.isActive=!0})),h.addEventListener("mouseleave",(()=>{this.mouse.isOnCanvas=!1})),h.addEventListener("touchstart",(t=>t.preventDefault())),h.addEventListener("contextmenu",(t=>t.preventDefault()))),h.save??=t.saveCanvas.bind(t),h.resize??=t.resizeCanvas.bind(t),h.hw=.5*h.w,h.hh=.5*h.h,h.mouse={x:t.mouseX,y:t.mouseY},"2d"!=h.renderer||t._webgpuFallback?(t.camera.x=0,t.camera.y=0,"webgl"==h.renderer&&(t._textCache=!1),t._webgpuFallback||(t.p5play._renderStats={x:10-h.hw,y:20-h.hh})):(t.camera.x=t.camera.ogX=h.hw,t.camera.y=t.camera.ogY=h.hh),g||(p5.disableFriendlyErrors=!1),t.displayMode(e,i,s),o},this.Canvas=class{constructor(t,e,i,s){this.w,this.width,this.h,this.height,this.hw,this.hh,this.mouse}resize(){}save(){}},this.canvas=t.canvas,t.Canvas=function(){return t.createCanvas(...arguments).canvas};const m=t.resizeCanvas;this.resizeCanvas=(e,i)=>{e??=window.innerWidth,i??=window.innerHeight,m.call(t,e,i);let s=t.canvas;s.w=s.width/t.pixelDensity(),s.h=s.height/t.pixelDensity(),s.hw=.5*s.w,s.hh=.5*s.h,s.fullscreen&&(s.w/s.h>window.innerWidth/window.innerHeight?(s.style.width="100%!important",s.style.height="auto!important"):(s.style.width="auto!important",s.style.height="100%!important")),"2d"==s.renderer?(t.camera.x=s.hw,t.camera.y=s.hh):(t.camera.x=0,t.camera.y=0)};const y=t.frameRate;this.frameRate=function(e){let i=y.call(t,e);return e&&t.world._updateTimeStep(),i};const w=t.background;this.background=function(){let e=arguments;1==e.length&&1==e[0]?.length?w.call(t,t.colorPal(e[0])):w.call(t,...e)};const v=t.fill;this.fill=function(){let e=arguments;1==e.length&&1==e[0]?.length?v.call(t,t.colorPal(e[0])):v.call(t,...e)};const x=t.stroke;this.stroke=function(){let e=arguments;1==e.length&&1==e[0]?.length?x.call(t,t.colorPal(e[0])):x.call(t,...e)};const b=t.loadImage;this.loadImage=this.loadImg=function(){if(t.p5play.disableImages)return t._decrementPreload(),{w:16,width:16,h:16,height:16,pixels:[]};let e,i=arguments,s=i[0],r=t.p5play.images[s];if("function"==typeof i[i.length-1]&&(e=i[i.length-1]),r)return r.width<=1&&r.height<=1||!r.pixels.length?e?(r.cbs.push(e),r.calls++):t._decrementPreload():(e&&e(),t._decrementPreload()),r;return r=b.call(t,s,(e=>{if(e.w||(Object.defineProperty(e,"w",{get:function(){return this.width}}),Object.defineProperty(e,"h",{get:function(){return this.height}})),e.cbs){for(let t of e.cbs)t(e);for(let i=1;i\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\nbody.hasFrameBorder {\n\tdisplay: block;\n}\n.p5Canvas {\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.p5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.p5-centered,\n.p5-maxed,\n.p5-fullscreen {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.p5-centered,\nmain.p5-maxed,\n.p5-fullscreen {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n"),t._adjustDisplay=()=>{let e=t.canvas,i=e.style,s=e.parentElement;i&&s&&e.displayMode&&("pixelated"==e.renderQuality&&(e.classList.add("p5-pixelated"),t.pixelDensity(1),t.noSmooth&&t.noSmooth(),t.textFont&&t.textFont("monospace")),"normal"==e.displayMode?(s.classList.remove("p5-centered","p5-maxed","p5-fullscreen"),i.width=e.w*e.displayScale+"px",i.height=e.h*e.displayScale+"px"):(s.classList.add("p5-"+e.displayMode),s=s.getBoundingClientRect(),e.w/e.h>s.width/s.height?("centered"==e.displayMode?(i.width=e.w*e.displayScale+"px",i.maxWidth="100%"):i.width="100%",i.height="auto",i.maxHeight=""):(i.width="auto",i.maxWidth="","centered"==e.displayMode?(i.height=e.h*e.displayScale+"px",i.maxHeight="100%"):i.height="100%")))},t.displayMode=(e="normal",i="default",s=1)=>{let r=t.canvas;"string"==typeof s&&(s=parseFloat(s.slice(1))),Object.assign(r,{displayMode:e,renderQuality:i,displayScale:s}),t._adjustDisplay()});let A={generic:["Ah! I found an error","Oh no! Something went wrong","Oof! Something went wrong","Houston, we have a problem","Whoops, having trouble here"],Sprite:{constructor:{base:"Sorry I'm unable to make a new Sprite",0:"What is $0 for? If you're trying to specify the x position of the sprite, please specify the y position as well.",1:"If you're trying to specify points for a chain Sprite, please use an array of position arrays.\n$0",2:"Invalid input parameters: $0"},hw:{0:"I can't change the halfWidth of a Sprite directly, change the sprite's width instead."},hh:{1:"I can't change the halfHeight of a Sprite directly, change the sprite's height instead."},rotate:{0:"Can't use this function on a sprite with a static collider, try changing the sprite's collider type to kinematic.",1:'Can\'t use "$0" for the angle of rotation, it must be a number.'},rotateTo:{},rotateMinTo:{},rotateTowards:{},changeAnimation:'I can\'t find any animation named "$0".',collide:{0:"I can't make that sprite collide with $0. Sprites can only collide with another sprite or a group.",1:"The collision callback has to be a function.",2:"You're trying to check for an collision with a sprite or group that doesn't exist!"},overlap:{0:"I can't make that sprite overlap with $0. Sprites can only overlap with another sprite or a group.",1:"The overlap callback has to be a function.",2:"You're trying to check for an overlap with a sprite or group that doesn't exist!"}},Ani:{constructor:{base:"Hey so, I tried to make a new Ani but couldn't",1:"The name of the animation must be the first input parameter."},frame:"Index $0 out of bounds. That means there is no frame $0 in this animation. It only has $1 frames!"},Group:{constructor:{base:"Hmm awkward! Well it seems I can't make that new Group you wanted"}}};A.Group.collide=A.Sprite.collide,A.Group.overlap=A.Sprite.overlap,A.Sprite.rotateTo[0]=A.Sprite.rotateMinTo[0]=A.Sprite.rotateTowards[0]=A.Sprite.rotate[0];class C extends Error{constructor(t,e,i){super(),"string"!=typeof t&&(i=e,e=t,t=(t=this.stack.match(/\n\s*at ([^\(]*)/)[1]).slice(0,-1)),"number"!=typeof e&&(i=e,e=void 0),"new"==t.slice(0,3)&&(t=t.slice(4));let s=(t=t.split("."))[0];t=t[1]||"constructor";let r=this.stack.match(/\/([^p\/][^5][^\/:]*:[^\/:]+):/);r&&(r=r[1].split(":"),r=" in "+r[0]+" at line "+r[1]),r=" using "+s+"."+t+". ",i=i||[];let o,h=A[s][t];o=h.base?h.base+r:A.generic[Math.floor(Math.random()*A.generic.length)]+r,void 0!==e&&(h=h[e]),h&&(h=h.replace(/\$([0-9]+)/g,((t,e)=>i[e])),o+=h),p5._friendlyError(o,t)}}this.allSprites=new t.Group,this.world=new t.World,this.camera=new t.Camera,this.InputDevice=class{constructor(){this.holdThreshold=12,this._default=0}_ac(t){return t}presses(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),1==this[t]||-3==this[t]}pressing(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),-3==this[t]?1:this[t]>0?this[t]:0}pressed(t){return this.released(t)}holds(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]==this.holdThreshold}holding(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]>=this.holdThreshold?this[t]:0}held(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),-2==this[t]}released(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]<=-1}releases(t){return this.released(t)}},this._Mouse=class extends t.InputDevice{constructor(){super(),this._default="left";let e=this;this._pos=t.createVector.call(t),Object.defineProperty(this._pos,"x",{get:()=>e.x,set(t){e.x=t}}),Object.defineProperty(this._pos,"y",{get:()=>e.y,set(t){e.y=t}}),this.x=0,this.y=0,this.canvasPos={},this.left=0,this.center=0,this.right=0,this.drag={left:0,center:0,right:0},this._dragFrame={left:!1,center:!1,right:!1},this.isOnCanvas=!1,this.isActive=!1,this._visible=!0,this._cursor="default",this._ogX=0,this._ogY=0}_ac(t){return"left"==(t=t.toLowerCase()).slice(0,4)?t="left":"right"==t.slice(0,5)?t="right":"middle"==t.slice(0,6)&&(t="center"),t}_update(){t.mouse.canvasPos.x=t.mouseX,t.mouse.canvasPos.y=t.mouseY,t.camera.x==t.camera.ogX&&t.camera.y==t.camera.ogY&&1==t.camera.zoom?(this.x=t.mouseX,this.y=t.mouseY):"webgpu"!=t.canvas.renderer?(this.x=(t.mouseX-t.canvas.hw)/t.camera.zoom+t.camera.x,this.y=(t.mouseY-t.canvas.hh)/t.camera.zoom+t.camera.y):(this.x=t.mouseX/t.camera.zoom+t.camera.x,this.y=t.mouseY/t.camera.zoom+t.camera.y)}get pos(){return this._pos}get position(){return this._pos}get cursor(){return t.canvas.style.cursor}set cursor(e){e!=this._cursor&&(t.cursor(e),this._cursor=e)}get visible(){return this._visible}set visible(e){this._visible=e,t.canvas.style.cursor=e?"default":"none"}drags(t){return t??=this._default,1==this.drag[t]}dragging(t){return t??=this._default,this.drag[t]>0?this.drag[t]:0}dragged(t){return t??=this._default,this.drag[t]<=-1}},this.mouse=new t._Mouse,this._SpriteMouse=class extends t._Mouse{constructor(){super(),delete this.canvasPos,this.hover=0}hovers(){return 1==this.hover}hovering(){return this.hover>0?this.hover:0}hovered(){return this.hover<=-1}};const k=function(e){if(t.mouse.isActive=!0,t.mouse[e]++,t.world.mouseSprites.length){let i=t.world.mouseSprite?.mouse;i&&(i[e]=0,i.hover=0,i.drag[e]=0),ms=t.world.mouseSprites[0],t.world.mouseSprite=ms,i=ms.mouse,i[e]=1,i.hover<=0&&(i.hover=1)}},M=t._onmousedown;t._onmousedown=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),k.call(t,i),M.call(t,e)};const z=function(e){let i=t.mouse;i[e]>0&&(i._dragFrame[e]=!0)},T=t._onmousemove;t._onmousemove=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),z.call(t,i),T.call(t,e)};const j=function(e){let i=t.mouse;i[e]>=i.holdThreshold?i[e]=-2:i[e]>1?i[e]=-1:i[e]=-3,i.drag[e]>0&&(i.drag[e]=-1);let s=t.world.mouseSprite?.mouse;s&&(s.hover>1?(s[e]>=t.mouse.holdThreshold?s[e]=-2:s[e]>1?s[e]=-1:s[e]=-3,s.drag[e]>0&&(s.drag[e]=-1)):(s[e]=0,s.drag[e]=0))},O=t._onmouseup;if(t._onmouseup=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),j.call(t,i),O.call(t,e)},this._Touch=class extends t.InputDevice{constructor(e){super(),this.x,this.y,this.id=e.identifier,this._default="duration",this.holdThreshold=t.touches.holdThreshold,this.duration=1,this.drag=0,this._dragFrame=!1,this.canvasPos={},this._update(e)}_update(e){let i=t.canvas;const s=i.getBoundingClientRect(),r=i.scrollWidth/i.w||1,o=i.scrollHeight/i.h||1,h=this.canvasPos.x=(e.clientX-s.left)/r,a=this.canvasPos.y=(e.clientY-s.top)/o;t.camera.x==i.hw&&t.camera.y==i.hh&&1==t.camera.zoom?(this.x=h,this.y=a):(this.x=(h-i.hw)/t.camera.zoom+t.camera.x,this.y=(a-i.hh)/t.camera.zoom+t.camera.y),this.force=e.force}},this.touches=[],t.touches.holdThreshold=12,t._ontouchstart=function(e){if(t._setupDone){t.getAudioContext&&"suspended"==t.getAudioContext()?.state&&t.userStartAudio();for(let i of e.changedTouches)t.touches.push(new t._Touch(i)),1==t.touches.length&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t.world.mouseSprites=t.world.getMouseSprites(),t._onmousedown(e));t.touchStarted&&!t.touchStarted(e)&&e.preventDefault()}},t._ontouchmove=function(e){if(t._setupDone){for(let i of e.changedTouches){let s=t.touches.find((t=>t.id==i.identifier));s._update(i),s._dragFrame=!0,s.id==t.touches[0].id&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t._onmousemove(e))}t.touchMoved&&!t.touchMoved(e)&&e.preventDefault()}},t._ontouchend=function(e){if(t._setupDone){for(let i of e.changedTouches){let s=t.touches.find((t=>t.id==i.identifier));s._update(i),s.duration>=s.holdThreshold?s.duration=-2:s.duration>1?s.duration=-1:s.duration=-3,s.drag>0&&(s.drag=-1),s.id==t.touches[0].id&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t._onmouseup(e))}t.touchEnded&&!t.touchEnded(e)&&e.preventDefault()}},this._Keyboard=class extends t.InputDevice{constructor(){super(),this._default=" ",this.alt=0,this.arrowUp=0,this.arrowDown=0,this.arrowLeft=0,this.arrowRight=0,this.backspace=0,this.capsLock=0,this.control=0,this.enter=0,this.meta=0,this.shift=0,this.tab=0;let t=this._simpleKeyControls={arrowUp:"up",arrowDown:"down",arrowLeft:"left",arrowRight:"right"};t.w=t.W="up",t.s=t.S="down",t.a=t.A="left",t.d=t.D="right",t.i=t.I="up2",t.k=t.K="down2",t.j=t.J="left2",t.l=t.L="right2"}get visible(){return this._inp==document.activeElement}set visible(t){this._inp||(this._inp=Object.assign(document.createElement("input"),{type:"text",style:"position: fixed; height: 0; padding: 0; border: none; opacity: 0.0001; pointer-events: none;"}),document.body.appendChild(this._inp)),this._visible=t,t?this._inp.focus():this._inp.blur()}_ac(t){if(1!=t.length){if(!isNaN(t)){if(38==t)return"arrowUp";if(40==t)return"arrowDown";if(37==t)return"arrowLeft";if(39==t)return"arrowRight";if(t>=10)throw new Error("Use key names with the keyboard input functions, not keyCode numbers!");return t}t=t.replaceAll(/[ _-]/g,"")}if(1!=(t=t.toLowerCase()).length){if("arrowup"==t)return"arrowUp";if("arrowdown"==t)return"arrowDown";if("arrowleft"==t)return"arrowLeft";if("arrowright"==t)return"arrowRight";if("capslock"==t)return"capsLock"}return t}_pre(t){(!this[t]||this[t]<0)&&(this[t]=1)}_rel(t){this[t]>=this.holdThreshold?this[t]=-2:this[t]>1?this[t]=-1:this[t]=-3}get cmd(){return this.meta}get command(){return this.meta}get ctrl(){return this.control}get space(){return this[" "]}get spacebar(){return this[" "]}get opt(){return this.alt}get option(){return this.alt}get win(){return this.meta}get windows(){return this.meta}},this.kb=new t._Keyboard,this.keyboard=t.kb,"object"==typeof navigator&&navigator.keyboard){const e=navigator.keyboard;window==window.top?e.getLayoutMap().then((e=>{"w"!=e.get("KeyW")&&(t.p5play.standardizeKeyboard=!0)})):t.p5play.standardizeKeyboard=!0}else t.p5play.standardizeKeyboard=!0;function P(t){let e=t.code;return 4==e.length&&"Key"==e.slice(0,3)?e[3].toLowerCase():t.key}const F=t._onkeydown;t._onkeydown=function(t){let e=t.key;if(this.p5play.standardizeKeyboard&&(e=P(t)),e.length>1)e=e[0].toLowerCase()+e.slice(1);else{let t=e.toLowerCase(),i=e.toUpperCase();t!=i&&(e!=i?this.kb._pre(i):this.kb._pre(t))}this.kb._pre(e);let i=this.kb._simpleKeyControls[e];i&&this.kb._pre(i),F.call(this,t)};const I=t._onkeyup;t._onkeyup=function(t){let e=t.key;if(this.p5play.standardizeKeyboard&&(e=P(t)),e.length>1)e=e[0].toLowerCase()+e.slice(1);else{let t=e.toLowerCase(),i=e.toUpperCase();t!=i&&(e!=i?this.kb._rel(i):this.kb._rel(t))}this.kb._rel(e);let i=this.kb._simpleKeyControls[e];if(i&&this.kb._rel(i),t.shiftKey){let t=e.toLowerCase();this.kb[t]>0&&this.kb._rel(t)}I.call(this,t)},this.Contro=class extends t.InputDevice{constructor(t){super(),this._default="a",this.connected=!0,this.a=0,this.b=0,this.x=0,this.y=0,this.l=0,this.r=0,this.lt=0,this.rt=0,this.select=0,this.start=0,this.lsb=0,this.rsb=0,this.up=0,this.down=0,this.left=0,this.right=0,this.leftStick={x:0,y:0},this.rightStick={x:0,y:0},this.leftTrigger=0,this.rightTrigger=0,this.buttonMapping={a:0,b:1,x:2,y:3,l:4,r:5,lt:6,rt:7,select:8,start:9,lsb:10,rsb:11,up:12,down:13,left:14,right:15},this.axeMapping={leftStick:{x:0,y:1},rightStick:{x:2,y:3},leftTrigger:4,rightTrigger:5},this.isMock=!1,"string"!=typeof t?(this.gamepad=t,this.id=t.id):(this.gamepad={},this.id=t,this.isMock=!0),this._axeTriggers=this.gamepad.axes&&void 0!==this.gamepad.axes[this.axeMapping.leftTrigger],this.hasAnalogTriggers=this._axeTriggers||void 0,this.id.includes("GuliKit")&&(this.buttonMapping.a=1,this.buttonMapping.b=0,this.buttonMapping.x=3,this.buttonMapping.y=2)}_ac(t){return"lb"==(t=t.toLowerCase())?t="l":"rb"==t?t="r":"leftstickbutton"==t?t="lsb":"rightstickbutton"==t&&(t="rsb"),t}_update(){if(this.isMock)return;if(this.gamepad=navigator.getGamepads()[this.gamepad.index],!this.gamepad?.connected)return;let t=this.gamepad;for(let e in this.buttonMapping){let i=this.buttonMapping[e],s=t.buttons[i];s&&(s.pressed?this[e]++:this[e]=this[e]>0?-1:0)}return this.leftStick.x=t.axes[this.axeMapping.leftStick.x],this.leftStick.y=t.axes[this.axeMapping.leftStick.y],this.rightStick.x=t.axes[this.axeMapping.rightStick.x],this.rightStick.y=t.axes[this.axeMapping.rightStick.y],this._axeTriggers?(this.leftTrigger=t.axes[this.axeMapping.leftTrigger],this.rightTrigger=t.axes[this.axeMapping.rightTrigger]):(this.leftTrigger=t.buttons[this.buttonMapping.lt].value,this.rightTrigger=t.buttons[this.buttonMapping.rt].value,void 0===this.hasAnalogTriggers&&(this.leftTrigger||this.rightTrigger)&&(this.hasAnalogTriggers=!Number.isInteger(this.leftTrigger)||!Number.isInteger(this.rightTrigger))),!0}_reset(){for(let t in this.buttonMapping)this[t]=0;this.leftStick.x=0,this.leftStick.y=0,this.rightStick.x=0,this.rightStick.y=0,this.leftTrigger=0,this.rightTrigger=0}get cross(){return this.a}get circle(){return this.b}get square(){return this.x}get triangle(){return this.y}get ls(){return this.leftStick}get rs(){return this.rightStick}get lb(){return this.l}get rb(){return this.r}get l1(){return this.l}get r1(){return this.r}get zl(){return this.lt}get zr(){return this.rt}get l2(){return this.leftTrigger}get r2(){return this.rightTrigger}get leftStickButton(){return this.lsb}get rightStickButton(){return this.rsb}get l3(){return this.lsb}get r3(){return this.rsb}},this._Contros=class extends Array{constructor(){if(super(),window&&(window.addEventListener("gamepadconnected",(t=>{this._onConnect(t.gamepad)})),window.addEventListener("gamepaddisconnected",(t=>{this._onDisconnect(t.gamepad)}))),"object"!=typeof navigator||!navigator.getGamepads)return;let t=navigator.getGamepads();for(let e of t)e&&this._onConnect(e)}swap(e,i){let s=this[e];this[e]=this[i],this[i]=s,0!=e&&0!=i||(t.contro=this[0],!t._q5&&t._isGlobal&&(window.contro=this[0]))}remove(t){this[t]=null}onConnect(t){return!0}onDisconnect(t){return!1}_onConnect(e){if(e){for(let t=0;tt.p5play._fps,this.renderStats=(t,e)=>{console.error("p5play: renderStats() function is deprecated. Use `p5play.renderStats = true` instead.")}})),p5.prototype.registerMethod("pre",(function(){const t=this;t._q5||(t.p5play._preDrawFrameTime=performance.now()),t.p5play.spritesDrawn=0,t.mouse._update(),t.contros._update()})),p5.prototype.registerMethod("post",(function(){const t=this;if(t.p5play._inPostDraw=!0,window?.location?.hostname.endsWith("codehs.com"))return t.background("yellow"),t.fill("black"),t.textSize(14),t.textAlign(t.LEFT,t.BASELINE),t.text("CodeHS is currently prohibited from using p5play.\n\nCodeHS has failed to comply with p5play's AGPL license since January 11, 2024. CodeHS was notified on September 13, 2024 and acknowledged that their closed source, commercial use of p5play on codehs.com requires a proprietary license. CodeHS has tried to avoid or delay making a deal for too long.\n\nSoftware theft is a violation of the Digital Millennium Copyright Act.\n\nContact CodeHS Support to voice your frustration with this disruption in service. Contact info@p5play.org for more information.",12,12,300),void t.noLoop();if(t.allSprites.autoCull&&t.allSprites.cull(1e4),t.allSprites._autoDraw&&(t.camera.on(),t.allSprites.draw(),t.camera.off()),t.allSprites._autoDraw??=!0,t.p5play.renderStats){let e=t.p5play._renderStats;if(e.fontSize||(1==t.allSprites.tileSize||t.allSprites.tileSize>16?e.fontSize=16:e.fontSize=10,e.gap=1.25*e.fontSize),!t.p5play._fpsAvg||t.frameCount%20==0){let e=0,i=t.p5play._fpsArr.length;for(let s=0;s55?t.color(30,255,30):r>25?t.color(255,100,30):t.color(255,30,30),t.p5play._statsColor=s}t.p5play._fpsArr.push(t.getFPS()),t.push(),t.fill(0,0,0,128),t.rect(e.x-5,e.y-e.fontSize,8.5*e.fontSize,5*e.gap+5),t.fill(t.p5play._statsColor),t.textAlign("left"),t.textSize(e.fontSize),e.font&&t.textFont(e.font);let i=e.x,s=e.y;t.text("sprites: "+t.p5play.spritesDrawn,i,s),t.text("display: "+Math.round(t.frameRate())+"hz",i,s+e.gap),t.text("fps avg: "+t.p5play._fpsAvg,i,s+2*e.gap),t.text("fps min: "+t.p5play._fpsMin,i,s+3*e.gap),t.text("fps max: "+t.p5play._fpsMax,i,s+4*e.gap),t.pop(),e.show=!1}t.world.autoStep&&t.world.timeScale>0&&t.world.step(),t.world.autoStep??=!0,t.allSprites._autoUpdate&&t.allSprites.update(),t.allSprites._autoUpdate??=!0;for(let e of t.allSprites)e.autoDraw??=!0,e.autoUpdate??=!0;for(let e in t.kb)"holdThreshold"!=e&&(t.kb[e]<0?t.kb[e]=0:t.kb[e]>0&&t.kb[e]++);for(let e=0;e0&&e[t]++,i?.hover&&(i[t]=e[t]),e._dragFrame[t]?(e.drag[t]++,i&&(i.drag[t]=e.drag[t]),e._dragFrame[t]=!1):e.drag[t]<0&&(e.drag[t]=0,i&&(i.drag[t]=0));if(t.world.mouseTracking&&t.mouse.isActive){let s=t.world.getMouseSprites();for(let t=0;t0?e.mouse.hover=-1:e.mouse.hover<0&&(e.mouse.hover=0)}e.left<=0&&e.center<=0&&e.right<=0&&(t.world.mouseSprite=null);let r=t.world.mouseSprite,o=e.drag.left>0||e.drag.center>0||e.drag.right>0;for(let e of t.world.mouseSprites)if(!s.includes(e)){let i=e.mouse;i.hover>0&&(i.hover=-1,i.left=i.center=i.right=0),o||e!=r||(t.world.mouseSprite=r=null)}r&&(s.includes(r)||s.push(r),i.x=r.x-e.x,i.y=r.y-e.y),t.world.mouseSprites=s}t.camera.off(),t._q5||(t.p5play._postDrawFrameTime=performance.now(),t.p5play._fps=Math.round(1e3/(t.p5play._postDrawFrameTime-t.p5play._preDrawFrameTime))||1),t.p5play._inPostDraw=!1})); +if("object"!=typeof planck){if("object"!=typeof process)throw"planck.js must be loaded before p5play";global.planck=require("./planck.min.js")}p5.prototype.registerMethod("init",(function(){const t=this,e=planck;if("object"!=typeof process&&0!=window._p5play_gtagged){let t=document.createElement("script");t.src="https://www.googletagmanager.com/gtag/js?id=G-EHXNCTSYLK",t.async=!0,document.head.append(t),window._p5play_gtagged=!0,t.onload=()=>{window.dataLayer??=[],window.gtag=function(){dataLayer.push(arguments)},gtag("js",new Date),gtag("config","G-EHXNCTSYLK"),gtag("event","p5play_v3_25")}}const i=t.DEGREES;t.angleMode(i);const s=(i,s,r)=>new e.Vec2(i*r/t.world.meterSize,s*r/t.world.meterSize),r=(i,s,r)=>new e.Vec2(i/r*t.world.meterSize,s/r*t.world.meterSize),o=e.Settings.linearSlop,h=e.Settings.angularSlop/60,a=t=>Math.abs(t)<=o,n=(t,e)=>Math.abs(t-Math.round(t))<=(e||o)?Math.round(t):t,l=(e,s)=>{let r=t._angleMode==i?360:t.TWO_PI,o=(e-s)%r,h=(r-Math.abs(o))*-Math.sign(o);return(Math.abs(o)-1){let e=navigator.userAgent.substring(t+10,t+12);this.os.platform="iOS",this.os.version=e}else{let t=navigator.userAgentData?.platform;!t&&navigator.platform&&(t=navigator.platform.slice(3),"Mac"==t?t="macOS":"Win"==t?t="Windows":"Lin"==t&&(t="Linux")),this.os.platform=t}}this.renderStats=!1,this._renderStats={x:10,y:20,font:"monospace"},this._fps=60,this._fpsArr=[60],this._collides={},this._colliding={},this._collided={},this._overlaps={},this._overlapping={},this._overlapped={}}onImageLoad(){}},this.p5play=new t.P5Play,delete t.P5Play;const p=console.log;this.log=console.log,this.Sprite=class{constructor(i,s,r,o,h){this._isSprite=!0,this.idNum;let a,l,d=[...arguments];if(void 0!==d[0]&&d[0]._isGroup&&(a=d[0],d=d.slice(1)),void 0!==d[0]&&("string"==typeof d[0]||d[0]instanceof t.Ani||d[0]instanceof p5.Image)&&(l=d[0],d=d.slice(1)),1==d.length&&"number"==typeof d[0])throw new C("Sprite",0,[d[0]]);if(Array.isArray(d[0])){if(i=void 0,s=void 0,r=d[0],o=void 0,h=d[1],Array.isArray(h))throw new C("Sprite",1,[`[[${r}], [${o}]]`])}else i=d[0],s=d[1],r=d[2],o=d[3],h=d[4];"string"==typeof r&&(h=r,r=void 0),"string"==typeof o&&(!function(t){if("d"==t||"s"==t||"k"==t||"n"==t)return!0;let e=t.slice(0,2);return"dy"==e||"st"==e||"ki"==e||"no"==e}(o)?r=_(r,o):h=o,o=void 0),this.idNum=t.p5play.spritesCreated,this._uid=1e3+this.idNum,t.p5play.sprites[this._uid]=this,t.p5play.spritesCreated++,this.groups=[],this.animations=new t.Anis,this.joints=[],this.joints.removeAll=()=>{for(;this.joints.length;)this.joints.at(-1).remove()},this.watch,this.mod={},this._removed=!1,this._life=2147483647,this._visible=!0,this._pixelPerfect=!1,this._aniChangeCount=0,this._draw=()=>this.__draw(),this._hasOverlap={},this._collisions={},this._overlappers={},a??=t.allSprites,this._tile="",this.tileSize=a.tileSize||1;let p=this;this._position={x:0,y:0},this._pos=t.createVector.call(t),Object.defineProperty(this._pos,"x",{get(){if(!p.body)return p._position.x;let e=p.body.getPosition().x/p.tileSize*t.world.meterSize;return t.p5play.friendlyRounding?n(e):e},set(i){if(p.body){let s=new e.Vec2(i*p.tileSize/t.world.meterSize,p.body.getPosition().y);p.body.setPosition(s)}p._position.x=i}}),Object.defineProperty(this._pos,"y",{get(){if(!p.body)return p._position.y;let e=p.body.getPosition().y/p.tileSize*t.world.meterSize;return t.p5play.friendlyRounding?n(e):e},set(i){if(p.body){let s=new e.Vec2(p.body.getPosition().x,i*p.tileSize/t.world.meterSize);p.body.setPosition(s)}p._position.y=i}}),this._canvasPos=t.createVector.call(t),Object.defineProperty(this._canvasPos,"x",{get(){let e=p._pos.x-t.camera.x;return"2d"==t.canvas.renderer&&(e+=t.canvas.hw/t.camera._zoom),e}}),Object.defineProperty(this._canvasPos,"y",{get(){let e=p._pos.y-t.camera.y;return"2d"==t.canvas.renderer&&(e+=t.canvas.hh/t.camera._zoom),e}}),this._velocity={x:0,y:0},this._direction=0,this._vel=t.createVector.call(t),Object.defineProperties(this._vel,{x:{get(){let e;return e=p.body?p.body.getLinearVelocity().x:p._velocity.x,e/=p.tileSize,t.p5play.friendlyRounding?n(e):e},set(t){t*=p.tileSize,p.body?p.body.setLinearVelocity(new e.Vec2(t,p.body.getLinearVelocity().y)):p._velocity.x=t,(t||this.y)&&(p._direction=this.heading())}},y:{get(){let e;return e=p.body?p.body.getLinearVelocity().y:p._velocity.y,e/=p.tileSize,t.p5play.friendlyRounding?n(e):e},set(t){t*=p.tileSize,p.body?p.body.setLinearVelocity(new e.Vec2(p.body.getLinearVelocity().x,t)):p._velocity.y=t,(t||this.x)&&(p._direction=this.heading())}}}),this._mirror={_x:1,_y:1,get x(){return this._x<0},set x(t){p.watch&&(p.mod[20]=!0),this._x=t?-1:1},get y(){return this._y<0},set y(t){p.watch&&(p.mod[20]=!0),this._y=t?-1:1}},this._heading="right",this._layer=a._layer,this._layer??=t.allSprites._getTopLayer()+1,a.dynamic&&(h??="dynamic"),a.kinematic&&(h??="kinematic"),a.static&&(h??="static"),h??=a.collider,h&&"string"==typeof h||(h="dynamic"),this.collider=h,i??=a.x,void 0===i&&(i="2d"!=t.canvas?.renderer||t._webgpuFallback?0:t.canvas.hw/this.tileSize,r&&(this._vertexMode=!0)),s??=a.y,void 0===s&&(s="2d"!=t.canvas?.renderer||t._webgpuFallback?0:t.canvas.hh/this.tileSize);let g=!1;if(void 0===r&&(r=a.w||a.width||a.d||a.diameter||a.v||a.vertices,o||a.d||a.diameter||(o=a.h||a.height,g=!0)),"function"==typeof i&&(i=i(a.length)),"function"==typeof s&&(s=s(a.length)),"function"==typeof r&&(r=r(a.length)),"function"==typeof o&&(o=o(a.length)),this.x=i,this.y=s,!a._isAllSpritesGroup&&!l){for(let t in a.animations){l=t;break}l||(l=a._img,"function"==typeof l&&(l=l(a.length)),l&&(this._img=!0))}for(let e=a;e;e=t.p5play.groups[e.parent])this.groups.push(e);if(this.groups.reverse(),l){let e=this.tileSize;this._img||l instanceof p5.Image?(this.image="string"!=typeof l?l:new t.EmojiImage(l,r),r||1==this._img.w&&1==this._img.h||(r=(this._img.defaultWidth||this._img.w)/e,o??=(this._img.defaultHeight||this._img.h)/e)):("string"==typeof l?this._changeAni(l):this._ani=l.clone(),r||1==this._ani.w&&1==this._ani.h||(r=(this._ani.defaultWidth||this._ani.w)/e,o??=(this._ani.defaultHeight||this._ani.h)/e))}if(this.groups=[],this.mouse=new t._SpriteMouse,this._rotation=0,this._rotationSpeed=0,this._bearing=0,this._scale=new u,Object.defineProperty(this._scale,"x",{get(){return this._x},set(t){if(t==this._x)return;p.watch&&(p.mod[26]=!0);let e=Math.abs(t/this._x);p._w*=e,p._hw*=e,p._resizeColliders({x:e,y:1}),this._x=t,this._avg=.5*(this._x+this._y)}}),Object.defineProperty(this._scale,"y",{get(){return this._y},set(t){if(t==this._y)return;p.watch&&(p.mod[26]=!0);let e=Math.abs(t/this._y);p._h&&(this._h*=e,this._hh*=e),p._resizeColliders({x:1,y:e}),this._y=t,this._avg=.5*(this._x+this._y)}}),this._offset={_x:0,_y:0,get x(){return this._x},set x(t){t!=this._x&&(p.watch&&(p.mod[21]=!0),p._offsetCenterBy(t-this._x,0))},get y(){return this._y},set y(t){t!=this._y&&(p.watch&&(p.mod[21]=!0),p._offsetCenterBy(0,t-this._y))}},this._massUndef=!0,void 0===r&&(this._dimensionsUndef=!0,this._widthUndef=!0,r=this.tileSize>1?1:50,void 0===o&&(this._heightUndef=!0)),g&&(o??=this.tileSize>1?1:50),this._shape=a.shape,3!=this.__collider)this._vertexMode?this.addCollider(r):this.addCollider(0,0,r,o),this.shape=this._shape;else{if(this.w=r,Array.isArray(r))throw new Error('Cannot set the collider type of a sprite with a polygon or chain shape to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');void 0!==r&&void 0===o?this.shape="circle":(this.shape="box",this.h=o)}this.prevPos={x:i,y:s},this.prevRotation=0,this._dest={x:i,y:s},this._destIdx=0,this._debug=!1,this.text,a._isAllSpritesGroup||t.allSprites.push(this),a.push(this);let f=a.vel.x||0,m=a.vel.y||0;"function"==typeof f&&(f=f(a.length-1)),"function"==typeof m&&(m=m(a.length-1)),this.vel.x=f,this.vel.y=m;let y=["ani","collider","x","y","w","h","d","diameter","dynamic","height","kinematic","static","vel","width"];for(let e of t.Sprite.propsAll){if(y.includes(e))continue;let i=a[e];void 0!==i&&("function"==typeof i&&c(i)&&(i=i(a.length-1)),"object"==typeof i?i instanceof p5.Color?this[e]=t.color(...i.levels):this[e]=Object.assign({},i):this[e]=i)}y=["add","animation","animations","autoCull","contains","GroupSprite","Group","idNum","length","mod","mouse","p","parent","Sprite","Subgroup","subgroups","velocity"];for(let e=0;e1?1:50,h??=o,d=s(o-.08,h-.08,this.tileSize)),"box"==l)p=e.Box(d.x/2,d.y/2,s(i,r,this.tileSize),0);else if("circle"==l)p=e.Circle(s(i,r,this.tileSize),d.x/2);else if(n){let c,g,f=[{x:0,y:0}],m={x:0,y:0},y={x:0,y:0},w={x:0,y:0},v=Array.isArray(n[0]);function x(){m.xw.x&&(w.x=m.x),m.y>w.y&&(w.y=m.y)}if(v){this._vertexMode&&(c=n[0][0],g=n[0][1],this.fixture&&this._relativeOrigin?(c=this.x-this._relativeOrigin.x,g=this.y-this._relativeOrigin.y,f.pop()):(this.x=c,this.y=g));for(let S=0;S0?1:-1;A=Math.abs(A);let k=0;for(let M=0;Me.Settings.maxPolygonVertices||"chain"==this._shape)&&(l="chain"),"polygon"==l?p=e.Polygon(f):"chain"==l&&(p=e.Chain(f,!1))}if(this.shape??=l,this.fixtureList){this._extents??={t:this.hh,b:this.hh,l:this._hw,r:this._hw};let G=this._extents,N=i-.5*o,E=i+.5*o,R=r-.5*h,U=r+.5*h;NG.r&&(G.r=E),RG.b&&(G.b=U),this._totalWidth=G.r-G.l,this._totalHeight=G.b-G.t;let V=Math.abs;this._largestExtent=Math.max(V(G.l),V(G.r),V(G.t),V(G.b))}else this._w=o,this._hw=.5*o,1!=this.__shape&&(this._h=h,this._hh=.5*h);return p}removeColliders(){this.body&&(this._removeContacts(0),this._removeFixtures(0))}removeSensors(){this.body&&(this._removeContacts(1),this._removeFixtures(1),this._hasSensors=!1)}_removeFixtures(e){let i;for(let s=this.fixtureList;s;s=s.getNext())if(void 0===e||s.m_isSensor==e){let e=s.m_next;s.destroyProxies(t.world.m_broadPhase),i?i.m_next=e:this.body.m_fixtureList=e}else i=s}_removeContacts(e){if(!this.body)return;let i=this.body.m_contactList;for(;i;){let s=i.contact;i=i.next,void 0!==e&&s.m_fixtureA.m_isSensor!=e||t.world.destroyContact(s)}}_offsetCenterBy(t,e){if(!t&&!e)return;if(this._offset._x+=t,this._offset._y+=e,!this.body)return;let i=s(t,e,this.tileSize);this.__offsetCenterBy(i.x,i.y)}__offsetCenterBy(t,e){for(let i=this.body.m_fixtureList;i;i=i.m_next){let s=i.m_shape;if("circle"!=s.m_type){let i=s.m_vertices;for(let s of i)s.x+=t,s.y+=e}else s.m_p.x+=t,s.m_p.y+=e}}_cloneBodyProps(){let t={},e=["bounciness","density","drag","friction","heading","isSuperFast","rotation","rotationDrag","rotationLock","rotationSpeed","scale","vel","x","y"];this._massUndef&&this._dimensionsUndef||e.push("mass");for(let i of e)"object"==typeof this[i]?t[i]=Object.assign({},this[i]):t[i]=this[i];return t}get animation(){return this._ani}set animation(t){this.changeAni(t)}get ani(){return this._ani}set ani(t){this.changeAni(t)}get anis(){return this.animations}get autoDraw(){return this._autoDraw}set autoDraw(t){this._autoDraw=t}get allowSleeping(){return this.body?.isSleepingAllowed()}set allowSleeping(t){this.watch&&(this.mod[5]=!0),this.body&&this.body.setSleepingAllowed(t)}get autoUpdate(){return this._autoUpdate}set autoUpdate(t){this._autoUpdate=t}get bounciness(){if(this.fixture)return this.fixture.getRestitution()}set bounciness(t){this.watch&&(this.mod[7]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setRestitution(t)}get collider(){return this._collider}set collider(e){if(e==this._collider)return;let i=(e=e.toLowerCase())[0];if("d"==i&&(e="dynamic"),"s"==i&&(e="static"),"k"==i&&(e="kinematic"),"n"==i&&(e="none"),e==this._collider)return;if("none"==e&&("chain"==this._shape||"polygon"==this._shape))return void console.error('Cannot set the collider type of a polygon or chain collider to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');if(this._removed)throw new Error("Cannot change the collider type of a sprite that was removed.");let s=this.__collider;this._collider=e,this.__collider=["d","s","k","n"].indexOf(i),this.watch&&(this.mod[8]=!0),void 0!==s&&(3!=this.__collider?(this.body&&this.body.setType(e),3==s&&(this.addCollider(),this.x=this._position.x,this.y=this._position.y,this.vel.x=this._velocity.x,this.vel.y=this._velocity.y,this.rotation=this._rotation,this.rotationSpeed=this._rotationSpeed)):(this.removeColliders(),this.fixture?.m_isSensor?this.body.m_gravityScale=0:(this._position.x=this.x,this._position.y=this.y,this._velocity.x=this.vel.x,this._velocity.y=this.vel.y,this._rotation=this.rotation,this._rotationSpeed=this.rotationSpeed,t.world.destroyBody(this.body),this.body=null)))}_parseColor(e){return e instanceof p5.Color?e:"object"!=typeof e?1==e.length?t.colorPal(e):t.color(e):t.color(...e.levels)}get color(){return this._color}set color(t){this.watch&&(this.mod[9]=!0),this._color=this._parseColor(t)}get colour(){return this._color}set colour(t){this.color=t}get fill(){return this._color}set fill(t){this.color=t}get fillColor(){return this._color}set fillColor(t){this.color=t}get stroke(){return this._stroke}set stroke(t){this.watch&&(this.mod[29]=!0),this._stroke=this._parseColor(t)}get strokeColor(){return this._stroke}set strokeColor(t){this.stroke=t}get strokeWeight(){return this._strokeWeight}set strokeWeight(t){this.watch&&(this.mod[30]=!0),this._strokeWeight=t}get textColor(){return this._textFill}set textColor(t){this.watch&&(this.mod[32]=!0),this._textFill=this._parseColor(t)}get textColour(){return this._textFill}set textColour(t){this.textColor=t}get textFill(){return this._textFill}set textFill(t){this.textColor=t}get textSize(){return this._textSize}set textSize(t){this.watch&&(this.mod[33]=!0),this._textSize=t}get textStroke(){return this._textStroke}set textStroke(t){this.watch&&(this.mod[34]=!0),this._textStroke=this._parseColor(t)}get textStrokeWeight(){return this._textStrokeWeight}set textStrokeWeight(t){this.watch&&(this.mod[35]=!0),this._textStrokeWeight=t}get tile(){return this._tile}set tile(t){this.watch&&(this.mod[36]=!0),this._tile=t}get tileSize(){return this._tileSize}set tileSize(t){this.watch&&(this.mod[37]=!0),this._tileSize=t}get bearing(){return this._bearing}set bearing(t){this.watch&&(this.mod[6]=!0),this._bearing=t}get debug(){return this._debug}set debug(t){this.watch&&(this.mod[10]=!0),this._debug=t}get density(){if(this.fixture)return this.fixture.getDensity()}set density(t){this.watch&&(this.mod[11]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setDensity(t)}_getDirectionAngle(e){e=e.toLowerCase().replaceAll(/[ _-]/g,"");let i={up:-90,down:90,left:180,right:0,upright:-45,rightup:-45,upleft:-135,leftup:-135,downright:45,rightdown:45,downleft:135,leftdown:135,forward:this.rotation,backward:this.rotation+180}[e];return"radians"==t._angleMode&&(i=t.radians(i)),i}get direction(){return 0!==this.vel.x||0!==this.vel.y?t.atan2(this.vel.y,this.vel.x):this._isTurtleSprite?this.rotation:this._direction}set direction(e){this.watch&&(this.mod[12]=!0),"string"==typeof e&&(this._heading=e,e=this._getDirectionAngle(e)),this._direction=e,this._isTurtleSprite&&(this.rotation=e);let i=this.speed;this.vel.x=t.cos(e)*i,this.vel.y=t.sin(e)*i}get drag(){return this.body?.getLinearDamping()}set drag(t){this.watch&&(this.mod[13]=!0),this.body&&this.body.setLinearDamping(t)}get draw(){return this._display}set draw(t){this._userDefinedDraw=!0,this._draw=t}get dynamic(){return this.body?.isDynamic()}set dynamic(t){this.collider=t?"dynamic":"kinematic"}get fixture(){return this.fixtureList}get fixtureList(){return this.body?this.body.m_fixtureList:null}get friction(){if(this.fixture)return this.fixture.getFriction()}set friction(t){this.watch&&(this.mod[14]=!0);for(let e=this.fixtureList;e;e=e.getNext())e.setFriction(t)}get heading(){return this._heading}set heading(t){this.direction=t}get img(){return this._img||this._ani?.frameImage}set img(t){this.image=t}get image(){return this._img||this._ani?.frameImage}set image(e){"string"==typeof e&&(e=e.includes(".")?t.loadImage(e):new t.EmojiImage(e,this.w)),this._img=this._extendImage(e)}_extendImage(t){return t.offset??={x:0,y:0},t._scale??={x:1,y:1},t.scale||Object.defineProperty(t,"scale",{get:()=>t._scale,set:e=>{"number"==typeof e&&(e={x:e,y:e}),t._scale=e}}),t}get isMoving(){return 0!=this.vel.x||0!=this.vel.y}get isSuperFast(){return this.body?.isBullet()}set isSuperFast(t){this.watch&&(this.mod[16]=!0),this.body&&this.body.setBullet(t)}get kinematic(){return this.body?.isKinematic()}set kinematic(t){this.collider=t?"kinematic":"dynamic"}get layer(){return this._layer}set layer(t){this.watch&&(this.mod[17]=!0),this._layer=t}get life(){return this._life}set life(t){this.watch&&(this.mod[18]=!0),this._life=t}get mass(){return this.body?.getMass()}set mass(t){if(!this.body)return;this.watch&&(this.mod[19]=!0);const i={I:0,center:new e.Vec2(this.body.getLocalCenter()),mass:0};this.body.getMassData(i),i.mass=t>0?t:1e-8,this.body.setMassData(i),delete this._massUndef}resetMass(){if(!this.body)return;let t=new e.Vec2(this.body.getLocalCenter());this.watch&&(this.mod[19]=!0),this.body.resetMassData(),this.body.setMassData({mass:this.body.getMass(),center:t,I:this.body.getInertia()})}resetCenterOfMass(){this.watch&&(this.mod[19]=!0),this.body.resetMassData();let{x:t,y:e}=this.body.getLocalCenter();if(0==t&&0==e)return;this.__offsetCenterBy(-t,-e),this.body.resetMassData();let i=this.body.getPosition();this.body.setPosition({x:i.x+t,y:i.y+e})}get mirror(){return this._mirror}set mirror(t){this.watch&&(this.mod[20]=!0),void 0!==t.x&&(this._mirror.x=t.x),void 0!==t.y&&(this._mirror.y=t.y)}get offset(){return this._offset}set offset(t){t.x??=this._offset._x,t.y??=this._offset._y,t.x==this._offset._x&&t.y==this._offset._y||(this.watch&&(this.mod[21]=!0),this._offsetCenterBy(t.x-this._offset._x,t.y-this._offset._y))}get opacity(){return this._opacity??1}set opacity(t){this.watch&&(this.mod[41]=!0),this._opacity=t}get previousPosition(){return this.prevPos}set previousPosition(t){this.prevPos=t}get previousRotation(){return this.prevRotation}set previousRotation(t){this.prevRotation=t}get pixelPerfect(){return this._pixelPerfect}set pixelPerfect(t){this.watch&&(this.mod[22]=!0),this._pixelPerfect=t}get removed(){return this._removed}set removed(t){t&&!this._removed&&(this.watch&&(this.mod[23]=!0),this._removed=!0,this._remove())}get rotation(){if(!this.body)return this._rotation||0;let e=this.body.getAngle();return e=t.p5play.friendlyRounding?n(e,h):e,t._angleMode==i&&(e=t.degrees(e)),e}set rotation(e){this.body?(t._angleMode==i&&(e=t.radians(e%360)),this.body.setAngle(e),this.body.synchronizeTransform()):this._rotation=e}get rotationDrag(){return this.body?.getAngularDamping()}set rotationDrag(t){this.body&&(this.watch&&(this.mod[24]=!0),this.body.setAngularDamping(t))}get rotationLock(){return this.body?.isFixedRotation()}set rotationLock(t){if(!this.body)return;this.watch&&(this.mod[25]=!0);let e=this.mass;this.body.setFixedRotation(t),this.mass=e}get rotationSpeed(){if(this.body){let e=this.body.getAngularVelocity()/60;return t._angleMode==i?t.degrees(e):e}return this._rotationSpeed}set rotationSpeed(e){this.body?(e*=60,t._angleMode==i&&(e=t.radians(e)),this.body.setAngularVelocity(e)):this._rotationSpeed=e}get scale(){return this._scale}set scale(t){if(0==t&&(t=.01),"number"==typeof t?t={x:t,y:t}:(t.x??=this._scale._x,t.y??=this._scale._y),t.x==this._scale._x&&t.y==this._scale._y)return;this.watch&&(this.mod[26]=!0);let e={x:Math.abs(t.x/this._scale._x),y:Math.abs(t.y/this._scale._y)};this._w*=e.x,this._hw*=e.x,this._h&&(this._h*=e.y,this._hh*=e.y),this._resizeColliders(e),this._scale._x=t.x,this._scale._y=t.y,this._scale._avg=t.x}get sleeping(){if(this.body)return!this.body.isAwake()}set sleeping(t){this.body&&(this.watch&&(this.mod[28]=!0),this.body.setAwake(!t))}get speed(){return t.createVector(this.vel.x,this.vel.y).mag()}set speed(e){let i=this.direction;this.vel.x=t.cos(i)*e,this.vel.y=t.sin(i)*e}get static(){return this.body?.isStatic()}set static(t){this.collider=t?"static":"dynamic"}get tint(){return this._tint}set tint(t){this.watch&&(this.mod[38]=!0),this._tint=this._parseColor(t)}get tintColor(){return this._tint}set tintColor(t){this.tint=t}set vertices(t){if(3==this.__collider)throw new Error('Cannot set vertices of a sprite with collider type of "none".');this.watch&&(this.mod[27]=!0),this._removeFixtures(),this._originMode="start",this.addCollider(t),this._hasSensors&&this.addDefaultSensors()}get vertices(){return this._getVertices()}_getVertices(e){let i=this.fixture.getShape(),s=[...i.m_vertices];"polygon"==i.m_type&&s.unshift(s.at(-1));let r=this.x,o=this.y;for(let i=0;i=2)return void console.error('Cannot set the collider shape to chain or polygon if the sprite has a collider type of "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');let s,r,o=this.__shape;if(this.__shape=i,this._shape=e,this.watch&&(this.mod[27]=!0),void 0===o)return;if(0==this.__shape?(this._h=this._w,this._hh=this._hw):(this._h=void 0,this._hh=void 0),1!=o&&1!=this.__shape?s=this._getVertices(!0):r=this._w,this._removeFixtures(),3!=this.__collider)if(s)this._originMode??="center",this.addCollider(s);else if(1==o){let t=this._w*Math.sin(Math.PI/12);this.addCollider(0,0,[t,-30,12])}else this.addCollider();this._hasSensors&&this.addDefaultSensors();let h=this._offset._x,a=this._offset._y;(h||a)&&(this._offset._x=0,this._offset._y=0,this._offsetCenterBy(h,a))}get update(){return this._update}set update(t){this._customUpdate=t}get vel(){return this._vel}set vel(t){this.vel.x=t.x,this.vel.y=t.y}get velocity(){return this._vel}set velocity(t){this.vel=t}get gravityScale(){return this.body?.getGravityScale()}set gravityScale(t){this.body&&(this.watch&&(this.mod[42]=!0),this.body.setGravityScale(t))}_update(){this._ani?.update&&this._ani.update();for(let t in this.mouse)-1==this.mouse[t]&&(this.mouse[t]=0);this._customUpdate&&this._customUpdate(),this.autoUpdate&&(this.autoUpdate=null)}_step(){this.life-=t.world.timeScale,2147483647!=this._life&&this._life<=0&&this.remove(),this.body||this._removed||(this.rotation+=this._rotationSpeed,this.x+=this.vel.x,this.y+=this.vel.y),this.watch&&(this.x!=this.prevX&&(this.mod[0]=this.mod[2]=!0),this.y!=this.prevY&&(this.mod[1]=this.mod[2]=!0),this.rotation!=this.prevRotation&&(this.mod[3]=this.mod[4]=!0)),(this.body||this._removed)&&this.__step()}__step(){let e,i=this;for(let s in d)for(let r in this[s]){if(r>=1e3){if(i._isGroup||i._uid>=r)continue;e=t.p5play.sprites[r]}else{if(i._isGroup&&i._uid>=r)continue;e=t.p5play.groups[r]}let o=i[s][r]+1;e&&0!=o&&-2!=o?(this[s][r]=o,e[s][i._uid]=o):(delete i[s][r],e&&delete e[s][i._uid])}}___step(){let e,i,s,r,o=this,h=!0;for(let a in d){for(let n in this[a]){if(n>=1e3){if(o._isGroup||o._uid>=n)continue;e=t.p5play.sprites[n]}else{if(o._isGroup&&o._uid>=n)continue;e=t.p5play.groups[n]}if(o._isGroup||e?._isGroup)continue;if(s=o._hasOverlap[e._uid]??e._hasOverlap[o._uid],h&&!1!==s||!h&&!0!==s)continue;let l=o[a][n];for(let s=0;s<3;s++){if(0==s&&1!=l&&-3!=l)continue;if(1==s&&-1==l)continue;if(2==s&&l>=1)continue;i=d[a][s];let h=t.p5play[i][o._uid];if(h){r=h[e._uid],r&&r.call(o,o,e,l);for(let t of e.groups)r=h[t._uid],r&&r.call(o,o,e,l)}let n=t.p5play[i][e._uid];if(n){r=n[o._uid],r&&r.call(e,e,o,l);for(let t of o.groups)r=n[t._uid],!r||h&&r==h[t._uid]||r.call(e,e,o,l)}}}h=!1}if(this._removed&&0==Object.keys(this._collisions).length&&0==Object.keys(this._overlappers).length){this._isSprite?delete t.p5play.sprites[this._uid]:t.p5play.storeRemovedGroupRefs||delete t.p5play.groups[this._uid];for(let e in d)for(let i of d[e])delete t.p5play[i][this._uid]}}__draw(){if(!t.p5play.disableImages)if(this._ani)this._ani.draw(this._offset._x,this._offset._y,0,this._scale._x,this._scale._y);else if(this._img){let e=this._img,i=1!=this._scale._x||1!=this._scale._y||1!=e.scale.x||1!=e.scale.y;i&&(t.push(),t.scale(this._scale._x*e.scale.x,this._scale._y*e.scale.y)),t.image(e,this._offset._x+e.offset.x,this._offset._y+e.offset.y),i&&t.pop()}if(!this._ani&&!this._img||this.debug||t.p5play.disableImages)if(this.debug&&(t.noFill(),t.stroke(0,255,0),t.line(0,-2,0,2),t.line(-2,0,2,0)),3!=this.__collider){this.debug||0===this._strokeWeight?t.noStroke():2==this.__shape?t.stroke(this.stroke||this.color):this._stroke&&t.stroke(this._stroke);for(let e=this.fixtureList;e;e=e.getNext()){if(this.debug)e.m_isSensor?t.stroke(255,255,0,127):t.stroke(0,255,0,127);else if(e.m_isSensor)continue;this._drawFixture(e)}}else 0!==this._strokeWeight&&t.stroke(this._stroke||120),0==this.__shape?t.rect(this._offset._x,this._offset._y,this.w*this.tileSize,this.h*this.tileSize):1==this.__shape&&t.circle(this._offset._x,this._offset._y,this.d*this.tileSize);void 0!==this.text&&(t.textAlign(t.CENTER,t.CENTER),t.fill(this._textFill),this._textStrokeWeight&&t.strokeWeight(this._textStrokeWeight),this._textStroke?t.stroke(this._textStroke):t.noStroke(),t.textSize(this.textSize*this.tileSize),t.text(this.text,0,0))}_display(){let e,i=this.x*this.tileSize+t.world.origin.x,s=this.y*this.tileSize+t.world.origin.y;if(!this._userDefinedDraw){let e;if(e=this._totalWidth?Math.max(this._totalWidth,this._totalHeight):void 0!==this._h?Math.max(this._w,this._h):this._w,this.ani&&!t.p5play.disableImages&&(e=Math.max(e,this.ani.w,this.ani.h)),"chain"!=this.shape&&t.camera.isActive&&(i+et.camera.bound.max.x||s+et.camera.bound.max.y))return void(this._visible=null)}if(this._visible=!0,t.p5play.spritesDrawn++,this._pixelPerfect){let e,r;this.ani&&this.ani.length&&!t.p5play.disableImages?(e=this.ani[this.ani._frame].w,r=this.ani[this.ani._frame].h):(e=this._w,r=this._h),i=e%2==0?Math.round(i):Math.round(i-.5)+.5,s=r%2==0?Math.round(s):Math.round(s-.5)+.5}else i=n(i),s=n(s);for(let t of this.joints)t.visible?this._uid==t.spriteA._uid?(!t.spriteB._visible||this.layer<=t.spriteB.layer)&&t._display():(!t.spriteA._visible||this.layer{let s,r;do{if(await t.sleep(),c!=this._destIdx)return!1;let o=this.direction<0?this.direction+360:this.direction;if(u&&(o<=n||o>=l)||Math.abs(this.vel.x)<=d&&Math.abs(this.vel.y)<=d)return!1;e&&(s=this.vel.x>0?this._dest.x-this.x:this.x-this._dest.x),i&&(r=this.vel.y>0?this._dest.y-this.y:this.y-this._dest.y)}while(e&&s>p||i&&r>p);return this.x=this._dest.x,this.y=this._dest.y,this.vel.x=0,this.vel.y=0,!0})()}rotateTowards(t,e){if(1==this.__collider)return void new C(0);let i,s,r,o=arguments;"number"!=typeof o[0]?(i=o[0].x,s=o[0].y,e=o[1],r=o[2]):arguments.length>2&&(i=o[0],s=o[1],e=o[2],r=o[3]),void 0!==i?t=this.angleToFace(i,s,r):t-=this.rotation,e??=.1,this.rotationSpeed=t*e}angleTo(e,i){if("object"==typeof e){let s=e;if(s==t.mouse&&!t.mouse.isActive)return 0;if(void 0===s.x||void 0===s.y)return console.error("sprite.angleTo ERROR: rotation destination not defined, object given with no x or y properties"),0;i=s.y,e=s.x}return t.atan2(i-this.y,e-this.x)}rotationToFace(t,e,i){return"object"==typeof t&&(i=e,e=t.y,t=t.x),Math.abs(t-this.x)<.01&&Math.abs(e-this.y)<.01?0:this.angleTo(t,e)+(i||0)}angleToFace(t,e,i){let s=this.rotationToFace(t,e,i);return l(s,this.rotation)}rotateTo(e,s,r){if(1==this.__collider)return void new C(0);let o=arguments;if("number"!=typeof o[0]?e=this.rotationToFace(o[0].x,o[0].y,r):o.length>2&&(r=o[3],s=o[2],e=this.rotationToFace(o[0],o[1],r)),e==this.rotation)return;let h=t._angleMode==i?360:t.TWO_PI;return(e=(e-this.rotation)%h)<0&&s>0&&(e+=h),e>0&&s<0&&(e-=h),s??=this.rotationSpeed||Math.sign(e),this.rotate(e,s)}rotateMinTo(t,e,i){if(1==this.__collider)return void new C(0);let s=arguments;return"number"!=typeof s[0]?t=this.rotationToFace(s[0].x,s[0].y,i):s.length>2&&(i=s[3],e=s[2],t=this.rotationToFace(s[0],s[1],i)),t!=this.rotation?(t=l(t,this.rotation),e??=this.rotationSpeed>.1?this.rotationSpeed:1,e=Math.abs(e)*Math.sign(t),this.rotate(t,e)):void 0}rotate(e,i){if(1==this.__collider)return void new C(0);if(isNaN(e))return void new C(1,[e]);if(0==e)return;i??=this.rotationSpeed||1;let s=e>0&&i>0;s||(e=-Math.abs(e),i=-Math.abs(i)),this.rotationSpeed=i;let r=Math.abs(i),o=this.rotation+e;this._rotateIdx??=0,this._rotateIdx++;let h=this._rotateIdx;return(async()=>{let e=.01;do{let a=Math.abs(o-this.rotation);if(r>a&&(this.rotationSpeed=a*Math.sign(i)),await t.sleep(),this._rotateIdx!=h)return!1;if(s&&this.rotationSpeed-.01)return!1}while((s&&o>this.rotation||!s&&o1)e=[...arguments];else if(e instanceof t.Ani){if(e==this._ani)return;e=[e]}else if(!Array.isArray(e)){if(e==this._ani?.name)return;e=[e]}let i,s;this._aniChangeCount++;for(let r=0;r1&&("!"==o.name[0]&&(o.name=o.name.slice(1),o.start=-1,o.end=0),"<"!=o.name[0]&&">"!=o.name[0]||(o.name=o.name.slice(1),o.flipX=!0),"^"==o.name[0]&&(o.name=o.name.slice(1),o.flipY=!0),"**"==o.name&&(i=!0,e=e.slice(0,-1)),";;"==o.name&&(s=!0,e=e.slice(0,-1)))}let r=this._aniChangeCount;do{for(let t=0;t1&&(i.start=0),await this._playSequencedAni(i)}}while(i&&r==this._aniChangeCount);1!=e.length&&s&&this._ani.stop()}_playSequencedAni(t){return new Promise((e=>{let{name:i,start:s,end:r,flipX:o,flipY:h}=t;this._changeAni(i),o&&(this._ani.scale.x=-this._ani.scale.x),h&&(this._ani.scale.y=-this._ani.scale.y),s<0&&(s=this._ani.length+s),void 0!==s&&(this._ani._frame=s),void 0!==r?this._ani.goToFrame(r):this._ani._frame==this._ani.lastFrame&&e(),this._ani._onComplete=this._ani._onChange=()=>{o&&(this._ani.scale.x=-this._ani.scale.x),h&&(this._ani.scale.y=-this._ani.scale.y),this._ani._onComplete=this._ani._onChange=null,e()}}))}changeAnimation(){return this.changeAni(...arguments)}_changeAni(e){this._ani?._onChange&&this._ani._onChange(),this._ani?.onChange&&this._ani.onChange();let i=this.animations[e];if(!i)for(let t=this.groups.length-1;t>=0;t--){if(i=this.groups[t].animations[e],i){i=i.clone();break}}if(!i)throw t.noLoop(),new C("Sprite.changeAnimation",[e]);this._ani=i,this._ani.name=e,this.resetAnimationsOnChange&&(this._ani._frame=0)}remove(){this.removed=!0}_remove(){this.body&&t.world.destroyBody(this.body),this.body=null;for(let t of this.groups)t.remove(this)}toString(){return"s"+this.idNum}_setContactCB(e,i,s,r){let o;o=0==s?d._collisions[r]:d._overlappers[r];let h=t.p5play[o],a=h[this._uid]??={};a[e._uid]!=i&&(a[e._uid]=i,a=h[e._uid],a&&a[this._uid]&&(delete a[this._uid],0==Object.keys(a).length&&delete h[e._uid]))}_validateCollideParams(t,e){if(!t)throw new C("Sprite.collide",2);if(!t._isSprite&&!t._isGroup)throw new C("Sprite.collide",0,[t]);if(e&&"function"!=typeof e)throw new C("Sprite.collide",1,[e])}_ensureCollide(t,e,i){if(!1!==this._hasOverlap[t._uid]&&(this._hasOverlap[t._uid]=!1),!1!==t._hasOverlap[this._uid]&&(t._hasOverlap[this._uid]=!1,t._isGroup))for(let e of t)e._hasOverlap[this._uid]=!1,this._hasOverlap[e._uid]=!1}collide(t,e){return this.collides(t,e)}collides(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,0),1==this._collisions[t._uid]||this._collisions[t._uid]<=-3}colliding(t,e){this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,1);let i=this._collisions[t._uid];return i<=-3?1:i>0?i:0}collided(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,2),this._collisions[t._uid]<=-1}_validateOverlapParams(t,e){if(!t)throw new C("Sprite.overlap",2);if(!t._isSprite&&!t._isGroup)throw new C("Sprite.overlap",0,[t]);if(e&&"function"!=typeof e)throw new C("Sprite.overlap",1,[e])}_ensureOverlap(t){if(this._hasSensors||this.addDefaultSensors(),!t._hasSensors)if(t._isSprite)t.addDefaultSensors();else{for(let e of t)e._hasSensors||e.addDefaultSensors();t._hasSensors=!0}if(this._hasOverlap[t._uid]||(this._removeContactsWith(t),this._hasOverlap[t._uid]=!0),!t._hasOverlap[this._uid]&&(t._removeContactsWith(this),t._hasOverlap[this._uid]=!0,t._isGroup))for(let e of t)e._hasOverlap[this._uid]=!0,this._hasOverlap[e._uid]=!0}overlap(t,e){return this.overlaps(t,e)}overlaps(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,0),1==this._overlappers[t._uid]||this._overlappers[t._uid]<=-3}overlapping(t,e){this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,1);let i=this._overlappers[t._uid];return i<=-3?1:i>0?i:0}overlapped(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,2),this._overlappers[t._uid]<=-1}_removeContactsWith(t){if(t._isGroup)for(let e of t)this._removeContactsWith(e);else this.__removeContactsWith(t)}__removeContactsWith(e){if(this.body)for(let i=this.body.getContactList();i;i=i.next){let s=i.contact;s.m_fixtureA.m_body.sprite._uid!=e._uid&&s.m_fixtureB.m_body.sprite._uid!=e._uid||t.world.destroyContact(s)}}_sortFixtures(){let t,e,i=null,s=null;for(let r=this.fixtureList;r;r=r.getNext())r.m_isSensor?(s?s.m_next=r:s=r,e=r):(i?i.m_next=r:i=r,t=r);s&&(e.m_next=null),i&&(t.m_next=s),this.body.m_fixtureList=i||s}addDefaultSensors(){let t;if(this.body&&this.fixtureList){for(let e=this.fixtureList;e;e=e.getNext())e.m_isSensor||(t=e.m_shape,this.body.createFixture({shape:t,isSensor:!0}));this._sortFixtures()}else this.addSensor();this._hasSensors=!0}distanceTo(e){return t.dist(this.x,this.y,e.x,e.y)}},t.Sprite.propTypes={x:"Float64",y:"Float64",vel:"Vec2",rotation:"number",rotationSpeed:"number",allowSleeping:"boolean",bearing:"number",bounciness:"number",collider:"Uint8",color:"color",debug:"boolean",density:"number",direction:"number",drag:"number",friction:"number",h:"number",isSuperFast:"boolean",layer:"number",life:"Int32",mass:"number",mirror:"Vec2_boolean",offset:"Vec2",pixelPerfect:"boolean",removed:"boolean",rotationDrag:"number",rotationLock:"boolean",scale:"Vec2",shape:"Uint8",sleeping:"boolean",stroke:"color",strokeWeight:"number",text:"string",textColor:"color",textSize:"number",textStroke:"color",textStrokeWeight:"number",tile:"string",tileSize:"number",tint:"color",visible:"boolean",w:"number",opacity:"number",gravityScale:"number"},t.Sprite.props=Object.keys(t.Sprite.propTypes),t.Sprite.propsAll=t.Sprite.props.concat(["autoDraw","autoUpdate","colour","d","diameter","dynamic","fill","height","heading","kinematic","resetAnimationsOnChange","speed","spriteSheet","static","textColour","textFill","width"]),t.Sprite.colliderTypes=["d","s","k","n"],t.Sprite.shapeTypes=["box","circle","chain","polygon"],t.Turtle=function(e){if(t.allSprites.tileSize>1)throw new Error("Turtle can't be used when allSprites.tileSize is greater than 1.");e??=25;let i=new t.Sprite(e,e,[[e,.4*e],[-e,.4*e],[0,.8*-e]]);i.color="green",i._isTurtleSprite=!0,i._prevPos={x:i.x,y:i.y};let s=i.move;return i.move=function(){return this._prevPos.x=this.x,this._prevPos.y=this.y,s.call(this,...arguments)},i},this.Ani=class extends Array{constructor(){super();let e,i=[...arguments];if(this.name="default","object"==typeof i[0]&&(i[0]._isSprite||i[0]._isGroup)&&(e=i[0],i=i.slice(1),this._addedToSpriteOrGroup=!0),e??=t.allSprites,"string"!=typeof i[0]||1!=i[0].length&&i[0].includes(".")||(this.name=i[0],i=i.slice(1)),this._frame=0,this._cycles=0,this.targetFrame=-1,this.offset={x:e.anis.offset.x??0,y:e.anis.offset.y??0},this._frameDelay=e.anis.frameDelay||4,this.demoMode=e.anis.demoMode??!1,this.playing=!0,this.visible=!0,this.looping=e.anis.looping??!0,this.endOnFirstFrame=e.anis.endOnFirstFrame??!1,this.frameChanged=!1,this.onComplete=this.onChange=null,this._onComplete=this._onChange=null,this.rotation=e.anis.rotation??0,this._scale=new u,0!=i.length&&"number"!=typeof i[0]){if(e.animations[this.name]=this,e._ani=this,Array.isArray(i[0])&&"string"==typeof i[0][0]&&(i=[...i[0]]),2!=i.length||"string"!=typeof i[0]||"string"!=typeof i[1]&&"number"!=typeof i[1])if("string"==typeof i.at(-1)||i.at(-1)instanceof p5.Image)for(let s=0;s=3)throw new C("Ani",1);o=i[0],r=i[1]}else r=i[0];let h=this;if(o instanceof p5.Image&&1!=o.width&&1!=o.height)this.spriteSheet=o,a();else{let n;n="string"==typeof o?o:o.url,t._incrementPreload(),this.spriteSheet=t.loadImage(n,(()=>{a(),t._decrementPreload()})),"string"==typeof o&&(e.spriteSheet=this.spriteSheet)}function a(){Array.isArray(r)&&(r="object"==typeof r[0]?{frames:r}:4==r.length?{pos:r.slice(0,2),size:r.slice(2)}:{pos:r});let{w:i,h:s,width:o,height:a,size:n,row:l,col:d,line:p,x:u,y:c,pos:_,frames:g,frameCount:f,frameDelay:m,frameSize:y,delay:w,rotation:v}=r;y??=n||e.anis.frameSize,w&&(h.frameDelay=w),m&&(h.frameDelay=m),v&&(h.rotation=v),g&&Array.isArray(g)?f=g.length:f??=g||1,i??=o||e.anis.w,s??=a||e.anis.h,u??=d||0,c??=p||l||0,_&&(u=_[0],c=_[1]),"number"==typeof y?i=s=y:y&&(i=y[0],s=y[1]);let x=e.tileSize;if(i&&s?(i*=x,s*=x):!e._dimensionsUndef&&e.w&&e.h?(i??=e.w*x,s??=e.h*x):1!=x?(i??=x,s??=x):f?(i??=h.spriteSheet.width/f,s??=h.spriteSheet.height):i=s=h.spriteSheet.width=h.spriteSheet.width&&(u=0,c+=s,c>=h.spriteSheet.height&&(c=0))}}}}else{let l,d,p=i[0];isNaN(i[1])?l=i[1]:d=Number(i[1]);let c=p.lastIndexOf("."),_=0,g=0;for(let w=c-1;w>=0&&!isNaN(p.charAt(w));w--)_++;if(l)for(let v=l.length-5;v>=0&&!isNaN(l.charAt(v));v--)g++;let f,m=p.slice(c),y=p.slice(0,c-_);if(l&&(f=l.slice(0,c-g)),l&&y!=f)this.push(t.loadImage(p)),this.push(t.loadImage(l));else{let x,b=parseInt(p.slice(c-_,c),10);if(d??=parseInt(l.slice(c-g,c),10),d=this.length)throw new C("Ani.frame",[t,this.length]);this._frame=t,this._cycles=0}get frameDelay(){return this._frameDelay}set frameDelay(t){t<=0&&(t=1),this._frameDelay=t}get scale(){return this._scale}set scale(t){"number"==typeof t&&(t={x:t,y:t}),this._scale._x=t.x,this._scale._y=t.y,this._scale._avg=t.x}clone(){this.length||console.error(`The animation named "${this.name}" must be loaded before it can be properly copied. Sprites need their own copy of a group's animation. Try loading the animation in the preload function and creating new group sprites in the setup function.`);let e=new t.Ani;e.spriteSheet=this.spriteSheet;for(let t=0;tthis._frame&&-1!==this.targetFrame?this._frame++:this.targetFrame=this.lastFrame?this._frame=0:this._frame++:this._frame{this._onComplete=()=>{this._onComplete=null,t()}}))}pause(t){this.playing=!1,t&&(this._frame=t)}stop(t){this.playing=!1,t&&(this._frame=t)}rewind(){return this.looping=!1,this.goToFrame(0)}loop(){this.looping=!0,this.playing=!0}noLoop(){this.looping=!1}nextFrame(){this._frame0?this._frame=this._frame-1:this.looping&&(this._frame=this.length-1),this.targetFrame=-1,this.playing=!1,this._cycles=0}goToFrame(t){if(!(t<0||t>=this.length))return this.targetFrame=t,this._cycles=0,this.targetFrame!==this._frame&&(this.playing=!0),new Promise((t=>{this._onComplete=()=>{this._onComplete=null,t()}}))}get lastFrame(){return this.length-1}get frameImage(){let e=this[this._frame];if(e instanceof p5.Image)return e;let{x:i,y:s,w:r,h:o}=e,h=t.createImage(r,o);return h.copy(this.spriteSheet,this.offset.x,this.offset.y,r,o,i,s,r,o),h}get w(){return this.width}get width(){let t=this[this._frame];return t instanceof p5.Image?t.width:t?t.w:1}get defaultWidth(){return this[this._frame].defaultWidth}get h(){return this.height}get height(){let t=this[this._frame];return t instanceof p5.Image?t.height:t?t.h:1}get defaultHeight(){return this[this._frame].defaultHeight}},t.Ani.props=["demoMode","endOnFirstFrame","frameDelay","frameSize","looping","offset","rotation","scale"],t.SpriteAnimation=t.Ani,this.Anis=class{#t={};constructor(){let e=this,i=[...t.Ani.props,"w","h"],s=["offset","scale"];for(let t of i)Object.defineProperty(this,t,{get:()=>e.#t[t],set(i){e.#t[t]=i;for(let s in e){let r=e[s];r instanceof Ani&&(r[t]=i)}}});for(let t of s){this.#t[t]={_x:0,_y:0};for(let i of["x","y"])Object.defineProperty(this.#t[t],i,{get:()=>e.#t[t]["_"+i],set(s){e.#t[t]["_"+i]=s;for(let r in e){let o=e[r];o instanceof Ani&&(o[t][i]=s)}}})}}get width(){return this.w}set width(t){this.w=t}get height(){return this.h}set height(t){this.h=t}},this.Group=class extends Array{constructor(...e){let i;if(e[0]instanceof t.Group&&(i=e[0],e=e.slice(1)),super(...e),"number"==typeof e[0])return;for(let e of this)if(!(e instanceof t.Sprite))throw new Error("A group can only contain sprites");if(this._isGroup=!0,this.x,this.y,this.vel,this.rotation,this.rotationSpeed,this.autoDraw,this.allowSleeping,this.autoUpdate,this.bounciness,this.collider,this.color,this.debug,this.density,this.direction,this.drag,this.friction,this.h,this.isSuperFast,this.layer,this.life,this.mass,this.mirror,this.offset,this.pixelPerfect,this.removed,this.rotationDrag,this.rotationLock,this.scale,this.shape,this.sleeping,this.stroke,this.strokeWeight,this.text,this.textColor,this.tile,this.tileSize,this.visible,this.w,this.bearing,this.d,this.dynamic,this.heading,this.kinematic,this.resetAnimationsOnChange,this.speed,this.static,this.idNum,t.p5play.groupsCreated<999)this.idNum=t.p5play.groupsCreated;else{for(let e=1;et&&(t=e._layer);return t}get ani(){return this._ani}set ani(t){this.addAni(t);for(let e of this)e.changeAni(t)}get animation(){return this._ani}set animation(t){this.ani=t}get anis(){return this.animations}get img(){return this._img}set img(t){this.image=t}get image(){return this._img}set image(e){"function"!=typeof e?("string"==typeof e&&(e=e.includes(".")?t.loadImage(e):new t.EmojiImage(e,this.w||this.width||this.d||this.diameter)),this._img=t.Sprite.prototype._extendImage(e)):this._img=e}get amount(){return this.length}set amount(t){let e=t-this.length,i=e>0;e=Math.abs(e);for(let t=0;t0?i:0}collided(t,e){return this._validateCollideParams(t,e),this._ensureCollide(t),e&&this._setContactCB(t,e,0,2),this._collisions[t._uid]<=-1}_validateOverlapParams(t,e){if(e&&"function"!=typeof e)throw new C("Group.overlap",1,[e]);if(!t)throw new C("Group.overlap",2);if(!t._isGroup&&!t._isSprite)throw new C("Group.overlap",0,[t])}_ensureOverlap(t){if(!this._hasSensors){for(let t of this)t._hasSensors||t.addDefaultSensors();this._hasSensors=!0}if(!t._hasSensors)if(t._isSprite)t.addDefaultSensors();else{for(let e of t)e._hasSensors||e.addDefaultSensors();t._hasSensors=!0}if(1!=this._hasOverlap[t._uid]){this._removeContactsWith(t),this._hasOverlap[t._uid]=!0;for(let e of this)if(e._hasOverlap[t._uid]=!0,t._hasOverlap[e._uid]=!0,this._uid==t._uid)for(let i of t)e._hasOverlap[i._uid]=!0,i._hasOverlap[e._uid]=!0}if(1!=t._hasOverlap[this._uid]&&(t._removeContactsWith(this),t._hasOverlap[this._uid]=!0,t._isGroup))for(let e of t){e._hasOverlap[this._uid]=!0,this._hasOverlap[e._uid]=!0;for(let t of this)e._hasOverlap[t._uid]=!0,t._hasOverlap[e._uid]=!0}}overlap(t,e){return this.overlaps(t,e)}overlaps(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,0),1==this._overlappers[t._uid]||this._overlappers[t._uid]<=-3}overlapping(t,e){this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,1);let i=this._overlappers[t._uid];return i<=-3?1:i>0?i:0}overlapped(t,e){return this._validateOverlapParams(t,e),this._ensureOverlap(t),e&&this._setContactCB(t,e,1,2),this._overlappers[t._uid]<=-1}_removeContactsWith(t){for(let e of this)e._removeContactsWith(t)}applyForce(){for(let t of this)t.applyForce(...arguments)}applyForceScaled(){for(let t of this)t.applyForceScaled(...arguments)}attractTo(){for(let t of this)t.attractTo(...arguments)}applyTorque(){for(let t of this)t.applyTorque(...arguments)}move(t,e,i){let s=[];for(let r of this)s.push(r.move(t,e,i));return Promise.all(s)}moveTo(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}let r=this._resetCentroid(),o=[];for(let t of this){let h={x:t.x-r.x+e,y:t.y-r.y+i};o.push(t.moveTo(h.x,h.y,s))}return Promise.all(o)}moveTowards(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}if(void 0!==e||void 0!==i){this._resetCentroid();for(let t of this){void 0===t.distCentroid&&this._resetDistancesFromCentroid();let r={x:t.distCentroid.x+e,y:t.distCentroid.y+i};t.moveTowards(r.x,r.y,s)}}}moveAway(e,i,s){if("number"!=typeof e){let r=e;if(r==t.mouse&&!t.mouse.isActive)return;s=i,i=r.y,e=r.x}if(void 0!==e||void 0!==i){this._resetCentroid();for(let t of this){void 0===t.distCentroid&&this._resetDistancesFromCentroid();let r={x:t.distCentroid.x+e,y:t.distCentroid.y+i};t.moveAway(r.x,r.y,s)}}}push(...e){this.removed&&(console.warn("Adding a sprite to a group that was removed. Use `group.removeAll()` to remove all of a group's sprites without removing the group itself. Restoring the group in p5play's memory."),t.p5play.groups[this._uid]=this,this.removed=!1);for(let i of e){if(!(i instanceof t.Sprite))throw new Error("You can only add sprites to a group, not "+typeof i);if(i.removed){console.error("Can't add a removed sprite to a group");continue}let e;for(let s in this._hasOverlap){let r=this._hasOverlap[s];r&&!i._hasSensors&&i.addDefaultSensors(),e=s>=1e3?t.p5play.sprites[s]:t.p5play.groups[s],e&&!e.removed&&(r?e._ensureOverlap(i):e._ensureCollide(i))}for(let e in d){let s=d[e];for(let e of s){let s=t.p5play[e],r=s[this._uid];if(!r)continue;let o=s[i._uid]??={};for(let t in r)o[t]=r[t]}}super.push(i),this.parent&&t.p5play.groups[this.parent].push(i),i.groups.push(this)}return this.length}repelFrom(){for(let t of this)t.repelFrom(...arguments)}size(){return this.length}toString(){return"g"+this.idNum}cull(e,i,s,r,o){if(void 0===s){o=i,e=i=s=r=e}if(isNaN(e)||isNaN(i)||isNaN(s)||isNaN(r))throw new TypeError("The culling boundary must be defined with numbers");if(o&&"function"!=typeof o)throw new TypeError("The callback to group.cull must be a function");let h=t.camera.x-t.canvas.hw/t.camera.zoom,a=t.camera.y-t.canvas.hh/t.camera.zoom,n=-s+h,l=-e+a,d=t.width+r+h,p=t.height+i+a,u=0;for(let t=0;td||e.y>p)&&(u++,o?o(e,u):e.remove(),e.removed&&t--))}return u}remove(t){if(void 0===t)return this.removeAll(),void(this._isAllSpritesGroup||(this.removed=!0));let e;if(e="number"==typeof t?t>=0?t:this.length+t:this.indexOf(t),-1==e)return;let i=this[e];return this.splice(e,1),i}splice(e,i){let s=super.splice(e,i);if(!s)return;let r=[];for(let t of s){if(t.removed)continue;let e=this._uid;do{r.push(e);let i=t.groups.findIndex((t=>t._uid==e)),s=t.groups.splice(i,1);e=s[0].parent}while(e)}for(let e of r){let i=t.p5play.groups[e];for(let e in d)for(let s in i[e]){if(0==i[e][s])continue;let r;r=s>=1e3?t.p5play.sprites[s]:t.p5play.groups[s];let o=!1;for(let t of i)if(t[e][r._uid]>0){o=!0;break}o||(i[e][r._uid]=-2,r[e][i._uid]=-2)}}return s}pop(){return this.remove(this.length-1)}shift(){return this.remove(0)}unshift(){return console.error("unshift is not supported for groups"),this.length}removeAll(){for(;this.length>0;)this.at(-1).remove()}_step(){this.__step()}draw(){let e=[...this];e.sort(((t,e)=>t._layer-e._layer));for(let i=0;i2)return console.error("world.timeScale must be between 0 and 2");this._timeScale!=t&&(this._timeScale=t,this._updateTimeStep())}_updateTimeStep(){this._timeStep=1/(t._targetFrameRate||60)*this._timeScale}get velocityThreshold(){return e.Settings.velocityThreshold}set velocityThreshold(t){e.Settings.velocityThreshold=t}step(e,i,s){for(let e of t.allSprites)e.prevPos.x=e.x,e.prevPos.y=e.y,e.prevRotation=e.rotation;super.step(e||this._timeStep,i||this.velocityIterations,s||this.positionIterations),this.physicsTime+=e||this._timeStep;let r=Object.values(t.p5play.sprites),o=Object.values(t.p5play.groups);for(let t of r)t._step();for(let t of o)t._step();for(let t of r)t.___step();for(let t of o)t.___step();t.canvas.dispatchEvent&&t.canvas.dispatchEvent(this.steppedEvent),this.autoStep&&(this.autoStep=null)}get realTime(){return t.millis()/1e3}getSpritesAt(i,s,r,o=!0){"object"==typeof i&&(s=i.y,i=i.x);const h=new e.Vec2(i/t.world.meterSize,s/t.world.meterSize),a=new e.AABB;a.lowerBound=new e.Vec2(h.x-.001,h.y-.001),a.upperBound=new e.Vec2(h.x+.001,h.y+.001);let n=[];if(this.queryAABB(a,(t=>(t.getShape().testPoint(t.getBody().getTransform(),h)&&n.push(t),!0))),0==n.length)return[];r??=t.allSprites;let l=[];for(let t of n){const e=t.m_body.sprite;e._cameraActiveWhenDrawn==o&&(l.find((t=>t._uid==e._uid))||l.push(e))}return l.sort(((t,e)=>-1*(t._layer-e._layer))),l}getSpriteAt(t,e,i){return this.getSpritesAt(t,e,i)[0]}getMouseSprites(){let e=this.getSpritesAt(t.mouse.x,t.mouse.y);if(t.camera._wasOff){let i=this.getSpritesAt(t.mouse.canvasPos.x,t.mouse.canvasPos.y,t.allSprites,!1);i.length&&(e=[...i,...e])}return e}_beginContact(t){let e=t.m_fixtureA,i=t.m_fixtureB,s="_collisions";e.m_isSensor&&(s="_overlappers"),e=e.m_body.sprite,i=i.m_body.sprite,e[s][i._uid]=0,i[s][e._uid]=0;for(let t of i.groups)(!e[s][t._uid]||e[s][t._uid]<0)&&(e[s][t._uid]=0,t[s][e._uid]=0);for(let t of e.groups){(!i[s][t._uid]||i[s][t._uid]<0)&&(i[s][t._uid]=0,t[s][i._uid]=0);for(let e of i.groups)(!t[s][e._uid]||t[s][e._uid]<0)&&(t[s][e._uid]=0,e[s][t._uid]=0)}}_endContact(t){let e=t.m_fixtureA,i=t.m_fixtureB,s="_collisions";e.m_isSensor&&(s="_overlappers"),e=e.m_body.sprite,i=i.m_body.sprite,e[s][i._uid]=0!=e[s][i._uid]?-2:-4,i[s][e._uid]=0!=i[s][e._uid]?-2:-4;for(let t of i.groups){let i=!1;for(let r of t)if(r[s][e._uid]>=0){i=!0;break}i||(t[s][e._uid]=0!=t[s][e._uid]?-2:-4,e[s][t._uid]=0!=e[s][t._uid]?-2:-4)}for(let t of e.groups){let e=!1;for(let r of t)if(r[s][i._uid]>=0){e=!0;break}if(!e){t[s][i._uid]=0!=t[s][i._uid]?-2:-4,i[s][t._uid]=0!=i[s][t._uid]?-2:-4;for(let e of i.groups)t[s][e._uid]=0!=t[s][e._uid]?-2:-4,e[s][t._uid]=0!=e[s][t._uid]?-2:-4}}}_findContact(t,e,i){let s=e[t][i._uid];if(s)return s;for(let r of i.groups)if(s=e[t][r._uid],s)return s;for(let r of e.groups){if(s=r[t][i._uid],s)return s;for(let e of i.groups)if(r._uid==e._uid&&(s=r[t][e._uid],s))return s}return!1}get allowSleeping(){return this.getAllowSleeping()}set allowSleeping(t){this.setAllowSleeping(t)}rayCast(t,e,i){return this.rayCastAll(t,e,i,(()=>!0))[0]}rayCastAll(e,i,r,o){let h,a=t.allSprites.tileSize,n=s(e.x,e.y,a);if("number"==typeof arguments[1])h=s(e.x+r*t.cos(i),e.y+r*t.sin(i),a);else{let t=arguments[1];o??=arguments[2],h=s(t.x,t.y,a)}let l=[],d=1;super.rayCast(n,h,(function(t,e,i,s){let r=t.getBody().sprite,h=o&&o(r);return l.push({sprite:r,fraction:s}),h?(st.fraction-e.fraction));let p=[];for(let t of l)t.fraction<=d&&p.push(t.sprite);return p}},this.Camera=class{constructor(){this._pos=t.createVector.call(t),this.__pos={x:0,y:0,rounded:{}},this.isActive=!1,this.bound={min:{x:0,y:0},max:{x:0,y:0}},this._zoomIdx=-1,this._zoom=1,this._destIdx=0}get pos(){return this._pos}set pos(t){this.x=t.x,this.y=t.y}get position(){return this._pos}set position(t){this.x=t.x,this.y=t.y}_calcBoundsX(e){let i=t.canvas.hw/this._zoom;this.bound.min.x=e-i,this.bound.max.x=e+i}_calcBoundsY(e){let i=t.canvas.hh/this._zoom;this.bound.min.y=e-i,this.bound.max.y=e+i}get x(){return this._pos.x}set x(e){if(void 0===e||isNaN(e))return;this._pos.x=e;let i=-e;"2d"==t.canvas.renderer&&(i+=t.canvas.hw/this._zoom),this.__pos.x=i,t.allSprites.pixelPerfect&&(this.__pos.rounded.x=Math.round(i)),this._calcBoundsX(e)}get y(){return this._pos.y}set y(e){if(void 0===e||isNaN(e))return;this._pos.y=e;let i=-e;"2d"==t.canvas.renderer&&(i+=t.canvas.hh/this._zoom),this.__pos.y=i,t.allSprites.pixelPerfect&&(this.__pos.rounded.y=Math.round(i)),this._calcBoundsY(e)}moveTo(e,i,s){if(void 0===e)return;if(isNaN(e)&&(s=i,i=e.y,e=e.x),s??=1,s<=0)return console.warn("camera.moveTo: speed should be a positive number"),Promise.resolve(!1);let r=i-this.y,o=e-this.x,h=Math.sqrt(r*r+o*o),a=s/h,n=o*a,l=r*a;this._destIdx++;let d=this._destIdx,p=Math.ceil(h/s);return(async()=>{for(let e=0;e{for(let e=0;e0&&(e=e<.1?t.map(e,0,.1,30,4):e<.5?t.map(e,.1,.5,4,2.5):e<.8?t.map(e,.5,.8,2.5,1):e<.9?t.map(e,.8,.9,1,.5):t.map(e,.9,1,.5,.2)),this._springiness=e,"wheel"!=this.type)return this._j.setFrequency(e);this._j.setSpringFrequencyHz(e)}get damping(){return"wheel"!=this.type?this._j.getDampingRatio():this._j.getSpringDampingRatio()}set damping(t){"wheel"==this.type?this._j.setSpringDampingRatio(t):this._j.setDampingRatio(t)}get speed(){return this._j.getJointSpeed()}set speed(t){this._j.isMotorEnabled()||this._j.enableMotor(!0),this._j.setMotorSpeed(t)}get motorSpeed(){return this._j.getMotorSpeed()}get enableMotor(){return this._j.isMotorEnabled()}set enableMotor(t){this._j.enableMotor(t)}get maxPower(){return this._j.getMaxMotorTorque()}set maxPower(t){!this._j.isMotorEnabled()&&t&&this._j.enableMotor(!0),this._j.setMaxMotorTorque(t),t||this._j.enableMotor(!1)}get power(){return this._j.getMotorTorque()}get collideConnected(){return this._j.getCollideConnected()}set collideConnected(t){this._j.m_collideConnected=t}get reactionForce(){return this._j.getReactionForce(t.world._timeStep)}get reactionTorque(){return this._j.getReactionTorque(t.world._timeStep)}remove(){this._removed||(this.spriteA.joints.splice(this.spriteA.joints.indexOf(this),1),this.spriteB.joints.splice(this.spriteB.joints.indexOf(this),1),t.world.destroyJoint(this._j),this._removed=!0)}},this.GlueJoint=class extends t.Joint{constructor(t,e){super(...arguments,"glue")}},this.DistanceJoint=class extends t.Joint{constructor(t,i){super(...arguments,"distance");let s=e.DistanceJoint({},t.body,i.body,t.body.getWorldCenter(),i.body.getWorldCenter());this._createJoint(s)}_display(){let t,e;(this.offsetA.x||this.offsetA.y)&&(t=this.spriteA.body.getWorldPoint(this._j.m_localAnchorA),t=r(t.x,t.y,this.spriteA.tileSize)),(this.offsetB.x||this.offsetB.y)&&(e=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB),e=r(e.x,e.y,this.spriteB.tileSize)),this._draw(t?t.x:this.spriteA.x,t?t.y:this.spriteA.y,e?e.x:this.spriteB.x,e?e.y:this.spriteB.y),this.visible=null}},this.WheelJoint=class extends t.Joint{constructor(s,r){super(...arguments,"wheel");let o=e.WheelJoint({maxMotorTorque:1e3,frequencyHz:4,dampingRatio:.7},s.body,r.body,r.body.getWorldCenter(),new e.Vec2(0,1));this._createJoint(o),this._angle=t._angleMode==i?90:1.5707963267948966}_display(){let e,i,s=this.spriteA.x,o=this.spriteA.y;if(this.offsetB.x||this.offsetB.y){let t=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB);t=r(t.x,t.y,this.spriteB.tileSize),e=t.x,i=t.y}else e=this.spriteB.x,i=this.spriteB.y;let h=t.tan(this.spriteA.rotation),a=t.tan(this._angle+this.spriteA.rotation),n=(i-o+h*s-a*e)/(h-a),l=h*(n-s)+o;this._draw(n,l,e,i),this.visible=null}get angle(){return this._angle}set angle(i){i!=this._angle&&(this._angle=i,this._j.m_localXAxisA=new e.Vec2(t.cos(i),t.sin(i)),this._j.m_localXAxisA.normalize(),this._j.m_localYAxisA=e.Vec2.crossNumVec2(1,this._j.m_localXAxisA))}},this.HingeJoint=class extends t.Joint{constructor(t,i){super(...arguments,"hinge");let s=e.RevoluteJoint({},t.body,i.body,t.body.getWorldCenter());this._createJoint(s)}_display(){const e=this.offsetA.x,i=this.offsetA.y,s=this.spriteA.rotation,r=e*t.cos(s)-i*t.sin(s),o=e*t.sin(s)+i*t.cos(s);this._draw(this.spriteA.x+r,this.spriteA.y+o),this.visible=null}get range(){return this.upperLimit-this.lowerLimit}set range(t){t/=2,this.upperLimit=t,this.lowerLimit=-t}get lowerLimit(){let e=this._j.getLowerLimit();return"radians"==t._angleMode?e:t.degrees(e)}set lowerLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),this.spriteA.body.setAwake(!0),this.spriteB.body.setAwake(!0),t._angleMode==i&&(e=t.radians(e)),this._j.m_lowerAngle=e}get upperLimit(){let e=this._j.getUpperLimit();return"radians"==t._angleMode?e:t.degrees(e)}set upperLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),this.spriteA.body.setAwake(!0),this.spriteB.body.setAwake(!0),t._angleMode==i&&(e=t.radians(e)),this._j.m_upperAngle=e}get angle(){let e=this._j.getJointAngle();return"radians"==t._angleMode?e:t.radians(e)}},t.RevoluteJoint=t.HingeJoint,this.SliderJoint=class extends t.Joint{constructor(t,i){super(...arguments,"slider");let s=e.PrismaticJoint({lowerTranslation:-1,upperTranslation:1,enableLimit:!0,maxMotorForce:50,motorSpeed:0,enableMotor:!0},t.body,i.body,t.body.getWorldCenter(),new e.Vec2(1,0));this._createJoint(s),this._angle=0}get angle(){return this._angle}set angle(i){i!=this._angle&&(this._angle=i,this._j.m_localXAxisA=new e.Vec2(t.cos(i),t.sin(i)),this._j.m_localXAxisA.normalize(),this._j.m_localYAxisA=e.Vec2.crossNumVec2(1,this._j.m_localXAxisA))}get range(){return this.upperLimit-this.lowerLimit}set range(t){t/=2,this.upperLimit=t,this.lowerLimit=-t}get lowerLimit(){return this._j.getLowerLimit()/this.spriteA.tileSize*t.world.meterSize}set lowerLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),e=e*this.spriteA.tileSize/t.world.meterSize,this._j.setLimits(e,this._j.getUpperLimit())}get upperLimit(){return this._j.getUpperLimit()/this.spriteA.tileSize*t.world.meterSize}set upperLimit(e){this._j.isLimitEnabled()||this._j.enableLimit(!0),e=e*this.spriteA.tileSize/t.world.meterSize,this._j.setLimits(this._j.getLowerLimit(),e)}},t.PrismaticJoint=t.SliderJoint,this.RopeJoint=class extends t.Joint{constructor(t,i){super(...arguments,"rope");let s=e.RopeJoint({maxLength:1},t.body,i.body,t.body.getWorldCenter());this._createJoint(s),this._j.m_localAnchorB.x=0,this._j.m_localAnchorB.y=0}get maxLength(){return e=this._j.getMaxLength(),i=this.spriteA.tileSize,e/i*t.world.meterSize;var e,i}set maxLength(e){var i,s;this._j.setMaxLength((i=e,s=this.spriteA.tileSize,i*s/t.world.meterSize))}},this.GrabberJoint=class extends this.Joint{constructor(t){super(t,t,"grab"),this._target={x:0,y:0},this.__target=new e.Vec2(0,0);let i=e.MouseJoint({maxForce:1e3,frequencyHz:3,dampingRatio:.9,target:t.body.getPosition()},t.body,t.body);this._createJoint(i)}_draw(){t.line(this.spriteA.x,this.spriteA.y,this._target.x,this._target.y)}get target(){return this._target}set target(e){this._target.x=e.x,this._target.y=e.y,this.__target.x=e.x/t.world.meterSize,this.__target.y=e.y/t.world.meterSize,this._j.setTarget(this.__target)}get maxForce(){return this._j.getMaxForce()}set maxForce(t){this._j.setMaxForce(t)}};class u{constructor(){let t=this;Object.defineProperties(this,{x:{get:()=>t._x,set(e){e!=t._x&&(t._x=e,t._avg=.5*(t._x+t._y))},configurable:!0,enumerable:!0},y:{get:()=>t._y,set(e){e!=t._y&&(t._y=e,t._avg=.5*(t._x+t._y))},configurable:!0,enumerable:!0},_x:{value:1,enumerable:!1,writable:!0},_y:{value:1,enumerable:!1,writable:!0},_avg:{value:1,enumerable:!1,writable:!0}})}valueOf(){return this._avg}}function c(t){return!/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test(t.toString())}function _(t,e){let i=t,s=e.toLowerCase();if("triangle"==s?i=[i,-120,3]:"square"==s?i=[i,-90,4]:"pentagon"==s?i=[i,-72,5]:"hexagon"==s?i=[i,-60,6]:"septagon"==s?i=[i,-51.4285714286,7]:"octagon"==s?i=[i,-45,8]:"enneagon"==s?i=[i,-40,9]:"decagon"==s?i=[i,-36,10]:"hendecagon"==s?i=[i,-32.7272727273,11]:"dodecagon"==s&&(i=[i,-30,12]),i==t)throw new Error("Invalid, not a regular polygon: "+e);return i}if(t.p5play.palettes=[{a:"aqua",b:"black",c:"crimson",d:"darkviolet",e:"peachpuff",f:"olive",g:"green",h:"hotpink",i:"indigo",j:"navy",k:"khaki",l:"lime",m:"magenta",n:"brown",o:"orange",p:"pink",q:"turquoise",r:"red",s:"skyblue",t:"tan",u:"blue",v:"violet",w:"white",x:"gold",y:"yellow",z:"gray"}],this.colorPal=(e,i)=>{if(e instanceof p5.Color)return e;"number"==typeof i&&(i=t.p5play.palettes[i]),i??=t.p5play.palettes[0];let s=i[e];return s?t.color(s):t.color(0,0,0,0)},this.EmojiImage=function(e,i){t.push(),t.textSize(i);let s=t.createGraphics(i,1.25*i);s.textSize(i),s.textAlign(t.CENTER),s.text(e,i/2,i);let r=s.drawingContext,o=s._pixelDensity||1,h=s.canvas.width,a=s.canvas.height,n=r.getImageData(0,0,h,a).data,l=h,d=0,p=a,u=0,c=3;for(let t=0;td&&(d=e),tu&&(u=t)),c+=4;return p=Math.floor(p/o),u=Math.floor(u/o),l=Math.floor(l/o),d=Math.floor(d/o),s=s.get(l,p,d-l+1,u-p+1),t.pop(),s.url=e,s},this.spriteArt=(e,i,s)=>{i??=1,"number"==typeof s&&(s=t.p5play.palettes[s]),s??=t.p5play.palettes[0];let r=e;"string"==typeof e&&(r=(e=(e=(e=e.trim()).replace(/\r*\n\t+/g,"\n")).replace(/\s+$/g,"")).split("\n"));let o=0;for(let t of r)t.length>o&&(o=t.length);let h=r.length,a=t.createImage(o*i,h*i);a.loadPixels();for(let t=0;tnew Promise(t?e=>{setTimeout(e,t)}:requestAnimationFrame),this.sleep=e=>e?t.delay(e):new Promise((e=>{if(t.canvas.dispatchEvent){t.canvas.addEventListener("p5play_worldStepped",(function i(){t.canvas.removeEventListener("p5play_worldStepped",i),e()}))}else setTimeout(e,1e3*t.world._timeStep)})),this.play=t=>{if(!t?.play)throw new Error("Tried to play your sound but it wasn't a sound object.");return new Promise((e=>{t.play(),t.onended((()=>e()))}))},window.location){let e=location.hostname;switch(e){case"":case"127.0.0.1":case"localhost":case"p5play.org":case"editor.p5js.org":case"codepen.io":case"codera.app":case"aug4th.com":case"cdpn.io":case"glitch.com":case"replit.com":case"stackblitz.com":case"jsfiddle.net":case"aijs.io":case"preview-aijs.web.app":case"quinton-ashley.github.io":break;default:if(/^[\d\.]+$/.test(e)||e.endsWith("stackblitz.io")||e.endsWith("glitch.me")||e.endsWith("replit.dev")||e.endsWith("codehs.com")||e.endsWith("openprocessing.org")||location.origin.endsWith("preview.p5js.org"))break;!async function(){if(document.getElementById("p5play-intro"))return;t._incrementPreload();let e=document.createElement("div");e.id="p5play-intro",e.style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; background-color: black;";let i=document.createElement("img");i.style="position: absolute; top: 50%; left: 50%; width: 80vmin; height: 40vmin; margin-left: -40vmin; margin-top: -20vmin; z-index: 1001; opacity: 1; scale: 1; transition: scale 1.5s, opacity 0.4s ease-in-out;",i.onerror=()=>{i.style.imageRendering="pixelated",i.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABACAYAAADS1n9/AAABbGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAACiRfZC/S0JhGIWfm4VgNkQNDg13igYr0SCXBjWQIkisQG26Xn+C2sfVCKMtWkPoP8igOWgoIgxaGhqCqCGitqamgpaSL+69hS51lvfhcDgcXujxaEKUeoFypWbEo2E1kUypzhcUFCxpelWEYrEFk39vlxT4uLezt+Nm12u7uRvciV6Wj88XNx88k/wvVyZb1YEvwKcLowaKF4ht1ITJW8CwkUimQGmYnLf5wOS0zSdWZjkeAeUaUPWClgHlFfCmu/x8F5dL6/rPMnO9O1tZWTJ7gBFmKVJFUEKjjkqMwB/5KSsfYQ1BHYMieQrUUAkhrIYsKnNU0JnAi4ofH3785p/tuo+7n/95O972M8y0pJRnHW++BUfT4DrteGNBGOyHq1OhGZplOYCeXA7eDmEgCUM34Fqt5gJ+e707DH1PUr6PgnMP2g0pP/elbDfB8QgXlW8Y/mq9pjC8gwAABSxJREFUeJztnb9y2zAMxulcpnbNntfJ3D5n97xO966Z3aNP9NHgBxAgQVmO8bvLNZZIiCI+gH8kpyl4bk7P3gErOJ/PZ0+zp9NpmZ9CAM54O7+wSgQhAEdWOb+wQgSvzZHAj5+/50x9/WkOeRMZwIkm+medXyAi8M4CL82R4KkIATjQRL8nJJN4XysEsAKv9L8DIYAnJyaBk8CUTDLA51/bbP7jHWSQRZPByADeTDp/tM4ozT4AVHSwO1kEMBMY/dTLFNcMcN5oSgTHYHBi2fPrS4qo98Mh/a+C8/ErdyJYw8cbb/bzH/ncGQY8aOYAnpThZ4XGerZdrn209fxIe6rVQw52Oif4NquAfF+d+Y6NSeej9C9F/714WAHkyP5uoxcSCBKSic5WMhwCciTlcnUaRSmVRlw5x0UiVx6VqW1Ru1zbaHl6TXS9Efae3GmuNzpXYDMA7VT6OxKE9nhPKNy1ZlHbEdL/qPNRdHsy2i5WAIk41yt6emM1Jw5OcL12eg4VR1rWmRCGAVEAGjhncseLQ7SOebZV6t4TxWEBcFHHOayO7PoHUcpy/y5FSP+jWJ06KoKRDAUngZxDUXrVlOsdR0jX8vjsxaqI1dilG0ciWdjgHcN4GqgERdcR1/VayjwgBFDzQG/yJEaASKgSIYBnAgg8BKAARRWKvkcjDwMhgAKIjkcACREJlgOuAu5K7Qgwaz0KeQaOOn9vTCsBwLwApMiZdOBROpnj3u2bdX5aPQfwaOBuDIr1HveYryldl30wBO4RZ4AS1aXCbFr2skezTa5b2+7Z7Z2nNjZKh3Jja3HGHtlAcnwyOj+/HIIFUACd0TizbhzTQU1ddAzYg+WYY5d0TM5dXql6A2VzO7n0jUS6kTtXuseVQ4Im01icXxgfApgOuvy8pevPjD3VuRrhRpu29trG2GI7eWPFkKCJerZdzH2UV8NUAsiqR8pnG5YdJjjNZA+8aYvqIq6dQqNfC9N5YofvDNuO3HbQ/tNG+dwVQOmwS8QAg/kY26lABF17Aqq65DgSlSkzMR2ZpM53hmsve32mvehLIvIcoFyIaUB9vhZB3bBmbJ6cLJkfrb4PRj+FmSAeCsbxiXF+0mSAG5WhDtjSfT32S3TtUb6wsMS6Qkd4TtKQoI62b0FTPkW3EQQ6G908KgcB5aA9BKir4WFf59q4ZNneF0eYZ/4SUxtB4lg88rVoLnqEa7CAOqz9J0Y9Caw/N44FnX0zYQPHRXsI4RqQ0Zk/B1iNUB5RYKohgN4svNG8GiApCpbr2QN2uHN08nmBGSK4ttyLkd1D1TBgxGUV4F1OOk/PSWUTENsRqJ3ovo1M5gHo+4A13/YPRd4sS2c7V/m1795WMJvZlNvIUv1RTtzXw2mqncXbnsSSqCJwIuCua3GetX4zBBj+ntDlBCeCYGNg2Vo7UXIeR6nv9fSPE0EIoAdwfs095xis85NeAC/SyWDSCQLXJ6cT9T2Ajo+MQOhkgWTMBMh55iecPSxDQHBLEwCG7WfJkd13CYS6mvpXrJPAoKURQdILATnSkrKbjTJLugc7piGAQWZEkDS7dMIj5utWulQf2SNIzk8hgD6zIoBQRy36n0U0k/sQgAIogjT/Z9saHO1pV3YhACUuImCcNWRPsGVZ1ocAjEAh9JwmOAsyaG9kPycEMAAUQWIcp3CWt71gB84SP34JJ7Gzm0I1A/a0hGomsTigF6VWZ3pEfQjAAY3jLM7yticRAnAEOW7GUd72ECEAZ2qneTjL294NKaX/gKttC9Kft4MAAAAASUVORK5CYII="};let s=window._p5play_intro_image;""==s||s?.includes("made_with_p5play")?((s.includes("bit.")||s.includes("pixel"))&&(i.style.imageRendering="pixelated"),i.src=s):i.src="https://p5play.org/assets/made_with_p5play.webp",await new Promise((t=>i.onload=t)),e.append(i),document.body.append(e),await t.delay(),i.offsetHeight,i.style.scale=1.2,await t.delay(1100),i.style.opacity=0,await t.delay(400),e.style.display="none",e.remove(),document.getElementById("p5play-intro")?.remove(),t._decrementPreload()}()}}let g=p5.disableFriendlyErrors;p5.disableFriendlyErrors=!0;const f=t.createCanvas;this.createCanvas=function(){let e,i,s,r=[...arguments];if("string"==typeof r[0])if(r[0].includes(":")){let t=r[0].split(":"),i=Number(t[0]),s=Number(t[1]),o=window.innerWidth,h=window.innerWidth*(s/i);h>window.innerHeight&&(o=window.innerHeight*(i/s),h=window.innerHeight),r[0]=Math.round(o),r.splice(1,0,Math.round(h)),e="fullscreen"}else r=[0,0,...r];if(r[0]||(r[0]=window.innerWidth,r[1]=window.innerHeight,e="fullscreen"),"string"==typeof r[2]){let t=r[2].toLowerCase().split(" ");"pixelated"==t[0]?(i="pixelated",t[1]?(e="centered",s=Number(t[1].slice(1))):e="fullscreen",r.splice(2,1)):"fullscreen"==t[0]&&(e="fullscreen",r.splice(2,1))}let o=f.call(t,...r);t.ctx=t.drawingContext;let h=o.canvas||o;return o.GL&&(h.renderer="webgl"),"webgpu"!=h.renderer&&(h.renderer="2d"),h.tabIndex=0,h.w=r[0],h.h=r[1],h.addEventListener&&(h.addEventListener("keydown",(function(t){" "!=t.key&&"/"!=t.key&&"ArrowUp"!=t.key&&"ArrowDown"!=t.key&&"ArrowLeft"!=t.key&&"ArrowRight"!=t.key||t.preventDefault()})),h.addEventListener("mouseover",(()=>{this.mouse.isOnCanvas=!0,this.mouse.isActive=!0})),h.addEventListener("mouseleave",(()=>{this.mouse.isOnCanvas=!1})),h.addEventListener("touchstart",(t=>t.preventDefault())),h.addEventListener("contextmenu",(t=>t.preventDefault()))),h.save??=t.saveCanvas.bind(t),h.resize??=t.resizeCanvas.bind(t),h.hw=.5*h.w,h.hh=.5*h.h,h.mouse={x:t.mouseX,y:t.mouseY},"2d"!=h.renderer||t._webgpuFallback?(t.camera.x=0,t.camera.y=0,"webgl"==h.renderer&&(t._textCache=!1),t._webgpuFallback||(t.p5play._renderStats={x:10-h.hw,y:20-h.hh})):(t.camera.x=t.camera.ogX=h.hw,t.camera.y=t.camera.ogY=h.hh),g||(p5.disableFriendlyErrors=!1),t.displayMode(e,i,s),o},this.Canvas=class{constructor(t,e,i,s){this.w,this.width,this.h,this.height,this.hw,this.hh,this.mouse}resize(){}save(){}},this.canvas=t.canvas,t.Canvas=function(){return t.createCanvas(...arguments).canvas};const m=t.resizeCanvas;this.resizeCanvas=(e,i)=>{e??=window.innerWidth,i??=window.innerHeight,m.call(t,e,i);let s=t.canvas;s.w=s.width/t.pixelDensity(),s.h=s.height/t.pixelDensity(),s.hw=.5*s.w,s.hh=.5*s.h,s.fullscreen&&(s.w/s.h>window.innerWidth/window.innerHeight?(s.style.width="100%!important",s.style.height="auto!important"):(s.style.width="auto!important",s.style.height="100%!important")),"2d"==s.renderer?(t.camera.x=s.hw,t.camera.y=s.hh):(t.camera.x=0,t.camera.y=0)};const y=t.frameRate;this.frameRate=function(e){let i=y.call(t,e);return e&&t.world._updateTimeStep(),i};const w=t.background;this.background=function(){let e=arguments;1==e.length&&1==e[0]?.length?w.call(t,t.colorPal(e[0])):w.call(t,...e)};const v=t.fill;this.fill=function(){let e=arguments;1==e.length&&1==e[0]?.length?v.call(t,t.colorPal(e[0])):v.call(t,...e)};const x=t.stroke;this.stroke=function(){let e=arguments;1==e.length&&1==e[0]?.length?x.call(t,t.colorPal(e[0])):x.call(t,...e)};const b=t.loadImage;this.loadImage=this.loadImg=function(){if(t.p5play.disableImages)return t._decrementPreload(),{w:16,width:16,h:16,height:16,pixels:[]};let e,i=arguments,s=i[0],r=t.p5play.images[s];if("function"==typeof i[i.length-1]&&(e=i[i.length-1]),r)return r.width<=1&&r.height<=1||!r.pixels.length?e?(r.cbs.push(e),r.calls++):t._decrementPreload():(e&&e(),t._decrementPreload()),r;return r=b.call(t,s,(e=>{if(e.w||(Object.defineProperty(e,"w",{get:function(){return this.width}}),Object.defineProperty(e,"h",{get:function(){return this.height}})),e.cbs){for(let t of e.cbs)t(e);for(let i=1;i\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\nbody.hasFrameBorder {\n\tdisplay: block;\n}\n.p5Canvas {\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.p5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.p5-centered,\n.p5-maxed,\n.p5-fullscreen {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.p5-centered,\nmain.p5-maxed,\n.p5-fullscreen {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n"),t._adjustDisplay=()=>{let e=t.canvas,i=e.style,s=e.parentElement;i&&s&&e.displayMode&&("pixelated"==e.renderQuality&&(e.classList.add("p5-pixelated"),t.pixelDensity(1),t.noSmooth&&t.noSmooth(),t.textFont&&t.textFont("monospace")),"normal"==e.displayMode?(s.classList.remove("p5-centered","p5-maxed","p5-fullscreen"),i.width=e.w*e.displayScale+"px",i.height=e.h*e.displayScale+"px"):(s.classList.add("p5-"+e.displayMode),s=s.getBoundingClientRect(),e.w/e.h>s.width/s.height?("centered"==e.displayMode?(i.width=e.w*e.displayScale+"px",i.maxWidth="100%"):i.width="100%",i.height="auto",i.maxHeight=""):(i.width="auto",i.maxWidth="","centered"==e.displayMode?(i.height=e.h*e.displayScale+"px",i.maxHeight="100%"):i.height="100%")))},t.displayMode=(e="normal",i="default",s=1)=>{let r=t.canvas;"string"==typeof s&&(s=parseFloat(s.slice(1))),Object.assign(r,{displayMode:e,renderQuality:i,displayScale:s}),t._adjustDisplay()});let A={generic:["Ah! I found an error","Oh no! Something went wrong","Oof! Something went wrong","Houston, we have a problem","Whoops, having trouble here"],Sprite:{constructor:{base:"Sorry I'm unable to make a new Sprite",0:"What is $0 for? If you're trying to specify the x position of the sprite, please specify the y position as well.",1:"If you're trying to specify points for a chain Sprite, please use an array of position arrays.\n$0",2:"Invalid input parameters: $0"},hw:{0:"I can't change the halfWidth of a Sprite directly, change the sprite's width instead."},hh:{1:"I can't change the halfHeight of a Sprite directly, change the sprite's height instead."},rotate:{0:"Can't use this function on a sprite with a static collider, try changing the sprite's collider type to kinematic.",1:'Can\'t use "$0" for the angle of rotation, it must be a number.'},rotateTo:{},rotateMinTo:{},rotateTowards:{},changeAnimation:'I can\'t find any animation named "$0".',collide:{0:"I can't make that sprite collide with $0. Sprites can only collide with another sprite or a group.",1:"The collision callback has to be a function.",2:"You're trying to check for an collision with a sprite or group that doesn't exist!"},overlap:{0:"I can't make that sprite overlap with $0. Sprites can only overlap with another sprite or a group.",1:"The overlap callback has to be a function.",2:"You're trying to check for an overlap with a sprite or group that doesn't exist!"}},Ani:{constructor:{base:"Hey so, I tried to make a new Ani but couldn't",1:"The name of the animation must be the first input parameter."},frame:"Index $0 out of bounds. That means there is no frame $0 in this animation. It only has $1 frames!"},Group:{constructor:{base:"Hmm awkward! Well it seems I can't make that new Group you wanted"}}};A.Group.collide=A.Sprite.collide,A.Group.overlap=A.Sprite.overlap,A.Sprite.rotateTo[0]=A.Sprite.rotateMinTo[0]=A.Sprite.rotateTowards[0]=A.Sprite.rotate[0];class C extends Error{constructor(t,e,i){super(),"string"!=typeof t&&(i=e,e=t,t=(t=this.stack.match(/\n\s*at ([^\(]*)/)[1]).slice(0,-1)),"number"!=typeof e&&(i=e,e=void 0),"new"==t.slice(0,3)&&(t=t.slice(4));let s=(t=t.split("."))[0];t=t[1]||"constructor";let r=this.stack.match(/\/([^p\/][^5][^\/:]*:[^\/:]+):/);r&&(r=r[1].split(":"),r=" in "+r[0]+" at line "+r[1]),r=" using "+s+"."+t+". ",i=i||[];let o,h=A[s][t];o=h.base?h.base+r:A.generic[Math.floor(Math.random()*A.generic.length)]+r,void 0!==e&&(h=h[e]),h&&(h=h.replace(/\$([0-9]+)/g,((t,e)=>i[e])),o+=h),p5._friendlyError(o,t)}}this.allSprites=new t.Group,this.world=new t.World,this.camera=new t.Camera,this.InputDevice=class{constructor(){this.holdThreshold=12,this._default=0}_ac(t){return t}presses(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),1==this[t]||-3==this[t]}pressing(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),-3==this[t]?1:this[t]>0?this[t]:0}pressed(t){return this.released(t)}holds(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]==this.holdThreshold}holding(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]>=this.holdThreshold?this[t]:0}held(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),-2==this[t]}released(t){return t??=this._default,void 0===this[t]&&(t=this._ac(t)),this[t]<=-1}releases(t){return this.released(t)}},this._Mouse=class extends t.InputDevice{constructor(){super(),this._default="left";let e=this;this._pos=t.createVector.call(t),Object.defineProperty(this._pos,"x",{get:()=>e.x,set(t){e.x=t}}),Object.defineProperty(this._pos,"y",{get:()=>e.y,set(t){e.y=t}}),this.x=0,this.y=0,this.canvasPos={},this.left=0,this.center=0,this.right=0,this.drag={left:0,center:0,right:0},this._dragFrame={left:!1,center:!1,right:!1},this.isOnCanvas=!1,this.isActive=!1,this._visible=!0,this._cursor="default",this._ogX=0,this._ogY=0}_ac(t){return"left"==(t=t.toLowerCase()).slice(0,4)?t="left":"right"==t.slice(0,5)?t="right":"middle"==t.slice(0,6)&&(t="center"),t}_update(){t.mouse.canvasPos.x=t.mouseX,t.mouse.canvasPos.y=t.mouseY,t.camera.x==t.camera.ogX&&t.camera.y==t.camera.ogY&&1==t.camera.zoom?(this.x=t.mouseX,this.y=t.mouseY):"webgpu"!=t.canvas.renderer?(this.x=(t.mouseX-t.canvas.hw)/t.camera.zoom+t.camera.x,this.y=(t.mouseY-t.canvas.hh)/t.camera.zoom+t.camera.y):(this.x=t.mouseX/t.camera.zoom+t.camera.x,this.y=t.mouseY/t.camera.zoom+t.camera.y)}get pos(){return this._pos}get position(){return this._pos}get cursor(){return t.canvas.style.cursor}set cursor(e){e!=this._cursor&&(t.cursor(e),this._cursor=e)}get visible(){return this._visible}set visible(e){this._visible=e,t.canvas.style.cursor=e?"default":"none"}drags(t){return t??=this._default,1==this.drag[t]}dragging(t){return t??=this._default,this.drag[t]>0?this.drag[t]:0}dragged(t){return t??=this._default,this.drag[t]<=-1}},this.mouse=new t._Mouse,this._SpriteMouse=class extends t._Mouse{constructor(){super(),delete this.canvasPos,this.hover=0}hovers(){return 1==this.hover}hovering(){return this.hover>0?this.hover:0}hovered(){return this.hover<=-1}};const k=function(e){if(t.mouse.isActive=!0,t.mouse[e]++,t.world.mouseSprites.length){let i=t.world.mouseSprite?.mouse;i&&(i[e]=0,i.hover=0,i.drag[e]=0),ms=t.world.mouseSprites[0],t.world.mouseSprite=ms,i=ms.mouse,i[e]=1,i.hover<=0&&(i.hover=1)}},M=t._onmousedown;t._onmousedown=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),k.call(t,i),M.call(t,e)};const z=function(e){let i=t.mouse;i[e]>0&&(i._dragFrame[e]=!0)},T=t._onmousemove;t._onmousemove=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),z.call(t,i),T.call(t,e)};const j=function(e){let i=t.mouse;i[e]>=i.holdThreshold?i[e]=-2:i[e]>1?i[e]=-1:i[e]=-3,i.drag[e]>0&&(i.drag[e]=-1);let s=t.world.mouseSprite?.mouse;s&&(s.hover>1?(s[e]>=t.mouse.holdThreshold?s[e]=-2:s[e]>1?s[e]=-1:s[e]=-3,s.drag[e]>0&&(s.drag[e]=-1)):(s[e]=0,s.drag[e]=0))},O=t._onmouseup;if(t._onmouseup=function(e){if(!t._setupDone)return;let i="left";1===e.button?i="center":2===e.button&&(i="right"),j.call(t,i),O.call(t,e)},this._Touch=class extends t.InputDevice{constructor(e){super(),this.x,this.y,this.id=e.identifier,this._default="duration",this.holdThreshold=t.touches.holdThreshold,this.duration=1,this.drag=0,this._dragFrame=!1,this.canvasPos={},this._update(e)}_update(e){let i=t.canvas;const s=i.getBoundingClientRect(),r=i.scrollWidth/i.w||1,o=i.scrollHeight/i.h||1,h=this.canvasPos.x=(e.clientX-s.left)/r,a=this.canvasPos.y=(e.clientY-s.top)/o;t.camera.x==i.hw&&t.camera.y==i.hh&&1==t.camera.zoom?(this.x=h,this.y=a):(this.x=(h-i.hw)/t.camera.zoom+t.camera.x,this.y=(a-i.hh)/t.camera.zoom+t.camera.y),this.force=e.force}},this.touches=[],t.touches.holdThreshold=12,t._ontouchstart=function(e){if(t._setupDone){t.getAudioContext&&"suspended"==t.getAudioContext()?.state&&t.userStartAudio();for(let i of e.changedTouches)t.touches.push(new t._Touch(i)),1==t.touches.length&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t.world.mouseSprites=t.world.getMouseSprites(),t._onmousedown(e));t.touchStarted&&!t.touchStarted(e)&&e.preventDefault()}},t._ontouchmove=function(e){if(t._setupDone){for(let i of e.changedTouches){let s=t.touches.find((t=>t.id==i.identifier));s._update(i),s._dragFrame=!0,s.id==t.touches[0].id&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t._onmousemove(e))}t.touchMoved&&!t.touchMoved(e)&&e.preventDefault()}},t._ontouchend=function(e){if(t._setupDone){for(let i of e.changedTouches){let s=t.touches.find((t=>t.id==i.identifier));s._update(i),s.duration>=s.holdThreshold?s.duration=-2:s.duration>1?s.duration=-1:s.duration=-3,s.drag>0&&(s.drag=-1),s.id==t.touches[0].id&&(t.mouseX=t.touches[0].x,t.mouseY=t.touches[0].y,t.mouse._update(),t._onmouseup(e))}t.touchEnded&&!t.touchEnded(e)&&e.preventDefault()}},this._Keyboard=class extends t.InputDevice{constructor(){super(),this._default=" ",this.alt=0,this.arrowUp=0,this.arrowDown=0,this.arrowLeft=0,this.arrowRight=0,this.backspace=0,this.capsLock=0,this.control=0,this.enter=0,this.meta=0,this.shift=0,this.tab=0;let t=this._simpleKeyControls={arrowUp:"up",arrowDown:"down",arrowLeft:"left",arrowRight:"right"};t.w=t.W="up",t.s=t.S="down",t.a=t.A="left",t.d=t.D="right",t.i=t.I="up2",t.k=t.K="down2",t.j=t.J="left2",t.l=t.L="right2"}get visible(){return this._inp==document.activeElement}set visible(t){this._inp||(this._inp=Object.assign(document.createElement("input"),{type:"text",style:"position: fixed; height: 0; padding: 0; border: none; opacity: 0.0001; pointer-events: none;"}),document.body.appendChild(this._inp)),this._visible=t,t?this._inp.focus():this._inp.blur()}_ac(t){if(1!=t.length){if(!isNaN(t)){if(38==t)return"arrowUp";if(40==t)return"arrowDown";if(37==t)return"arrowLeft";if(39==t)return"arrowRight";if(t>=10)throw new Error("Use key names with the keyboard input functions, not keyCode numbers!");return t}t=t.replaceAll(/[ _-]/g,"")}if(1!=(t=t.toLowerCase()).length){if("arrowup"==t)return"arrowUp";if("arrowdown"==t)return"arrowDown";if("arrowleft"==t)return"arrowLeft";if("arrowright"==t)return"arrowRight";if("capslock"==t)return"capsLock"}return t}_pre(t){(!this[t]||this[t]<0)&&(this[t]=1)}_rel(t){this[t]>=this.holdThreshold?this[t]=-2:this[t]>1?this[t]=-1:this[t]=-3}get cmd(){return this.meta}get command(){return this.meta}get ctrl(){return this.control}get space(){return this[" "]}get spacebar(){return this[" "]}get opt(){return this.alt}get option(){return this.alt}get win(){return this.meta}get windows(){return this.meta}},this.kb=new t._Keyboard,this.keyboard=t.kb,"object"==typeof navigator&&navigator.keyboard){const e=navigator.keyboard;window==window.top?e.getLayoutMap().then((e=>{"w"!=e.get("KeyW")&&(t.p5play.standardizeKeyboard=!0)})):t.p5play.standardizeKeyboard=!0}else t.p5play.standardizeKeyboard=!0;function P(t){let e=t.code;return 4==e.length&&"Key"==e.slice(0,3)?e[3].toLowerCase():t.key}const F=t._onkeydown;t._onkeydown=function(t){let e=t.key;if(this.p5play.standardizeKeyboard&&(e=P(t)),e.length>1)e=e[0].toLowerCase()+e.slice(1);else{let t=e.toLowerCase(),i=e.toUpperCase();t!=i&&(e!=i?this.kb._pre(i):this.kb._pre(t))}this.kb._pre(e);let i=this.kb._simpleKeyControls[e];i&&this.kb._pre(i),F.call(this,t)};const I=t._onkeyup;t._onkeyup=function(t){let e=t.key;if(this.p5play.standardizeKeyboard&&(e=P(t)),e.length>1)e=e[0].toLowerCase()+e.slice(1);else{let t=e.toLowerCase(),i=e.toUpperCase();t!=i&&(e!=i?this.kb._rel(i):this.kb._rel(t))}this.kb._rel(e);let i=this.kb._simpleKeyControls[e];if(i&&this.kb._rel(i),t.shiftKey){let t=e.toLowerCase();this.kb[t]>0&&this.kb._rel(t)}I.call(this,t)},this.Contro=class extends t.InputDevice{constructor(t){super(),this._default="a",this.connected=!0,this.a=0,this.b=0,this.x=0,this.y=0,this.l=0,this.r=0,this.lt=0,this.rt=0,this.select=0,this.start=0,this.lsb=0,this.rsb=0,this.up=0,this.down=0,this.left=0,this.right=0,this.leftStick={x:0,y:0},this.rightStick={x:0,y:0},this.leftTrigger=0,this.rightTrigger=0,this.buttonMapping={a:0,b:1,x:2,y:3,l:4,r:5,lt:6,rt:7,select:8,start:9,lsb:10,rsb:11,up:12,down:13,left:14,right:15},this.axeMapping={leftStick:{x:0,y:1},rightStick:{x:2,y:3},leftTrigger:4,rightTrigger:5},this.isMock=!1,"string"!=typeof t?(this.gamepad=t,this.id=t.id):(this.gamepad={},this.id=t,this.isMock=!0),this._axeTriggers=this.gamepad.axes&&void 0!==this.gamepad.axes[this.axeMapping.leftTrigger],this.hasAnalogTriggers=this._axeTriggers||void 0,this.id.includes("GuliKit")&&(this.buttonMapping.a=1,this.buttonMapping.b=0,this.buttonMapping.x=3,this.buttonMapping.y=2)}_ac(t){return"lb"==(t=t.toLowerCase())?t="l":"rb"==t?t="r":"leftstickbutton"==t?t="lsb":"rightstickbutton"==t&&(t="rsb"),t}_update(){if(this.isMock)return;if(this.gamepad=navigator.getGamepads()[this.gamepad.index],!this.gamepad?.connected)return;let t=this.gamepad;for(let e in this.buttonMapping){let i=this.buttonMapping[e],s=t.buttons[i];s&&(s.pressed?this[e]++:this[e]=this[e]>0?-1:0)}return this.leftStick.x=t.axes[this.axeMapping.leftStick.x],this.leftStick.y=t.axes[this.axeMapping.leftStick.y],this.rightStick.x=t.axes[this.axeMapping.rightStick.x],this.rightStick.y=t.axes[this.axeMapping.rightStick.y],this._axeTriggers?(this.leftTrigger=t.axes[this.axeMapping.leftTrigger],this.rightTrigger=t.axes[this.axeMapping.rightTrigger]):(this.leftTrigger=t.buttons[this.buttonMapping.lt].value,this.rightTrigger=t.buttons[this.buttonMapping.rt].value,void 0===this.hasAnalogTriggers&&(this.leftTrigger||this.rightTrigger)&&(this.hasAnalogTriggers=!Number.isInteger(this.leftTrigger)||!Number.isInteger(this.rightTrigger))),!0}_reset(){for(let t in this.buttonMapping)this[t]=0;this.leftStick.x=0,this.leftStick.y=0,this.rightStick.x=0,this.rightStick.y=0,this.leftTrigger=0,this.rightTrigger=0}get cross(){return this.a}get circle(){return this.b}get square(){return this.x}get triangle(){return this.y}get ls(){return this.leftStick}get rs(){return this.rightStick}get lb(){return this.l}get rb(){return this.r}get l1(){return this.l}get r1(){return this.r}get zl(){return this.lt}get zr(){return this.rt}get l2(){return this.leftTrigger}get r2(){return this.rightTrigger}get leftStickButton(){return this.lsb}get rightStickButton(){return this.rsb}get l3(){return this.lsb}get r3(){return this.rsb}},this._Contros=class extends Array{constructor(){if(super(),window&&(window.addEventListener("gamepadconnected",(t=>{this._onConnect(t.gamepad)})),window.addEventListener("gamepaddisconnected",(t=>{this._onDisconnect(t.gamepad)}))),"object"!=typeof navigator||!navigator.getGamepads)return;let t=navigator.getGamepads();for(let e of t)e&&this._onConnect(e)}swap(e,i){let s=this[e];this[e]=this[i],this[i]=s,0!=e&&0!=i||(t.contro=this[0],!t._q5&&t._isGlobal&&(window.contro=this[0]))}remove(t){this[t]=null}onConnect(t){return!0}onDisconnect(t){return!1}_onConnect(e){if(e){for(let t=0;tt.p5play._fps,this.renderStats=(t,e)=>{console.error("p5play: renderStats() function is deprecated. Use `p5play.renderStats = true` instead.")}})),p5.prototype.registerMethod("pre",(function(){const t=this;t._q5||(t.p5play._preDrawFrameTime=performance.now()),t.p5play.spritesDrawn=0,t.mouse._update(),t.contros._update()})),p5.prototype.registerMethod("post",(function(){const t=this;if(t.p5play._inPostDraw=!0,t.allSprites.autoCull&&t.allSprites.cull(1e4),t.allSprites._autoDraw&&(t.camera.on(),t.allSprites.draw(),t.camera.off()),t.allSprites._autoDraw??=!0,t.p5play.renderStats){let e=t.p5play._renderStats;if(e.fontSize||(1==t.allSprites.tileSize||t.allSprites.tileSize>16?e.fontSize=16:e.fontSize=10,e.gap=1.25*e.fontSize),!t.p5play._fpsAvg||t.frameCount%20==0){let e=0,i=t.p5play._fpsArr.length;for(let s=0;s55?t.color(30,255,30):r>25?t.color(255,100,30):t.color(255,30,30),t.p5play._statsColor=s}t.p5play._fpsArr.push(t.getFPS()),t.push(),t.fill(0,0,0,128),t.rect(e.x-5,e.y-e.fontSize,8.5*e.fontSize,5*e.gap+5),t.fill(t.p5play._statsColor),t.textAlign("left"),t.textSize(e.fontSize),e.font&&t.textFont(e.font);let i=e.x,s=e.y;t.text("sprites: "+t.p5play.spritesDrawn,i,s),t.text("display: "+Math.round(t.frameRate())+"hz",i,s+e.gap),t.text("fps avg: "+t.p5play._fpsAvg,i,s+2*e.gap),t.text("fps min: "+t.p5play._fpsMin,i,s+3*e.gap),t.text("fps max: "+t.p5play._fpsMax,i,s+4*e.gap),t.pop(),e.show=!1}t.world.autoStep&&t.world.timeScale>0&&t.world.step(),t.world.autoStep??=!0,t.allSprites._autoUpdate&&t.allSprites.update(),t.allSprites._autoUpdate??=!0;for(let e of t.allSprites)e.autoDraw??=!0,e.autoUpdate??=!0;for(let e in t.kb)"holdThreshold"!=e&&(t.kb[e]<0?t.kb[e]=0:t.kb[e]>0&&t.kb[e]++);for(let e=0;e0&&e[t]++,i?.hover&&(i[t]=e[t]),e._dragFrame[t]?(e.drag[t]++,i&&(i.drag[t]=e.drag[t]),e._dragFrame[t]=!1):e.drag[t]<0&&(e.drag[t]=0,i&&(i.drag[t]=0));if(t.world.mouseTracking&&t.mouse.isActive){let s=t.world.getMouseSprites();for(let t=0;t0?e.mouse.hover=-1:e.mouse.hover<0&&(e.mouse.hover=0)}e.left<=0&&e.center<=0&&e.right<=0&&(t.world.mouseSprite=null);let r=t.world.mouseSprite,o=e.drag.left>0||e.drag.center>0||e.drag.right>0;for(let e of t.world.mouseSprites)if(!s.includes(e)){let i=e.mouse;i.hover>0&&(i.hover=-1,i.left=i.center=i.right=0),o||e!=r||(t.world.mouseSprite=r=null)}r&&(s.includes(r)||s.push(r),i.x=r.x-e.x,i.y=r.y-e.y),t.world.mouseSprites=s}t.camera.off(),t._q5||(t.p5play._postDrawFrameTime=performance.now(),t.p5play._fps=Math.round(1e3/(t.p5play._postDrawFrameTime-t.p5play._preDrawFrameTime))||1),t.p5play._inPostDraw=!1})); diff --git a/v3/q5.js b/v3/q5.js index e0900633..a1e5fc7f 100644 --- a/v3/q5.js +++ b/v3/q5.js @@ -2690,22 +2690,21 @@ Q5.modules.input = ($, q) => { if (!$.touchEnded(e)) e.preventDefault(); }; - if (c) { - c.addEventListener('mousedown', (e) => $._onmousedown(e)); - c.addEventListener('mouseup', (e) => $._onmouseup(e)); - c.addEventListener('wheel', (e) => $._onwheel(e)); - c.addEventListener('click', (e) => $._onclick(e)); - c.addEventListener('touchstart', (e) => $._ontouchstart(e)); - c.addEventListener('touchmove', (e) => $._ontouchmove(e)); - c.addEventListener('touchcancel', (e) => $._ontouchend(e)); - c.addEventListener('touchend', (e) => $._ontouchend(e)); - } - if (window) { let l = window.addEventListener; - l('mousemove', (e) => $._onmousemove(e), false); l('keydown', (e) => $._onkeydown(e), false); l('keyup', (e) => $._onkeyup(e), false); + + l('mousedown', (e) => $._onmousedown(e)); + l('mousemove', (e) => $._onmousemove(e), false); + l('mouseup', (e) => $._onmouseup(e)); + l('wheel', (e) => $._onwheel(e)); + l('click', (e) => $._onclick(e)); + + l('touchstart', (e) => $._ontouchstart(e)); + l('touchmove', (e) => $._ontouchmove(e)); + l('touchend', (e) => $._ontouchend(e)); + l('touchcancel', (e) => $._ontouchend(e)); } }; Q5.modules.math = ($, q) => { diff --git a/v3/q5.min.js b/v3/q5.min.js index 3017b4b3..44990784 100644 --- a/v3/q5.min.js +++ b/v3/q5.min.js @@ -5,4 +5,4 @@ * @license LGPL-3.0 * @class Q5 */ -function Q5(e,t,r){let a=this;a._q5=!0,a._parent=t,"webgpu-fallback"==r?(a._webgpuFallback=!0,a._renderer="q2d"):a._renderer=r||Q5.render,a._preloadCount=0;let n,i="auto"==e;if(e??="global","auto"==e){if(!window.setup&&!window.draw)return;e="global"}a._scope=e,"global"==e&&(Q5._hasGlobal=a._isGlobal=!0,n=Q5._server?global:window);let o=new Proxy(a,{set:(e,t,r)=>(a[t]=r,a._isGlobal&&(n[t]=r),!0)});a.canvas=a.ctx=a.drawingContext=null,a.pixels=[];let s=null;a.frameCount=0,a.deltaTime=16,a._targetFrameRate=0,a._targetFrameDuration=16.666666666666668,a._frameRate=a._fps=60,a._loop=!0,a._hooks={postCanvas:[],preRender:[],postRender:[]};let l=0;a.millis=()=>performance.now()-l,a.noCanvas=()=>{a.canvas?.remove&&a.canvas.remove(),a.canvas=0,o.ctx=o.drawingContext=0},window&&(a.windowWidth=window.innerWidth,a.windowHeight=window.innerHeight,a.deviceOrientation=window.screen?.orientation?.type),a._incrementPreload=()=>o._preloadCount++,a._decrementPreload=()=>o._preloadCount--,a._draw=e=>{let t=e||performance.now();if(a._lastFrameTime??=t-a._targetFrameDuration,a._didResize&&(a.windowResized(),a._didResize=!1),a._loop)s=c(a._draw);else if(a.frameCount&&!a._redraw)return;if(s&&a.frameCount){if(t-a._lastFrameTime{a._loop=!1,s=null},a.loop=()=>{a._loop=!0,a._setupDone&&null==s&&a._draw()},a.isLooping=()=>a._loop,a.redraw=(e=1)=>{a._redraw=!0;for(let t=0;t{a.noLoop(),a.canvas.remove()},a.frameRate=e=>(e&&(a._targetFrameRate=e,a._targetFrameDuration=1e3/e),a._frameRate),a.getTargetFrameRate=()=>a._targetFrameRate||60,a.getFPS=()=>a._fps,a.Element=function(e){this.elt=e},a._elements=[],a.describe=()=>{},a.TWO_PI=a.TAU=2*Math.PI,a.log=a.print=console.log;for(let e in Q5.modules)Q5.modules[e](a,o);let d=Q5.renderers[a._renderer];for(let e in d)d[e](a,o);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(a[e]=Q5[e]);if("graphics"==e)return;"global"==e&&(Object.assign(Q5,a),delete Q5.Q5),a._webgpuFallback&&(a.colorMode("rgb",1),a._beginRender=()=>a.translate(a.canvas.hw,a.canvas.hh));for(let e of Q5.methods.init)e.call(a);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof a[e]&&(a[e]=t.bind(a));if("global"==e){let e=Object.getOwnPropertyNames(a);for(let t of e)"_"!=t[0]&&(n[t]=a[t])}"function"==typeof e&&e(a),Q5._instanceCount++;let c=window.requestAnimationFrame||function(e){const t=a._lastFrameTime+a._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},h=n||a;a._isTouchAware=h.touchStarted||h.touchMoved||h.mouseReleased,a._isGlobal&&(a.preload=h.preload,a.setup=h.setup,a.draw=h.draw),a.preload??=()=>{},a.setup??=()=>{},a.draw??=()=>{};let u=["mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","mouseWheel","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized"];for(let e of u)h[e]?a._isGlobal&&(a[e]=t=>{try{return h[e](t)}catch(e){throw a._askAI&&a._askAI(e),e}}):a[e]=()=>{};async function p(){if(a._startDone=!0,a._preloadCount>0)return c(p);l=performance.now(),await a.setup(),a._setupDone=!0,a.frameCount||(null===a.ctx&&a.createCanvas(200,200),a.ctx&&a.resetMatrix(),c(a._draw))}function f(){try{a.preload(),a._startDone||p()}catch(e){throw a._askAI&&a._askAI(e),e}}i?f():setTimeout(f,32)}function createCanvas(e,t,r){if(!Q5._hasGlobal){(new Q5).createCanvas(e,t,r)}}Q5.render="q2d",Q5.renderers={},Q5.modules={},Q5._server="object"==typeof process,Q5._instanceCount=0,Q5._friendlyError=(e,t)=>{Q5.disableFriendlyErrors||console.error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.methods={init:[],pre:[],post:[],remove:[]},Q5.prototype.registerMethod=(e,t)=>Q5.methods[e].push(t),Q5.prototype.registerPreloadMethod=(e,t)=>Q5.prototype[e]=t[e],Q5._server&&(global.p5??=global.Q5=Q5),"object"==typeof window?window.p5??=window.Q5=Q5:global.window=0,Q5.version=Q5.VERSION="2.11","object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||new Q5("auto")})),Q5.modules.canvas=(e,t)=>{e._OffscreenCanvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._server?Q5._createServerCanvas&&(t.canvas=Q5._createServerCanvas(100,100)):"image"!=e._scope&&"graphics"!=e._scope||(t.canvas=new e._OffscreenCanvas(100,100)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas());let r=e.canvas;async function a(e,t,r){if(t=t||"untitled","jpg"==(r=r||"png")||"png"==r||"webp"==r)if(e instanceof OffscreenCanvas){const t=await e.convertToBlob({type:"image/"+r});e=await new Promise((e=>{const r=new FileReader;r.onloadend=()=>e(r.result),r.readAsDataURL(t)}))}else e=e.toDataURL("image/"+r);else{let t="text/plain";"json"==r&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),e=new Blob([e],{type:t}),e=URL.createObjectURL(e)}let a=document.createElement("a");a.href=e,a.download=t+"."+r,a.click(),URL.revokeObjectURL(a.href)}if(e.width=200,e.height=200,e._pixelDensity=1,e.displayDensity=()=>window.devicePixelRatio||1,r&&(r.width=200,r.height=200,"image"!=e._scope&&(r.renderer=e._renderer,r[e._renderer]=!0,e._pixelDensity=Math.ceil(e.displayDensity()))),e._adjustDisplay=()=>{r.style&&(r.style.width=r.w+"px",r.style.height=r.h+"px")},e.createCanvas=function(t,a,n){"object"==typeof t&&(n=t,t=null),n??=arguments[3];let i=Object.assign({},Q5.canvasOptions);if("object"==typeof n&&Object.assign(i,n),"image"!=e._scope)if("graphics"==e._scope)e._pixelDensity=this._pixelDensity;else if(window.IntersectionObserver){let t=!1;new IntersectionObserver((a=>{r.visible=a[0].isIntersecting,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,a),Object.assign(r,i);let o=e._createCanvas(r.w,r.h,i);if(e._hooks)for(let t of e._hooks.postCanvas)t();return e._beginRender&&e._beginRender(),o},e.createGraphics=function(t,r,a){let n=new Q5("graphics");return a??={},a.alpha??=!0,a.colorSpace??=e.canvas.colorSpace,n.createCanvas.call(e,t,r,a),n.defaultWidth=t,n.defaultHeight=r,n},e.save=(t,r,n)=>{if((!t||"string"==typeof t&&(!r||!n&&r.length<5))&&(n=r,r=t,t=e.canvas),n)return a(t,r,n);r?a(t,(r=r.split("."))[0],r.at(-1)):a(t)},e._setCanvasSize=(a,n)=>{a??=window.innerWidth,n??=window.innerHeight,e.defaultWidth=r.w=a=Math.ceil(a),e.defaultHeight=r.h=n=Math.ceil(n),r.hw=a/2,r.hh=n/2,r.width=Math.ceil(a*e._pixelDensity),r.height=Math.ceil(n*e._pixelDensity),e._da?e.flexibleCanvas(e._dau):(t.width=a,t.height=n),e.displayMode&&!r.displayMode?e.displayMode():e._adjustDisplay()},e._setImageSize=(a,n)=>{t.width=r.w=a,t.height=r.h=n,r.hw=a/2,r.hh=n/2,r.width=Math.ceil(a*e._pixelDensity),r.height=Math.ceil(n*e._pixelDensity)},e.defaultImageScale=t=>t?e._defaultImageScale=t:e._defaultImageScale,e.defaultImageScale(.5),"image"!=e._scope){if(r&&"graphics"!=e._scope){function n(){let t=e._parent;t??=document.getElementsByTagName("main")[0],t||(t=document.createElement("main"),document.body.append(t)),r.parent(t)}r.parent=t=>{function a(){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(a),e._ro.observe(t)):e.frameCount||window.addEventListener("resize",a)},document.body?n():document.addEventListener("DOMContentLoaded",n)}e.resizeCanvas=(t,a)=>{if(!e.ctx)return e.createCanvas(t,a);t==r.w&&a==r.h||e._resizeCanvas(t,a)},r&&!Q5._createServerCanvas&&(r.resize=e.resizeCanvas,r.save=e.saveCanvas=e.save),e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._setCanvasSize(r.w,r.h),t):e._pixelDensity,e.flexibleCanvas=(a=400)=>{a?(e._da=r.width/(a*e._pixelDensity),t.width=e._dau=a,t.height=r.h/r.w*a):e._da=0},e._styleNames=["_fill","_stroke","_strokeWeight","_doStroke","_doFill","_strokeSet","_fillSet","_shadow","_shadowOffsetX","_shadowOffsetY","_shadowBlur","_tint","_imageMode","_rectMode","_ellipseMode","_textSize","_textAlign","_textBaseline"],e._styles=[],e.pushStyles=()=>{let t={};for(let r of e._styleNames)t[r]=e[r];e._styles.push(t)},e.popStyles=()=>{let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r]},window&&"graphics"!=e._scope&&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.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.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.P2D="2d",Q5.WEBGL="webgl",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.q2d={},Q5.renderers.q2d.canvas=(e,t)=>{let r=e.canvas;e.colorMode&&e.colorMode("srgb"!=Q5.canvasOptions.colorSpace?"rgb":"srgb",255),e._createCanvas=function(a,n,i){if(r)return t.ctx=t.drawingContext=r.getContext("2d",i),"image"!=e._scope&&(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.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()},"image"!=e._scope&&(e._resizeCanvas=(t,a)=>{let n,i={};for(let t in e.ctx)"function"!=typeof e.ctx[t]&&(i[t]=e.ctx[t]);if(delete i.canvas,e.frameCount>1){n=new e._OffscreenCanvas(r.width,r.height),n.w=r.w,n.h=r.h,n.getContext("2d").drawImage(r,0,0)}e._setCanvasSize(t,a);for(let t in i)e.ctx[t]=i[t];e.scale(e._pixelDensity),n&&e.ctx.drawImage(n,0,0,n.w,n.h)},e.fill=function(t){if(e._doFill=e._fillSet=!0,Q5.Color&&(t._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),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._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=e._stroke=t.toString()},e.strokeWeight=t=>{t||(e._doStroke=!1),e._da&&(t*=e._da),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._shadowOffsetX=e._shadowOffsetY=e._shadowBlur=10,e.shadow=function(t){Q5.Color&&(t._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t])))),e.ctx.shadowColor=e._shadow=t.toString(),e.ctx.shadowOffsetX||=e._shadowOffsetX,e.ctx.shadowOffsetY||=e._shadowOffsetY,e.ctx.shadowBlur||=e._shadowBlur},e.shadowBox=(t,r,a)=>{e.ctx.shadowOffsetX=e._shadowOffsetX=t,e.ctx.shadowOffsetY=e._shadowOffsetY=r||t,e.ctx.shadowBlur=e._shadowBlur=a||0},e.noShadow=()=>{e.ctx.shadowOffsetX=e.ctx.shadowOffsetY=e.ctx.shadowBlur=0},e.translate=(t,r)=>{e._da&&(t*=e._da,r*=e._da),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,a,n,i,o)=>e.ctx.transform(t,r,a,n,i,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.pushMatrix=()=>e.ctx.save(),e.popMatrix=()=>e.ctx.restore(),e.popStyles=()=>{let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r];e.ctx.fillStyle=e._fill,e.ctx.strokeStyle=e._stroke,e.ctx.lineWidth=e._strokeWeight},e.push=()=>{e.ctx.save(),e.pushStyles()},e.pop=()=>{e.ctx.restore(),e.popStyles()},e.createCapture=e=>{var t=document.createElement("video");return t.playsinline="playsinline",t.autoplay="autoplay",navigator.mediaDevices.getUserMedia(e).then((e=>{t.srcObject=e})),t.style.position="absolute",t.style.opacity=1e-5,t.style.zIndex=-1e3,document.body.append(t),t})},Q5.renderers.q2d.drawing=e=>{e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=Q5.CENTER,e._rectMode=Q5.CORNER,e._curveDetail=20,e._curveAlpha=0;let t=!0,r=[];function a(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}function n(t,r,a,n,i,o,s){e._angleMode&&(i=e.radians(i),o=e.radians(o));let l=e.TAU;if((i%=l)<0&&(i+=l),(o%=l)<0&&(o+=l),i>o&&(o+=l),i==o)return e.ellipse(t,r,a,n);if(a/=2,n/=2,e._doFill||s!=e.PIE_OPEN||(s=e.CHORD_OPEN),e.ctx.beginPath(),e.ctx.ellipse(t,r,a,n,0,i,o),s!=e.PIE&&s!=e.PIE_OPEN||e.ctx.lineTo(t,r),e._doFill&&e.ctx.fill(),e._doStroke){if(s!=e.PIE&&s!=e.CHORD||e.ctx.closePath(),s!=e.PIE_OPEN)return e.ctx.stroke();e.ctx.beginPath(),e.ctx.ellipse(t,r,a,n,0,i,o),e.ctx.stroke()}}function i(t,r,n,i){e.ctx.beginPath(),e.ctx.ellipse(t,r,n/2,i/2,0,0,e.TAU),a()}function o(t,r,n,i,s,l,d,c){return void 0===s?function(t,r,n,i){e._da&&(t*=e._da,r*=e._da,n*=e._da,i*=e._da),e.ctx.beginPath(),e.ctx.rect(t,r,n,i),a()}(t,r,n,i):void 0===l?o(t,r,n,i,s,s,s,s):(e._da&&(t*=e._da,r*=e._da,n*=e._da,i*=e._da,s*=e._da,l*=e._da,c*=e._da,d*=e._da),e.ctx.roundRect(t,r,n,i,[s,l,d,c]),void a())}e.blendMode=t=>e.ctx.globalCompositeOperation=t,e.strokeCap=t=>e.ctx.lineCap=t,e.strokeJoin=t=>e.ctx.lineJoin=t,e.ellipseMode=t=>e._ellipseMode=t,e.rectMode=t=>e._rectMode=t,e.curveDetail=t=>e._curveDetail=t,e.curveAlpha=t=>e._curveAlpha=t,e.curveTightness=t=>e._curveAlpha=t,e.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._q5Color&&("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height)),e.ctx.restore()},e.line=(t,r,a,n)=>{e._doStroke&&(e._da&&(t*=e._da,r*=e._da,a*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(a,n),e.ctx.stroke())},e.arc=(t,r,a,i,o,s,l)=>{if(o==s)return e.ellipse(t,r,a,i);e._da&&(t*=e._da,r*=e._da,a*=e._da,i*=e._da),l??=e.PIE_OPEN,e._ellipseMode==e.CENTER?n(t,r,a,i,o,s,l):e._ellipseMode==e.RADIUS?n(t,r,2*a,2*i,o,s,l):e._ellipseMode==e.CORNER?n(t+a/2,r+i/2,a,i,o,s,l):e._ellipseMode==e.CORNERS&&n((t+a)/2,(r+i)/2,a-t,i-r,o,s,l)},e.ellipse=(t,r,a,n)=>{n??=a,e._da&&(t*=e._da,r*=e._da,a*=e._da,n*=e._da),e._ellipseMode==e.CENTER?i(t,r,a,n):e._ellipseMode==e.RADIUS?i(t,r,2*a,2*n):e._ellipseMode==e.CORNER?i(t+a/2,r+n/2,a,n):e._ellipseMode==e.CORNERS&&i((t+a)/2,(r+n)/2,a-t,n-r)},e.circle=(t,r,n)=>{e._ellipseMode==e.CENTER?(e._da&&(t*=e._da,r*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.arc(t,r,n/2,0,e.TAU),a()):e.ellipse(t,r,n,n)},e.point=(t,r)=>{e._doStroke&&(t.x&&(r=t.y,t=t.x),e._da&&(t*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(t,r),e.ctx.stroke())},e.rect=(t,r,a,n=a,i,s,l,d)=>{e._rectMode==e.CENTER?o(t-a/2,r-n/2,a,n,i,s,l,d):e._rectMode==e.RADIUS?o(t-a,r-n,2*a,2*n,i,s,l,d):e._rectMode==e.CORNER?o(t,r,a,n,i,s,l,d):e._rectMode==e.CORNERS&&o(t,r,a-t,n-r,i,s,l,d)},e.square=(t,r,a,n,i,o,s)=>e.rect(t,r,a,a,n,i,o,s),e.beginShape=()=>{r.length=0,e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),r.length=0,t=!0},e.endContour=()=>{r.length=0,t=!0},e.vertex=(a,n)=>{e._da&&(a*=e._da,n*=e._da),r.length=0,t?e.ctx.moveTo(a,n):e.ctx.lineTo(a,n),t=!1},e.bezierVertex=(t,a,n,i,o,s)=>{e._da&&(t*=e._da,a*=e._da,n*=e._da,i*=e._da,o*=e._da,s*=e._da),r.length=0,e.ctx.bezierCurveTo(t,a,n,i,o,s)},e.quadraticVertex=(t,a,n,i)=>{e._da&&(t*=e._da,a*=e._da,n*=e._da,i*=e._da),r.length=0,e.ctx.quadraticCurveTo(t,a,n,i)},e.bezier=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(a,n,i,o,s,l),e.endShape()},e.triangle=(t,r,a,n,i,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.endShape(e.CLOSE)},e.quad=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{r.length=0,t&&e.ctx.closePath(),a()},e.curveVertex=(a,n)=>{if(e._da&&(a*=e._da,n*=e._da),r.push([a,n]),r.length<4)return;let i=r.at(-4),o=r.at(-3),s=r.at(-2),l=r.at(-1),d=o[0]+(s[0]-i[0])/6,c=o[1]+(s[1]-i[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,a,n,i,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(a,n),e.curveVertex(i,o),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,r,a,n)=>{const i=n*n*n,o=n*n;return e*(-.5*i+o-.5*n)+t*(1.5*i-2.5*o+1)+r*(-1.5*i+2*o+.5*n)+a*(.5*i-.5*o)},e.bezierPoint=(e,t,r,a,n)=>{const i=1-n;return Math.pow(i,3)*e+3*Math.pow(i,2)*n*t+3*i*Math.pow(n,2)*r+Math.pow(n,3)*a},e.curveTangent=(e,t,r,a,n)=>{const i=n*n;return e*(-3*i/2+2*n-.5)+t*(9*i/2-5*n)+r*(-9*i/2+4*n+.5)+a*(3*i/2-n)},e.bezierTangent=(e,t,r,a,n)=>{const i=1-n;return 3*a*Math.pow(n,2)-3*r*Math.pow(n,2)+6*r*i*n-6*t*i*n+3*t*Math.pow(i,2)-3*e*Math.pow(i,2)},e.erase=function(t=255,r=255){e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgba(0, 0, 0, ${t/255})`,e.ctx.strokeStyle=`rgba(0, 0, 0, ${r/255})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,r)=>{const a=e._pixelDensity;return e.ctx.isPointInPath(t*a,r*a)},e.inStroke=(t,r)=>{const a=e._pixelDensity;return e.ctx.isPointInStroke(t*a,r*a)}},Q5.renderers.q2d.image=(e,t)=>{Q5.Image??=class{constructor(e,t,r){let a=this;a._scope="image",a.canvas=a.ctx=a.drawingContext=null,a.pixels=[],Q5.modules.canvas(a,a);let n=Q5.renderers.q2d;for(let e of["canvas","image","soft_filters"])n[e]&&n[e](a,a);a._pixelDensity=r.pixelDensity||1,a.createCanvas(e,t,r),delete a.createCanvas,a._loop=!1}get w(){return this.width}get h(){return this.height}},e._tint=null;let r=null;e.createImage=(t,r,a)=>{a??={},a.alpha??=!0,a.colorSpace??=e.canvas.colorSpace||Q5.canvasOptions.colorSpace;let n=new Q5.Image(t,r,a);return n.defaultWidth=t*e._defaultImageScale,n.defaultHeight=r*e._defaultImageScale,n},e.loadImage=function(r,a,n){if(r.canvas)return r;if("gif"==r.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");t._preloadCount++;let i=[...arguments].at(-1);"object"==typeof i?(n=i,a=null):n=null;let o=e.createImage(1,1,n),s=o._pixelDensity=n?.pixelDensity||1;let l=new window.Image;return l.crossOrigin="Anonymous",l.onload=()=>function(r){r._pixelDensity=s,o.defaultWidth=r.width*e._defaultImageScale,o.defaultHeight=r.height*e._defaultImageScale,o.naturalWidth=r.naturalWidth||r.width,o.naturalHeight=r.naturalHeight||r.height,o._setImageSize(Math.ceil(o.naturalWidth/s),Math.ceil(o.naturalHeight/s)),o.ctx.drawImage(r,0,0),t._preloadCount--,a&&a(o)}(l),l.onerror=e=>{throw t._preloadCount--,e},l.src=r,o},e.imageMode=t=>e._imageMode=t,e.image=(t,r,a,n,i,o=0,s=0,l,d)=>{if(!t)return;let c=t.canvas||t;n??=t.defaultWidth||c.width||t.videoWidth,i??=t.defaultHeight||c.height||t.videoHeight,"center"==e._imageMode&&(r-=.5*n,a-=.5*i),e._da&&(r*=e._da,a*=e._da,n*=e._da,i*=e._da,o*=e._da,s*=e._da,l*=e._da,d*=e._da);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}e.ctx.drawImage(c,o*h,s*h,l,d,r,a,n,i)},e.filter=(t,r)=>{if(!e.ctx.filter)return e._softFilter(t,r);let a="";if("string"==typeof t)a=t;else if(t===Q5.GRAY)a="saturate(0%)";else if(t===Q5.INVERT)a="invert(100%)";else if(t===Q5.BLUR){a=`blur(${Math.ceil(r*e._pixelDensity)||1}px)`}else if(t===Q5.THRESHOLD){r??=.5;a=`saturate(0%) brightness(${Math.floor(.5/Math.max(r,1e-5)*100)}%) contrast(1000000%)`}else if(t===Q5.SEPIA)a=`sepia(${r??1})`;else if(t===Q5.BRIGHTNESS)a=`brightness(${r??1})`;else if(t===Q5.SATURATION)a=`saturate(${r??1})`;else if(t===Q5.CONTRAST)a=`contrast(${r??1})`;else{if(t!==Q5.HUE_ROTATE)return void e._softFilter(t,r);a=`hue-rotate(${r}${0===e._angleMode?"rad":"deg"})`}if(e.ctx.filter=a,"none"==e.ctx.filter)throw new Error(`Invalid filter format: ${t}`);e.ctx.drawImage(e.canvas,0,0,e.canvas.width,e.canvas.height),e.ctx.filter="none",e._retint=!0},"image"==e._scope&&(e.resize=(t,r)=>{let a=e.canvas,n=new e._OffscreenCanvas(a.width,a.height);n.getContext("2d",{colorSpace:a.colorSpace}).drawImage(a,0,0),e._setImageSize(t,r),e.defaultWidth=a.width*e._defaultImageScale,e.defaultHeight=a.height*e._defaultImageScale,e.ctx.clearRect(0,0,a.width,a.height),e.ctx.drawImage(n,0,0,a.width,a.height),e._retint=!0}),e._getImageData=(t,r,a,n)=>e.ctx.getImageData(t,r,a,n,{colorSpace:e.canvas.colorSpace}),e.trim=()=>{let t=e._pixelDensity||1,r=e.canvas.width,a=e.canvas.height,n=e._getImageData(0,0,r,a).data,i=r,o=0,s=a,l=0,d=3;for(let e=0;eo&&(o=t),el&&(l=e)),d+=4;return s=Math.floor(s/t),l=Math.floor(l/t),i=Math.floor(i/t),o=Math.floor(o/t),e.get(i,s,o-i+1,l-s+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._retint=!0},e.inset=(t,r,a,n,i,o,s,l)=>{let d=e._pixelDensity||1;e.ctx.drawImage(e.canvas,t*d,r*d,a*d,n*d,i,o,s,l),e._retint=!0},e.copy=()=>e.get(),e.get=(t,r,a,n)=>{let i=e._pixelDensity||1;if(void 0!==t&&void 0===a){let a=e._getImageData(t*i,r*i,1,1).data;return[a[0],a[1],a[2],a[3]/255]}t=Math.floor(t||0)*i,r=Math.floor(r||0)*i;let o=a=a||e.width,s=n=n||e.height;a*=i,n*=i;let l=e.createImage(a,n);return l.ctx.drawImage(e.canvas,t,r,a,n,0,0,a,n),l._pixelDensity=i,l.width=o,l.height=s,l},e.set=(t,r,a)=>{if(t=Math.floor(t),r=Math.floor(r),e._retint=!0,a.canvas){let n=e._tint;return e._tint=null,e.image(a,t,r),void(e._tint=n)}e.pixels.length||e.loadPixels();let n=e._pixelDensity||1;for(let i=0;i{r=e._getImageData(0,0,e.canvas.width,e.canvas.height),t.pixels=r.data},e.updatePixels=()=>{null!=r&&(e.ctx.putImageData(r,0,0),e._retint=!0)},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,"image"!=e._scope&&(e.tint=function(t){e._tint=(t._q5Color?t:e.color(...arguments)).toString()},e.noTint=()=>e._tint=null)},Q5.renderers.q2d.soft_filters=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=(a,n)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let r=0;r=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t{for(let t=0;t{for(let t=0;t{let r=t-1;for(let a=0;a>8)/r,e[a+1]=255*(e[a+1]*t>>8)/r,e[a+2]=255*(e[a+2]*t>>8)/r},e._filters[Q5.DILATE]=(a,n)=>{n??=Math.max,r(),t.set(a);let[i,o]=[e.canvas.width,e.canvas.height];for(let e=0;e{e._filters[Q5.DILATE](t,Math.min)},e._filters[Q5.BLUR]=(a,n)=>{n=n||1,n=Math.floor(n*e._pixelDensity),r(),t.set(a);let i=2*n+1,o=function(e){let t=new Float32Array(e),r=.3*n+.8,a=r*r*2;for(let n=0;n{e._textAlign="left",e._textBaseline="alphabetic",e._textSize=12;let r="sans-serif",a=!1,n=15,i=3,o="normal",s=!1,l=0,d=[],c=!1,h=!1,u=0,p=12e3,f=e._textCache={};e.loadFont=(r,a)=>{t._preloadCount++;let n=r.split("/").pop().split(".")[0].replace(" ",""),i=new FontFace(n,`url(${r})`);return document.fonts.add(i),i.load().then((()=>{t._preloadCount--,a&&a(n)})),e.textFont(n),n},e.textFont=e=>{if(!e||e==r)return r;r=e,s=!0,l=-1},e.textSize=t=>{if(null==t||t==e._textSize)return e._textSize;e._da&&(t*=e._da),e._textSize=t,s=!0,l=-1,a||(n=1.25*t,i=n-t)},e.textStyle=e=>{if(!e||e==o)return o;o=e,s=!0,l=-1},e.textLeading=t=>null==t?n||1.25*e._textSize:(a=!0,t==n?n:(e._da&&(t*=e._da),n=t,i=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)};const _=()=>{e.ctx.font=`${o} ${e._textSize}px ${r}`,s=!1};e.textWidth=t=>(s&&_(),e.ctx.measureText(t).width),e.textAscent=t=>(s&&_(),e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(s&&_(),e.ctx.measureText(t).actualBoundingBoxDescent),e.textFill=e.fill,e.textStroke=e.stroke;e.textCache=(e,t)=>(t&&(p=t),void 0!==e&&(c=e),c),e.createTextImage=(t,r,a)=>(h=!0,img=e.text(t,0,0,r,a),h=!1,img);let g=[];e.text=(t,a,_,m,x)=>{if(void 0===t||!e._doFill&&!e._doStroke)return;t=t.toString(),e._da&&(a*=e._da,_*=e._da);let v,y,w,b,S=e.ctx;if(s&&(S.font=`${o} ${e._textSize}px ${r}`,s=!1),(c||h)&&(-1==l&&(()=>{let t=r+e._textSize+o+n,a=5381;for(let e=0;e>>0})(),v=f[t],v&&(v=v[l]),v)){if(v._fill==e._fill&&v._stroke==e._stroke&&v._strokeWeight==e._strokeWeight)return h?v:e.textImage(v,a,_);v.clear()}if(-1==t.indexOf("\n")?g[0]=t:g=t.split("\n"),t.length>m){let e=[];for(let t of g){let r=0;for(;r=t.length){e.push(t.slice(r));break}let n=t.lastIndexOf(" ",a);(-1===n||n=x)break;if(g.length=0,e._fillSet||(S.fillStyle=b),c||h){if(d.push(l),(f[t]??={})[l]=v,u++,u>p){let e=Math.ceil(u/2),t=d.splice(0,e);for(let e in f){e=f[e];for(let r of t)delete e[r]}u-=e}if(h)return v;e.textImage(v,a,_)}},e.textImage=(t,r,a)=>{"string"==typeof t&&(t=e.createTextImage(t));let n=e._imageMode;e._imageMode="corner";let i=e._textAlign;"center"==i?r-=t.canvas.hw:"right"==i&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?a-=t._leading:"middle"==o?a-=t._middle:"bottom"==o?a-=t._bottom:"top"==o&&(a-=t._top),e.image(t,r,a),e._imageMode=n},e.nf=(e,t,r)=>{let a=e<0,n=(e=Math.abs(e)).toFixed(r).split(".");n[0]=n[0].padStart(t,"0");let i=n.join(".");return a&&(i="-"+i),i}},Q5.modules.ai=e=>{e.askAI=(e="")=>{throw Q5.disableFriendlyErrors=!1,Error("Ask AI ✨ "+e)},e._askAI=async e=>{let t=e.message?.includes("Ask AI ✨"),r=e.stack?.split("\n");if(!e.stack||r.length<=1)return;let a=1,n="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(a=0,n="@");r[a].indexOf("q5")>=0;)a++;let i=r[a].split(n).at(-1);i.startsWith("blob:")&&(i=i.slice(5));let o=i.split(":"),s=parseInt(o.at(-2));t&&s++,o[3]=o[3].split(")")[0];let l=o.slice(0,2).join(":"),d=l.split("/").at(-1);try{let r=(await(await fetch(l)).text()).split("\n"),a=r[s-1].trim(),n="",i=1;for(;n.length<1600&&(s-i>=0&&(n=r[s-i].trim()+"\n"+n),s+i10?e.message.slice(10):"Whats+wrong+with+this+line%3F+short+answer")+(t?"":"%0A%0A"+encodeURIComponent(e.name+": "+e.message))+"%0A%0ALine%3A+"+encodeURIComponent(a)+"%0A%0AExcerpt+for+context%3A%0A%0A"+encodeURIComponent(n);if(console.warn("Error in "+d+" on line "+s+":\n\n"+a),console.warn("Ask AI ✨ "+o),t)return window.open(o,"_blank")}catch(e){}}},Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e._colorMode="rgb",e.SRGB="srgb",e.OKLCH="oklch",e.colorMode=(r,a)=>{e._colorMode=r;let n="srgb"==e.canvas.colorSpace||"srgb"==r;a??=n?"integer":"float",e._colorFormat="float"==a||1==a?1:255,"oklch"==r?t.Color=Q5.ColorOKLCH:(255==e._colorFormat?t.Color=n?Q5.ColorRGBA_8:Q5.ColorRGBA_P3_8:t.Color=n?Q5.ColorRGBA:Q5.ColorRGBA_P3,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],crimson:[220,20,60],cyan:[0,255,255],darkviolet:[148,0,211],gold:[255,215,0],green:[0,128,0],gray:[128,128,128],grey:[128,128,128],hotpink:[255,105,180],indigo:[75,0,130],khaki:[240,230,140],lightgreen:[144,238,144],lime:[0,255,0],magenta:[255,0,255],navy:[0,0,128],orange:[255,165,0],olive:[128,128,0],peachpuff:[255,218,185],pink:[255,192,203],purple:[128,0,128],red:[255,0,0],skyblue:[135,206,235],tan:[210,180,140],turquoise:[64,224,208],transparent:[0,0,0,0],white:[255,255,255],violet:[238,130,238],yellow:[255,255,0]},e.color=(t,r,a,n)=>{let i=e.Color;if(t._q5Color)return new i(...t.levels);if(null==r){if("string"==typeof t){if("#"==t[0])t.length<=5?(t.length>4&&(n=parseInt(t[4]+t[4],16)),a=parseInt(t[3]+t[3],16),r=parseInt(t[2]+t[2],16),t=parseInt(t[1]+t[1],16)):(t.length>7&&(n=parseInt(t.slice(7,9),16)),a=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])return console.error("q5 can't parse color: "+t+"\nOnly numeric input, hex, and common named colors are supported."),new i(0,0,0);[t,r,a,n]=e._namedColors[t]}1==e._colorFormat&&(t/=255,r&&(r/=255),a&&(a/=255),n&&(n/=255))}Array.isArray(t)&&([t,r,a,n]=t)}return null==a?e._colorMode==Q5.OKLCH?new i(t,0,0,r):new i(t,t,t,r):new i(t,r,a,n)},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=e=>e.l?e.l:100*(.2126*e.r+.7152*e.g+.0722*e.b)/255,e.hue=t=>{if(t.h)return t.h;let r=t.r,a=t.g,n=t.b;255==e._colorFormat&&(r/=255,a/=255,n/=255);let i,o=Math.max(r,a,n),s=Math.min(r,a,n);return i=o==s?0:o==r?60*(a-n)/(o-s):o==a?60*(n-r)/(o-s)+120:60*(r-a)/(o-s)+240,i<0&&(i+=360),i},e.lerpColor=(t,r,a)=>{if(a=Math.max(0,Math.min(1,a)),"rgb"==e._colorMode)return new e.Color(e.lerp(t.r,r.r,a),e.lerp(t.g,r.g,a),e.lerp(t.b,r.b,a),e.lerp(t.a,r.a,a));{let n=r.h-t.h;n>180&&(n-=360),n<-180&&(n+=360);let i=t.h+a*n;return i<0&&(i+=360),i>360&&(i-=360),new e.Color(e.lerp(t.l,r.l,a),e.lerp(t.c,r.c,a),i,e.lerp(t.a,r.a,a))}}},Q5.Color=class{constructor(){this._q5Color=!0}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,r,a){super(),this.l=e,this.c=t,this.h=r,this.a=a??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}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorRGBA=class extends Q5.Color{constructor(e,t,r,a){super(),this.r=e,this.g=t,this.b=r,this.a=a??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}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorRGBA_P3=class extends Q5.ColorRGBA{toString(){return`color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`}},Q5.ColorRGBA_8=class extends Q5.ColorRGBA{constructor(e,t,r,a){super(e,t,r,a??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.ColorRGBA_P3_8=class extends Q5.ColorRGBA{constructor(e,t,r,a){super(e,t,r,a??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),a=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${r} / ${a})`,this._edited=!1}return this._css}},Q5.modules.display=e=>{if(!e.canvas||"graphics"==e._scope)return;let t=e.canvas;e.CENTERED="centered",e.FULLSCREEN="fullscreen",e.MAXED="maxed",e.PIXELATED="pixelated",0!=Q5._instanceCount||Q5._server||document.head.insertAdjacentHTML("beforeend",""),e._adjustDisplay=()=>{let r=t.style,a=t.parentElement;r&&a&&t.displayMode&&("pixelated"==t.renderQuality&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.defaultImageScale(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),"default"==t.displayMode||"normal"==t.displayMode?(a.classList.remove("q5-centered","q5-maxed","q5-fullscreen"),r.width=t.w*t.displayScale+"px",r.height=t.h*t.displayScale+"px"):(a.classList.add("q5-"+t.displayMode),a=a.getBoundingClientRect(),t.w/t.h>a.width/a.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",a="smooth",n=1)=>{"string"==typeof n&&(n=parseFloat(n.slice(1))),"center"==r&&(r="centered"),Object.assign(t,{displayMode:r,renderQuality:a,displayScale:n}),e._adjustDisplay()},e.fullscreen=e=>{if(void 0===e)return document.fullscreenElement;e?document.body.requestFullscreen():document.body.exitFullscreen()}},Q5.modules.input=(e,t)=>{if("graphics"==e._scope)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.mouseButton="",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={},a=[Q5.LEFT,Q5.CENTER,Q5.RIGHT],n=e.canvas;function i(t){const r=e.canvas.getBoundingClientRect(),a=e.canvas.scrollWidth/e.width||1,n=e.canvas.scrollHeight/e.height||1;return{x:(t.clientX-r.left)/a,y:(t.clientY-r.top)/n,id:t.identifier}}if(e._startAudio=()=>{Q5.aud&&"suspended"!=Q5.aud?.state||e.userStartAudio()},e._updateMouse=r=>{if(!r.changedTouches){if(n){let a=n.getBoundingClientRect(),i=n.scrollWidth/e.width||1,o=n.scrollHeight/e.height||1;t.mouseX=(r.clientX-a.left)/i,t.mouseY=(r.clientY-a.top)/o,"webgpu"==n.renderer&&(t.mouseX-=n.hw,t.mouseY-=n.hh)}else t.mouseX=r.clientX,t.mouseY=r.clientY;t.moveX=r.movementX,t.moveY=r.movementY}},e._onmousedown=r=>{e._startAudio(),e._updateMouse(r),t.mouseIsPressed=!0,t.mouseButton=a[r.button],e.mousePressed(r)},e._onmousemove=t=>{e._updateMouse(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t)},e._onmouseup=r=>{e._updateMouse(r),t.mouseIsPressed=!1,e.mouseReleased(r)},e._onclick=r=>{e._updateMouse(r),t.mouseIsPressed=!0,e.mouseClicked(r),t.mouseIsPressed=!1},e._onwheel=t=>{e._updateMouse(t),t.delta=t.deltaY,0==e.mouseWheel(t)&&t.preventDefault()},e.cursor=(t,r,a)=>{let n="";t.includes(".")&&(t=`url("${t}")`,n=", auto"),void 0!==r&&(t+=" "+r+" "+a),e.canvas.style.cursor=t+n},e.noCursor=()=>{e.canvas.style.cursor="none"},window&&(e.requestPointerLock=document.body?.requestPointerLock,e.exitPointerLock=document.exitPointerLock),e._onkeydown=a=>{a.repeat||(e._startAudio(),t.keyIsPressed=!0,t.key=a.key,t.keyCode=a.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!0,e.keyPressed(a),1==a.key.length&&e.keyTyped(a))},e._onkeyup=a=>{t.keyIsPressed=!1,t.key=a.key,t.keyCode=a.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!1,e.keyReleased(a)},e.keyIsDown=e=>!!r["string"==typeof e?e.toLowerCase():e],e._ontouchstart=r=>{e._startAudio(),t.touches=[...r.touches].map(i),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,t.mouseIsPressed=!0,t.mouseButton=e.LEFT,e.mousePressed(r)||r.preventDefault()),e.touchStarted(r)||r.preventDefault()},e._ontouchmove=r=>{t.touches=[...r.touches].map(i),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,e.mouseDragged(r)||r.preventDefault()),e.touchMoved(r)||r.preventDefault()},e._ontouchend=r=>{t.touches=[...r.touches].map(i),e._isTouchAware||e.touches.length||(t.mouseIsPressed=!1,e.mouseReleased(r)||r.preventDefault()),e.touchEnded(r)||r.preventDefault()},n&&(n.addEventListener("mousedown",(t=>e._onmousedown(t))),n.addEventListener("mouseup",(t=>e._onmouseup(t))),n.addEventListener("wheel",(t=>e._onwheel(t))),n.addEventListener("click",(t=>e._onclick(t))),n.addEventListener("touchstart",(t=>e._ontouchstart(t))),n.addEventListener("touchmove",(t=>e._ontouchmove(t))),n.addEventListener("touchcancel",(t=>e._ontouchend(t))),n.addEventListener("touchend",(t=>e._ontouchend(t)))),window){let t=window.addEventListener;t("mousemove",(t=>e._onmousemove(t)),!1),t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1)}},Q5.modules.math=(e,t)=>{e.RADIANS=0,e.DEGREES=1,e.PI=Math.PI,e.HALF_PI=Math.PI/2,e.QUARTER_PI=Math.PI/4,e.abs=Math.abs,e.ceil=Math.ceil,e.exp=Math.exp,e.floor=e.int=Math.floor,e.loge=Math.log,e.mag=Math.hypot,e.max=Math.max,e.min=Math.min,e.round=Math.round,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2;let r=e._angleMode=0;e.angleMode=t=>(r=e._angleMode=0==t||"radians"==t?0:1,r?"degrees":"radians");let a=e._DEGTORAD=Math.PI/180,n=e._RADTODEG=180/Math.PI;function i(){let e,t,r=4294967295;return{setSeed(a){e=t=(a??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,a,n,i)=>{let o=a+1*(e-t)/(r-t)*(n-a);return i?ae*(1-r)+t*r,e.constrain=(e,t,r)=>Math.min(Math.max(e,t),r),e.norm=(t,r,a)=>e.map(t,r,a,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=e=>Math.sin(r?e*a:e),e.cos=e=>Math.cos(r?e*a:e),e.tan=e=>Math.tan(r?e*a:e),e.asin=e=>{let t=Math.asin(e);return r?t*n:t},e.acos=e=>{let t=Math.acos(e);return r?t*n:t},e.atan=e=>{let t=Math.atan(e);return r?t*n:t},e.atan2=(e,t)=>{let a=Math.atan2(e,t);return r?a*n:a};let o=i();o.setSeed(),e.randomSeed=e=>o.setSeed(e),e.random=(e,t)=>void 0===e?o.rand():"number"==typeof e?void 0!==t?o.rand()*(t-e)+e:o.rand()*e:e[Math.trunc(e.length*o.rand())],e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,r;return{setSeed(a){r=t=(a??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(r=(1664525*r+1013904223)%e,r/e)}}():t==e.SHR3&&(o=i()),o.setSeed()};var s=new function(){var e,t,r,a=new Array(128),n=new Array(256),i=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,n,o,l,d=3.44262;;){if(t=r*i[e],0==e){do{o=h(),l=h(),t=.2904764*-Math.log(o),n=-Math.log(l)}while(n+n0?d+t:-d-t}if(s[e]+h()*(s[e-1]-s[e]){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])(r=c(),e=127&r,Math.abs(r)(t=c()>>>0){var e,t,r=2147483648,o=4294967296,c=3.442619855899,h=c,u=.00991256303526217,p=7.697117470131487,f=p,_=.003949659822581572;for(e=u/Math.exp(-.5*c*c),a[0]=Math.floor(c/e*r),a[1]=0,i[0]=e/r,i[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))),a[t+1]=Math.floor(c/h*r),h=c,s[t]=Math.exp(-.5*c*c),i[t]=c/r;for(e=_/Math.exp(-p),n[0]=Math.floor(p/e*o),n[1]=0,l[0]=e/o,l[255]=p/o,d[0]=1,d[255]=Math.exp(-p),t=254;t>=1;t--)p=-Math.log(_/p+Math.exp(-p)),n[t+1]=Math.floor(p/f*o),f=p,d[t]=Math.exp(-p),l[t]=p/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.Noise=Q5.PerlinNoise,e.noiseMode=e=>{t.Noise=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],l=null},e.noiseSeed=t=>{l=new e.Noise(t)},e.noise=(t=0,r=0,a=0)=>(l??=new e.Noise,l.noise(t,r,a)),e.noiseDetail=(t,r)=>{l??=new e.Noise,t>0&&(l.octaves=t),r>0&&(l.falloff=r)}},Q5.Noise=class{},Q5.PerlinNoise=class extends Q5.Noise{constructor(e){super(),this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.octaves=1,this.falloff=.5,this.p=null==e?Array.from({length:256},(()=>Math.floor(256*Math.random()))):this.seedPermutation(e),this.p=this.p.concat(this.p)}seedPermutation(e){let t,r,a=[];for(let e=0;e<256;e++)a[e]=e;for(let n=255;n>0;n--)t=(e=16807*e%2147483647)%(n+1),r=a[n],a[n]=a[t],a[t]=r;return a}dot(e,t,r,a){return e[0]*t+e[1]*r+e[2]*a}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 a=this,n=0,i=1,o=1,s=0;for(let l=0;l{e.Sound=Q5.Sound;let r=[];e.loadSound=(e,a)=>{t._preloadCount++;let n=new Q5.Sound(e,a);return n.crossOrigin="Anonymous",n.addEventListener("canplaythrough",(()=>{n.loaded||(t._preloadCount--,n.loaded=!0,Q5.aud&&n.init(),a&&a(n))})),r.push(n),n},e.getAudioContext=()=>Q5.aud,e.userStartAudio=()=>{if(window.AudioContext){if(!Q5.aud){Q5.aud=new window.AudioContext;for(let e of r)e.init()}return Q5.aud.resume()}}},window.Audio&&(Q5.Sound??=class extends Audio{init(){let e=this;e.panner=Q5.aud.createStereoPanner(),e.source=Q5.aud.createMediaElementSource(e),e.source.connect(e.panner),e.panner.connect(Q5.aud.destination);let t=e.pan;Object.defineProperty(e,"pan",{get:()=>e.panner.pan.value,set:t=>e.panner.pan.value=t}),t&&(e.pan=t)}setVolume(e){this.volume=e}setLoop(e){this.loop=e}setPan(e){this.pan=e}isLoaded(){return this.loaded}isPlaying(){return!this.paused}}),Q5.modules.util=(e,t)=>{e._loadFile=(r,a,n)=>{t._preloadCount++;let i={};return fetch(r).then((e=>"json"==n?e.json():e.text())).then((r=>{t._preloadCount--,"csv"==n&&(r=e.CSV.parse(r)),Object.assign(i,r),a&&a(r)})),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.CSV={},e.CSV.parse=(e,t=",",r="\n")=>{let a=[],n=e.split(r),i=n[0].split(t);for(let e=1;er[e]=JSON.parse(o[t]))),a.push(r)}return a},"object"==typeof localStorage&&(e.storeItem=localStorage.setItem,e.getItem=localStorage.getItem,e.removeItem=localStorage.removeItem,e.clearStorage=localStorage.clear),e.year=()=>(new Date).getFullYear(),e.day=()=>(new Date).getDay(),e.hour=()=>(new Date).getHours(),e.minute=()=>(new Date).getMinutes(),e.second=()=>(new Date).getSeconds()},Q5.modules.vector=e=>{e.createVector=(t,r,a)=>new Q5.Vector(t,r,a,e)},Q5.Vector=class{constructor(e,t,r,a){this.x=e||0,this.y=t||0,this.z=r||0,this._$=a||window,this._cn=null,this._cnsq=null}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}}_calcNorm(){this._cnsq=this.x*this.x+this.y*this.y+this.z*this.z,this._cn=Math.sqrt(this._cnsq)}add(){let e=this._arg2v(...arguments);return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}rem(){let e=this._arg2v(...arguments);return this.x%=e.x,this.y%=e.y,this.z%=e.z,this}sub(){let e=this._arg2v(...arguments);return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}mult(){let e=this._arg2v(...arguments);return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}div(){let e=this._arg2v(...arguments);return e.x?this.x/=e.x:this.x=0,e.y?this.y/=e.y:this.y=0,e.z?this.z/=e.z:this.z=0,this}mag(){return this._calcNorm(),this._cn}magSq(){return this._calcNorm(),this._cnsq}dot(){let e=this._arg2v(...arguments);return this.x*e.x+this.y*e.y+this.z*e.z}dist(){let e=this._arg2v(...arguments),t=this.x-e.x,r=this.y-e.y,a=this.z-e.z;return Math.sqrt(t*t+r*r+a*a)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,r=this.z*e.x-this.x*e.z,a=this.x*e.y-this.y*e.x;return this.x=t,this.y=r,this.z=a,this}normalize(){this._calcNorm();let e=this._cn;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._cn=1,this._cnsq=1,this}limit(e){this._calcNorm();let t=this._cn;if(t>e){let r=e/t;this.x*=r,this.y*=r,this.z*=r,this._cn=e,this._cnsq=e*e}return this}setMag(e){this._calcNorm();let t=e/this._cn;return this.x*=t,this.y*=t,this.z*=t,this._cn=e,this._cnsq=e*e,this}heading(){return this._$.atan2(this.y,this.x)}setHeading(e){let t=this.mag();return this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this}rotate(e){let t=this._$.cos(e),r=this._$.sin(e),a=this.x*t-this.y*r,n=this.x*r+this.y*t;return this.x=a,this.y=n,this}angleBetween(){let e=this._arg2v(...arguments),t=Q5.Vector.cross(this,e);return this._$.atan2(t.mag(),this.dot(e))*Math.sign(t.z||1)}lerp(){let e=[...arguments],t=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 a=this.mag(),n=r.mag();if(0==a||0==n)return this.mult(1-t).add(r.mult(t));let i=Q5.Vector.cross(this,r),o=i.mag(),s=Math.atan2(o,this.dot(r));if(o>0)i.div(o);else{if(se.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.heading=e=>this._$.atan2(e.y,e.x),Q5.Vector.magSq=e=>e.x*e.x+e.y*e.y+e.z*e.z,Q5.Vector.mag=e=>Math.sqrt(Q5.Vector.magSq(e)),Q5.Vector.mult=(e,t)=>e.copy().mult(t),Q5.Vector.normalize=e=>e.copy().normalize(),Q5.Vector.rem=(e,t)=>e.copy().rem(t),Q5.Vector.sub=(e,t)=>e.copy().sub(t);for(let e of["fromAngle","fromAngles","random2D","random3D"])Q5.Vector[e]=(t,r,a)=>(new Q5.Vector)[e](t,r,a);Q5.renderers.webgpu={},Q5.renderers.webgpu.canvas=(e,t)=>{let r=e.canvas;r.width=e.width=500,r.height=e.height=500,e.colorMode&&e.colorMode("rgb",1);let a,n,i,o=1,s=8;e._pipelineConfigs=[],e._pipelines=[];let l=e.drawStack=[],d=e.colorStack=new Float32Array(1e6);d.set([0,0,0,1,1,1,1,1]),e._transformLayout=Q5.device.createBindGroupLayout({label:"transformLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",hasDynamicOffset:!1}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage",hasDynamicOffset:!1}}]}),i=Q5.device.createBindGroupLayout({label:"colorsLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage",hasDynamicOffset:!1}}]}),e.bindGroupLayouts=[e._transformLayout,i];let c=Q5.device.createBuffer({size:8,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),h=()=>{n=Q5.device.createTexture({size:[e.canvas.width,e.canvas.height],sampleCount:4,format:"bgra8unorm",usage:GPUTextureUsage.RENDER_ATTACHMENT}).createView()};e._createCanvas=(a,n,i)=>(t.ctx=t.drawingContext=r.getContext("webgpu"),i.format??=navigator.gpu.getPreferredCanvasFormat(),i.device??=Q5.device,i.alpha&&(i.alphaMode="premultiplied"),e.ctx.configure(i),Q5.device.queue.writeBuffer(c,0,new Float32Array([e.canvas.hw,e.canvas.hh])),h(),r),e._resizeCanvas=(t,r)=>{e._setCanvasSize(t,r),h()},e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._setCanvasSize(r.w,r.h),h(),t):e._pixelDensity;let u=(t,r,a,n=1)=>{"string"==typeof t?t=e.color(t):null==a&&(n=r??1,r=a=t),t._q5Color&&(n=t.a,a=t.b,r=t.g,t=t.r);let i=d,l=s;i[l++]=t,i[l++]=r,i[l++]=a,i[l++]=n,s=l,o++};e._stroke=0,e._fill=1,e._doFill=e._doStroke=!0,e.fill=(t,r,a,n)=>{u(t,r,a,n),e._doFill=e._fillSet=!0,e._fill=o},e.stroke=(t,r,a,n)=>{u(t,r,a,n),e._doStroke=e._strokeSet=!0,e._stroke=o},e.noFill=()=>e._doFill=!1,e.noStroke=()=>e._doStroke=!1,e._strokeWeight=1,e.strokeWeight=t=>e._strokeWeight=Math.abs(t),e.resetMatrix=()=>{e._matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e._transformIndex=0},e.resetMatrix(),e._matrixDirty=!1;let p=[e._matrix.slice()];e._transformIndexStack=[],e.translate=(t,r,a)=>{(t||r||a)&&(e._matrix[12]+=t,e._matrix[13]-=r,e._matrix[14]+=a||0,e._matrixDirty=!0)},e.rotate=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.cos(t),a=Math.sin(t),n=e._matrix,i=n[0],o=n[1],s=n[4],l=n[5];1!=i||o||s||1!=l?(n[0]=i*r+o*a,n[1]=o*r-i*a,n[4]=s*r+l*a,n[5]=l*r-s*a):(n[0]=r,n[1]=-a,n[4]=a,n[5]=r),e._matrixDirty=!0},e.scale=(t=1,r,a=1)=>{r??=t;let n=e._matrix;n[0]*=t,n[1]*=t,n[2]*=t,n[3]*=t,n[4]*=r,n[5]*=r,n[6]*=r,n[7]*=r,n[8]*=a,n[9]*=a,n[10]*=a,n[11]*=a,e._matrixDirty=!0},e.shearX=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),a=e._matrix[0],n=e._matrix[1],i=e._matrix[4],o=e._matrix[5];e._matrix[0]=a+i*r,e._matrix[1]=n+o*r,e._matrixDirty=!0},e.shearY=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),a=e._matrix[0],n=e._matrix[1],i=e._matrix[4],o=e._matrix[5];e._matrix[4]=i+a*r,e._matrix[5]=o+n*r,e._matrixDirty=!0},e.applyMatrix=(...t)=>{let r;if(r=1==t.length?t[0]:t,9==r.length)r=[r[0],r[1],0,r[2],r[3],r[4],0,r[5],0,0,1,0,r[6],r[7],0,r[8]];else if(16!=r.length)throw new Error("Matrix must be a 3x3 or 4x4 array.");e._matrix=r.slice(),e._matrixDirty=!0},e._saveMatrix=()=>{p.push(e._matrix.slice()),e._transformIndex=p.length-1,e._matrixDirty=!1},e.pushMatrix=()=>{e._matrixDirty&&e._saveMatrix(),e._transformIndexStack.push(e._transformIndex)},e.popMatrix=()=>{if(!e._transformIndexStack.length)return console.warn("Matrix index stack is empty!");let t=e._transformIndexStack.pop();e._matrix=p[t].slice(),e._transformIndex=t,e._matrixDirty=!1},e.push=()=>{e.pushMatrix(),e.pushStyles()},e.pop=()=>{e.popMatrix(),e.popStyles()},e._calcBox=(e,t,r,a,n)=>{let i,o,s,l,d=r/2,c=a/2;return n&&"corner"!=n?"center"==n?(i=e-d,o=e+d,s=-(t-c),l=-(t+c)):(i=e,o=r,s=-t,l=-a):(i=e,o=e+r,s=-t,l=-(t+a)),[i,o,s,l]};let f=["zero","one","src-alpha","one-minus-src-alpha","dst","dst-alpha","one-minus-dst-alpha","one-minus-src"],_=["add","subtract","reverse-subtract","min","max"];const g={normal:[2,3,0,2,3,0],additive:[1,1,0,1,1,0]};e.blendConfigs={};for(const[t,r]of Object.entries(g))e.blendConfigs[t]={color:{srcFactor:f[r[0]],dstFactor:f[r[1]],operation:_[r[2]]},alpha:{srcFactor:f[r[3]],dstFactor:f[r[4]],operation:_[r[5]]}};e._blendMode="normal",e.blendMode=t=>{if(t!=e._blendMode){"source-over"==t&&(t="normal"),"lighter"==t&&(t="additive"),t=t.toLowerCase().replace(/[ -]/g,"_"),e._blendMode=t;for(let r=0;r{},e._beginRender=()=>{e.encoder=Q5.device.createCommandEncoder(),a=t.pass=e.encoder.beginRenderPass({label:"q5-webgpu",colorAttachments:[{view:n,resolveTarget:e.ctx.getCurrentTexture().createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]})},e._render=()=>{if(p.length>1||!e._transformBindGroup){let t=Q5.device.createBuffer({size:64*p.length,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(p.flat()),t.unmap(),e._transformBindGroup=Q5.device.createBindGroup({layout:e._transformLayout,entries:[{binding:0,resource:{buffer:c}},{binding:1,resource:{buffer:t}}]})}a.setBindGroup(0,e._transformBindGroup);let t=Q5.device.createBuffer({size:4*s,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(d.slice(0,s)),t.unmap(),e._colorsBindGroup=Q5.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:t}}]}),e.pass.setBindGroup(1,e._colorsBindGroup);for(let t of e._hooks.preRender)t();let r=0,n=0,o=0,h=-1;for(let t=0;t{a.end();let r=e.encoder.finish();Q5.device.queue.submit([r]),t.pass=e.encoder=null,e.drawStack.length=0,o=1,s=8,rotation=0,p.length=1,e._transformIndexStack.length=0}},Q5.initWebGPU=async()=>{if(!navigator.gpu)return console.warn("q5 WebGPU not supported on this browser!"),!1;if(!Q5.device){let e=await navigator.gpu.requestAdapter();if(!e)throw new Error("No appropriate GPUAdapter found.");Q5.device=await e.requestDevice()}return!0},Q5.webgpu=async function(e,t){return e&&"global"!=e||(Q5._hasGlobal=!0),await Q5.initWebGPU()?new Q5(e,t,"webgpu"):new Q5(e,t,"webgpu-fallback")},Q5.renderers.webgpu.drawing=(e,t)=>{let r=e.canvas,a=e.drawStack,n=new Float32Array(1e7),i=0,o=Q5.device.createShaderModule({label:"drawingVertexShader",code:"\nstruct VertexInput {\n\t@location(0) pos: vec2f,\n\t@location(1) colorIndex: f32,\n\t@location(2) transformIndex: f32\n}\nstruct VertexOutput {\n\t@builtin(position) position: vec4f,\n\t@location(0) color: vec4f\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@group(1) @binding(0) var colors : array;\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n\tvar vert = vec4f(input.pos, 0.0, 1.0);\n\tvert = transforms[i32(input.transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output: VertexOutput;\n\toutput.position = vert;\n\toutput.color = colors[i32(input.colorIndex)];\n\treturn output;\n}\n"}),s=Q5.device.createShaderModule({label:"drawingFragmentShader",code:"\n@fragment\nfn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {\n\treturn color;\n}\n"}),l=Q5.device.createPipelineLayout({label:"drawingPipelineLayout",bindGroupLayouts:e.bindGroupLayouts});e._pipelineConfigs[0]={label:"drawingPipeline",layout:l,vertex:{module:o,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:s,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[0]=Q5.device.createRenderPipeline(e._pipelineConfigs[0]);const d=(e,t,r,a)=>{let o=n,s=i;o[s++]=e,o[s++]=t,o[s++]=r,o[s++]=a,i=s},c=(e,t,r,o,s,l,d,c,h,u)=>{let p=n,f=i;p[f++]=e,p[f++]=t,p[f++]=h,p[f++]=u,p[f++]=r,p[f++]=o,p[f++]=h,p[f++]=u,p[f++]=d,p[f++]=c,p[f++]=h,p[f++]=u,p[f++]=s,p[f++]=l,p[f++]=h,p[f++]=u,i=f,a.push(0,4)},h=(t,r,o,s,l,d,c)=>{r=-r;let h=0,u=e.TAU/l,p=n,f=i;for(let e=0;e<=l;e++){p[f++]=t,p[f++]=r,p[f++]=d,p[f++]=c;let e=t+o*Math.cos(h),a=r+s*Math.sin(h);p[f++]=e,p[f++]=a,p[f++]=d,p[f++]=c,h+=u}p[f++]=t,p[f++]=r,p[f++]=d,p[f++]=c,p[f++]=t+o,p[f++]=r,p[f++]=d,p[f++]=c,i=f,a.push(0,2*(l+1)+2)};e.rectMode=t=>e._rectMode=t,e.rect=(t,r,a,n)=>{let i,o,[s,l,d,h]=e._calcBox(t,r,a,n,e._rectMode);if(e._matrixDirty&&e._saveMatrix(),o=e._transformIndex,e._doFill&&(i=e._fill,c(s,d,l,d,l,h,s,h,i,o)),e._doStroke){i=e._stroke;let t=e._strokeWeight/2,r=s-t,a=l+t,n=d+t,u=h-t,p=s+t,f=l-t,_=d-t,g=h+t;c(r,_,a,_,a,n,r,n,i,o),c(r,u,a,u,a,g,r,g,i,o),n=d-t,u=h+t,c(r,n,p,n,p,u,r,u,i,o),c(f,n,a,n,a,u,f,u,i,o)}},e.square=(t,r,a)=>e.rect(t,r,a,a);const u=e=>e<4?6:e<6?8:e<10?10:e<16?12:e<20?14:e<22?16:e<24?18:e<28?20:e<34?22:e<42?24:e<48?26:e<56?28:e<64?30:e<72?32:e<84?34:e<96?36:e<98?38:e<113?40:e<149?44:e<199?48:e<261?52:e<353?56:e<461?60:e<585?64:e<1200?70:e<1800?80:e<2400?90:100;let p;e.ellipseMode=t=>e._ellipseMode=t,e.ellipse=(t,r,o,s)=>{let l=u(Math.max(o,s)),d=Math.max(o,1)/2,c=o==s?d:Math.max(s,1)/2;e._matrixDirty&&e._saveMatrix();let p=e._transformIndex;if(e._doFill&&h(t,r,d,c,l,e._fill,p),e._doStroke){let o=e._strokeWeight/2;((t,r,o,s,l,d,c,h,u)=>{r=-r;let p=e.TAU/c,f=0,_=n,g=i;for(let e=0;e<=c;e++){let e=t+o*Math.cos(f),a=r+s*Math.sin(f),n=t+l*Math.cos(f),i=r+d*Math.sin(f);_[g++]=e,_[g++]=a,_[g++]=h,_[g++]=u,_[g++]=n,_[g++]=i,_[g++]=h,_[g++]=u,f+=p}i=g,a.push(0,2*(c+1))})(t,r,d+o,c+o,d-o,c-o,l,e._stroke,p)}},e.circle=(t,r,a)=>e.ellipse(t,r,a,a),e.point=(t,r)=>{e._matrixDirty&&e._saveMatrix();let a=e._transformIndex,n=e._stroke,i=e._strokeWeight;if(i<2){let[o,s,l,d]=e._calcBox(t,r,i,i,"corner");c(o,l,s,l,s,d,o,d,n,a)}else{let e=u(i);i/=2,h(t,r,i,i,e,n,a)}},e.stokeJoin=t=>{e.log("q5 WebGPU doesn't support changing stroke join style.")},e.line=(t,r,a,n)=>{e._matrixDirty&&e._saveMatrix();let i=e._transformIndex,o=e._stroke,s=e._strokeWeight,l=s/2,d=a-t,p=n-r,f=Math.hypot(d,p),_=-p/f*l,g=d/f*l;if(c(t+_,-r-g,t-_,-r+g,a-_,-n+g,a+_,-n-g,o,i),s>2){let e=u(s);h(t,r,l,l,e,o,i),h(a,n,l,l,e,o,i)}};let f=[],_=[];e.beginShape=()=>{p=0,f=[],_=[]},e.vertex=(t,r)=>{e._matrixDirty&&e._saveMatrix(),f.push(t,-r,e._fill,e._transformIndex),p++},e.curveVertex=(t,r)=>{e._matrixDirty&&e._saveMatrix(),_.push({x:t,y:-r})},e.endShape=t=>{if(_.length>0){let t=[..._];if(t.length<4)for(;t.length<4;)t.unshift(t[0]),t.push(t[t.length-1]);for(let r=0;r{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.endShape(!0)},e.quad=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.vertex(s,l),e.endShape(!0)},e.background=(t,a,n,i)=>{if(e.push(),e.resetMatrix(),e._doStroke=!1,t.src){let a=e._imageMode;e._imageMode="corner",e.image(t,-r.hw,-r.hh,r.w,r.h),e._imageMode=a}else{let o=e._rectMode;e._rectMode="corner",e.fill(t,a,n,i),e.rect(-r.hw,-r.hh,r.w,r.h),e._rectMode=o}e.pop(),e._fillSet||(e._fill=1)},e._hooks.preRender.push((()=>{e.pass.setPipeline(e._pipelines[0]);let t=Q5.device.createBuffer({size:4*i,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(n.slice(0,i)),t.unmap(),e.pass.setVertexBuffer(0,t)})),e._hooks.postRender.push((()=>{i=0}))},Q5.renderers.webgpu.image=(e,t)=>{e._textureBindGroups=[];let r=[],a=Q5.device.createShaderModule({label:"imageVertexShader",code:"\nstruct VertexOutput {\n\t@builtin(position) position: vec4f,\n\t@location(0) texCoord: vec2f\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@vertex\nfn vertexMain(@location(0) pos: vec2f, @location(1) texCoord: vec2f, @location(2) transformIndex: f32) -> VertexOutput {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output: VertexOutput;\n\toutput.position = vert;\n\toutput.texCoord = texCoord;\n\treturn output;\n}\n\t"}),n=Q5.device.createShaderModule({label:"imageFragmentShader",code:"\n@group(2) @binding(0) var samp: sampler;\n@group(2) @binding(1) var texture: texture_2d;\n\n@fragment\nfn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {\n\t// Sample the texture using the interpolated texture coordinate\n\treturn textureSample(texture, samp, texCoord);\n}\n\t"}),i=Q5.device.createBindGroupLayout({label:"textureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]});const o=Q5.device.createPipelineLayout({label:"imagePipelineLayout",bindGroupLayouts:[...e.bindGroupLayouts,i]});let s;e._pipelineConfigs[1]={label:"imagePipeline",layout:o,vertex:{module:a,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},{arrayStride:20,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"},{shaderLocation:2,offset:16,format:"float32"}]}]},fragment:{module:n,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[1]=Q5.device.createRenderPipeline(e._pipelineConfigs[1]);let l=e=>{s=Q5.device.createSampler({magFilter:e,minFilter:e})};l("linear"),e.smooth=()=>{l("linear")},e.noSmooth=()=>{l("nearest")};e._textures=[];let d=0;e._createTexture=t=>{t.canvas&&(t=t.canvas);let r=[t.width,t.height,1],a=Q5.device.createTexture({size:r,format:"bgra8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:t},{texture:a,colorSpace:e.canvas.colorSpace},r),e._textures[d]=a,t.textureIndex=d;const n=Q5.device.createBindGroup({layout:i,entries:[{binding:0,resource:s},{binding:1,resource:a.createView()}]});e._textureBindGroups[d]=n,d=(d+1)%12e3,e._textures[d]&&(e._textures[d].destroy(),delete e._textures[d],delete e._textureBindGroups[d])},e.loadImage=(r,a)=>{t._preloadCount++;const n=new Image;return n.crossOrigin="Anonymous",n.onload=()=>{n.defaultWidth=n.width*e._defaultImageScale,n.defaultHeight=n.height*e._defaultImageScale,n.pixelDensity=1,e._createTexture(n),t._preloadCount--,a&&a(n)},n.src=r,n},e.imageMode=t=>e._imageMode=t,e.image=(t,a,n,i,o,s=0,l=0,d,c)=>{if(t.canvas&&(t=t.canvas),null==t.textureIndex)return;e._matrixDirty&&e._saveMatrix();let h=e._transformIndex,u=t.width,p=t.height;i??=t.defaultWidth,o??=t.defaultHeight,d??=u,c??=p;let f=t.pixelDensity||1;i*=f,o*=f;let[_,g,m,x]=e._calcBox(a,n,i,o,e._imageMode),v=s/u,y=l/p,w=(s+d)/u,b=(l+c)/p;r.push(_,m,v,y,h,g,m,w,y,h,_,x,v,b,h,g,x,w,b,h),e.drawStack.push(1,t.textureIndex)},e._hooks.preRender.push((()=>{if(!e._textureBindGroups.length)return;e.pass.setPipeline(e._pipelines[1]);const t=Q5.device.createBuffer({size:4*r.length,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(r),t.unmap(),e.pass.setVertexBuffer(1,t)})),e._hooks.postRender.push((()=>{r.length=0}))},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.renderers.webgpu.text=(e,t)=>{let r=Q5.device.createShaderModule({label:"MSDF text shader",code:"\n// Positions for simple quad geometry\nconst pos = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));\n\nstruct VertexInput {\n\t@builtin(vertex_index) vertex : u32,\n\t@builtin(instance_index) instance : u32\n}\nstruct VertexOutput {\n\t@builtin(position) position : vec4f,\n\t@location(0) texCoord : vec2f,\n\t@location(1) fillColor : vec4f\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\ttransformIndex: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@group(1) @binding(0) var colors : array;\n\n@group(2) @binding(0) var fontTexture: texture_2d;\n@group(2) @binding(1) var fontSampler: sampler;\n@group(2) @binding(2) var fontChars: array;\n\n@group(3) @binding(0) var textChars: array;\n@group(3) @binding(1) var textMetadata: array;\n\n@vertex\nfn vertexMain(input : VertexInput) -> VertexOutput {\n\tlet char = textChars[input.instance];\n\n\tlet text = textMetadata[i32(char.w)];\n\n\tlet fontChar = fontChars[i32(char.z)];\n\n\tlet charPos = ((pos[input.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;\n\n\tvar vert = vec4f(charPos, 0.0, 1.0);\n\tvert = transforms[i32(text.transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output : VertexOutput;\n\toutput.position = vert;\n\toutput.texCoord = (pos[input.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;\n\toutput.fillColor = colors[i32(text.fillIndex)];\n\treturn output;\n}\n\nfn sampleMsdf(texCoord: vec2f) -> f32 {\n\tlet c = textureSample(fontTexture, fontSampler, texCoord);\n\treturn max(min(c.r, c.g), min(max(c.r, c.g), c.b));\n}\n\n@fragment\nfn fragmentMain(input : VertexOutput) -> @location(0) vec4f {\n\t// pxRange (AKA distanceRange) comes from the msdfgen tool,\n\t// uses the default which is 4.\n\tlet pxRange = 4.0;\n\tlet sz = vec2f(textureDimensions(fontTexture, 0));\n\tlet dx = sz.x*length(vec2f(dpdxFine(input.texCoord.x), dpdyFine(input.texCoord.x)));\n\tlet dy = sz.y*length(vec2f(dpdxFine(input.texCoord.y), dpdyFine(input.texCoord.y)));\n\tlet toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);\n\tlet sigDist = sampleMsdf(input.texCoord) - 0.5;\n\tlet pxDist = sigDist * toPixels;\n\tlet edgeWidth = 0.5;\n\tlet alpha = smoothstep(-edgeWidth, edgeWidth, pxDist);\n\tif (alpha < 0.001) {\n\t\tdiscard;\n\t}\n\treturn vec4f(input.fillColor.rgb, input.fillColor.a * alpha);\n}\n"}),a=Q5.device.createBindGroupLayout({label:"MSDF text group layout",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"}}]}),n=Q5.device.createSampler({minFilter:"linear",magFilter:"linear",mipmapFilter:"linear",maxAnisotropy:16}),i=Q5.device.createBindGroupLayout({label:"MSDF font group layout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:2,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),o=Q5.device.createPipelineLayout({bindGroupLayouts:[...e.bindGroupLayouts,i,a]});e._pipelineConfigs[2]={label:"msdf font pipeline",layout:o,vertex:{module:r,entryPoint:"vertexMain"},fragment:{module:r,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[2]=Q5.device.createRenderPipeline(e._pipelineConfigs[2]);class s{constructor(e,t,r,a){this.bindGroup=e,this.lineHeight=t,this.chars=r,this.kernings=a;let n=Object.values(r);this.charCount=n.length,this.defaultChar=n[0]}getChar(e){return this.chars[e]??this.defaultChar}getXAdvance(e,t=-1){let r=this.getChar(e);if(t>=0){let a=this.kernings.get(e);if(a)return r.xadvance+(a.get(t)??0)}return r.xadvance}}e._fonts=[];let l={},d=e.createGraphics(1,1);d.colorMode(e.RGB,1),e.loadFont=(r,a)=>{if("json"!=r.slice(r.lastIndexOf(".")+1))return d.loadFont(r,a);let o=r.slice(r.lastIndexOf("/")+1,r.lastIndexOf("-"));return(async(r,a,o)=>{t._preloadCount++;let d=await fetch(r);if(404==d.status)return t._preloadCount--,"";let c=await d.json(),h=r.lastIndexOf("/"),u=-1!=h?r.substring(0,h+1):"";d=await fetch(u+c.pages[0]);let p=await createImageBitmap(await d.blob()),f=[p.width,p.height,1],_=Q5.device.createTexture({label:`MSDF ${a}`,size:f,format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:p},{texture:_},f),"string"==typeof c.chars&&(c.chars=e.CSV.parse(c.chars," "),c.kernings=e.CSV.parse(c.kernings," "));let g=c.chars.length,m=Q5.device.createBuffer({size:32*g,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),x=new Float32Array(m.getMappedRange()),v=1/c.common.scaleW,y=1/c.common.scaleH,w={},b=0;for(let[e,t]of c.chars.entries())w[t.id]=t,w[t.id].charIndex=e,x[b]=t.x*v,x[b+1]=t.y*y,x[b+2]=t.width*v,x[b+3]=t.height*y,x[b+4]=t.width,x[b+5]=t.height,x[b+6]=t.xoffset,x[b+7]=-t.yoffset,b+=8;m.unmap();let S=Q5.device.createBindGroup({label:"msdf font bind group",layout:i,entries:[{binding:0,resource:_.createView()},{binding:1,resource:n},{binding:2,resource:{buffer:m}}]}),M=new Map;if(c.kernings)for(let e of c.kernings){let t=M.get(e.first);t||(t=new Map,M.set(e.first,t)),t.set(e.second,e.amount)}e._font=new s(S,c.common.lineHeight,w,M),e._font.index=e._fonts.length,e._fonts.push(e._font),l[a]=e._font,t._preloadCount--,o&&o(a)})(r,o,a),o},e._textSize=18,e._textAlign="left",e._textBaseline="alphabetic";let c=!1,h=22.5,u=4.5,p=1.25;e.textFont=t=>{e._font=l[t]},e.textSize=t=>{e._textSize=t,c||(h=t*p,u=h-t)},e.textLeading=t=>{e._font.lineHeight=h=t,u=h-e._textSize,p=h/e._textSize,c=!0},e.textAlign=(t,r)=>{e._textAlign=t,r&&(e._textBaseline=r)},e._charStack=[],e._textStack=[];let f,_=(e,t,r)=>{let a=0,n=0,i=0,o=0,s=0,l=[],d=t.charCodeAt(0);for(let c=0;c{if(!e._font)return void(navigator.onLine&&!f&&(f=!0,e.loadFont("https://q5js.org/fonts/YaHei-msdf.json")));if(t.length>n){let e=[],r=0;for(;r=t.length){e.push(t.slice(r));break}let i=t.lastIndexOf(" ",a);(-1==i||i{let i=0;"center"==d?i=-.5*s.width- -.5*(s.width-s.lineWidths[a]):"right"==d&&(i=s.width-s.lineWidths[a]),l[p]=e+i,l[p+1]=t+r,l[p+2]=n.charIndex,l[p+3]=u,p+=4}))}else s=_(e._font,t,((e,t,r,a)=>{l[p]=e,l[p+1]=t,l[p+2]=a.charIndex,l[p+3]=u,p+=4})),"alphabetic"==c?a-=e._textSize:"center"==c?a-=.5*e._textSize:"bottom"==c&&(a-=h);e._charStack.push(l);let g=[];e._matrixDirty&&e._saveMatrix(),g[0]=r,g[1]=-a,g[2]=e._textSize/44,g[3]=e._transformIndex,g[4]=e._fillSet?e._fill:0,g[5]=e._stroke,e._textStack.push(g),e.drawStack.push(2,s.printedCharCount,e._font.index)},e.textWidth=t=>e._font?_(e._font,t).width:0,e.createTextImage=(t,r,a)=>{if(d.textSize(e._textSize),e._doFill){let t=4*e._fill;d.fill(colorStack.slice(t,t+4))}if(e._doStroke){let t=4*e._stroke;d.stroke(colorStack.slice(t,t+4))}let n=d.createTextImage(t,r,a);if(null==n.canvas.textureIndex)e._createTexture(n);else if(n.modified){let t=n.canvas,r=[t.width,t.height,1],a=e._textures[t.textureIndex];Q5.device.queue.copyExternalImageToTexture({source:t},{texture:a,colorSpace:e.canvas.colorSpace},r),n.modified=!1}return n},e.textImage=(t,r,a)=>{"string"==typeof t&&(t=e.createTextImage(t));let n=e._imageMode;e._imageMode="corner";let i=e._textAlign;"center"==i?r-=t.canvas.hw:"right"==i&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?a-=t._leading:"center"==o?a-=t._middle:"bottom"==o?a-=t._bottom:"top"==o&&(a-=t._top),e.image(t,r,a),e._imageMode=n},e._hooks.preRender.push((()=>{if(!e._charStack.length)return;let t=0;for(let r of e._charStack)t+=4*r.length;let r=Q5.device.createBuffer({size:t,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(r.getMappedRange()).set(e._charStack.flat()),r.unmap();let n=6*e._textStack.length*4,i=Q5.device.createBuffer({label:"textBuffer",size:n,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(i.getMappedRange()).set(e._textStack.flat()),i.unmap(),e._textBindGroup=Q5.device.createBindGroup({label:"msdf text bind group",layout:a,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:i}}]})})),e._hooks.postRender.push((()=>{e._charStack.length=0,e._textStack.length=0}))}; +function Q5(e,t,r){let a=this;a._q5=!0,a._parent=t,"webgpu-fallback"==r?(a._webgpuFallback=!0,a._renderer="q2d"):a._renderer=r||Q5.render,a._preloadCount=0;let n,i="auto"==e;if(e??="global","auto"==e){if(!window.setup&&!window.draw)return;e="global"}a._scope=e,"global"==e&&(Q5._hasGlobal=a._isGlobal=!0,n=Q5._server?global:window);let o=new Proxy(a,{set:(e,t,r)=>(a[t]=r,a._isGlobal&&(n[t]=r),!0)});a.canvas=a.ctx=a.drawingContext=null,a.pixels=[];let s=null;a.frameCount=0,a.deltaTime=16,a._targetFrameRate=0,a._targetFrameDuration=16.666666666666668,a._frameRate=a._fps=60,a._loop=!0,a._hooks={postCanvas:[],preRender:[],postRender:[]};let l=0;a.millis=()=>performance.now()-l,a.noCanvas=()=>{a.canvas?.remove&&a.canvas.remove(),a.canvas=0,o.ctx=o.drawingContext=0},window&&(a.windowWidth=window.innerWidth,a.windowHeight=window.innerHeight,a.deviceOrientation=window.screen?.orientation?.type),a._incrementPreload=()=>o._preloadCount++,a._decrementPreload=()=>o._preloadCount--,a._draw=e=>{let t=e||performance.now();if(a._lastFrameTime??=t-a._targetFrameDuration,a._didResize&&(a.windowResized(),a._didResize=!1),a._loop)s=c(a._draw);else if(a.frameCount&&!a._redraw)return;if(s&&a.frameCount){if(t-a._lastFrameTime{a._loop=!1,s=null},a.loop=()=>{a._loop=!0,a._setupDone&&null==s&&a._draw()},a.isLooping=()=>a._loop,a.redraw=(e=1)=>{a._redraw=!0;for(let t=0;t{a.noLoop(),a.canvas.remove()},a.frameRate=e=>(e&&(a._targetFrameRate=e,a._targetFrameDuration=1e3/e),a._frameRate),a.getTargetFrameRate=()=>a._targetFrameRate||60,a.getFPS=()=>a._fps,a.Element=function(e){this.elt=e},a._elements=[],a.describe=()=>{},a.TWO_PI=a.TAU=2*Math.PI,a.log=a.print=console.log;for(let e in Q5.modules)Q5.modules[e](a,o);let d=Q5.renderers[a._renderer];for(let e in d)d[e](a,o);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(a[e]=Q5[e]);if("graphics"==e)return;"global"==e&&(Object.assign(Q5,a),delete Q5.Q5),a._webgpuFallback&&(a.colorMode("rgb",1),a._beginRender=()=>a.translate(a.canvas.hw,a.canvas.hh));for(let e of Q5.methods.init)e.call(a);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof a[e]&&(a[e]=t.bind(a));if("global"==e){let e=Object.getOwnPropertyNames(a);for(let t of e)"_"!=t[0]&&(n[t]=a[t])}"function"==typeof e&&e(a),Q5._instanceCount++;let c=window.requestAnimationFrame||function(e){const t=a._lastFrameTime+a._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},h=n||a;a._isTouchAware=h.touchStarted||h.touchMoved||h.mouseReleased,a._isGlobal&&(a.preload=h.preload,a.setup=h.setup,a.draw=h.draw),a.preload??=()=>{},a.setup??=()=>{},a.draw??=()=>{};let u=["mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","mouseWheel","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized"];for(let e of u)h[e]?a._isGlobal&&(a[e]=t=>{try{return h[e](t)}catch(e){throw a._askAI&&a._askAI(e),e}}):a[e]=()=>{};async function p(){if(a._startDone=!0,a._preloadCount>0)return c(p);l=performance.now(),await a.setup(),a._setupDone=!0,a.frameCount||(null===a.ctx&&a.createCanvas(200,200),a.ctx&&a.resetMatrix(),c(a._draw))}function f(){try{a.preload(),a._startDone||p()}catch(e){throw a._askAI&&a._askAI(e),e}}i?f():setTimeout(f,32)}function createCanvas(e,t,r){if(!Q5._hasGlobal){(new Q5).createCanvas(e,t,r)}}Q5.render="q2d",Q5.renderers={},Q5.modules={},Q5._server="object"==typeof process,Q5._instanceCount=0,Q5._friendlyError=(e,t)=>{Q5.disableFriendlyErrors||console.error(t+": "+e)},Q5._validateParameters=()=>!0,Q5.methods={init:[],pre:[],post:[],remove:[]},Q5.prototype.registerMethod=(e,t)=>Q5.methods[e].push(t),Q5.prototype.registerPreloadMethod=(e,t)=>Q5.prototype[e]=t[e],Q5._server&&(global.p5??=global.Q5=Q5),"object"==typeof window?window.p5??=window.Q5=Q5:global.window=0,Q5.version=Q5.VERSION="2.11","object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||new Q5("auto")})),Q5.modules.canvas=(e,t)=>{e._OffscreenCanvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._server?Q5._createServerCanvas&&(t.canvas=Q5._createServerCanvas(100,100)):"image"!=e._scope&&"graphics"!=e._scope||(t.canvas=new e._OffscreenCanvas(100,100)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas());let r=e.canvas;async function a(e,t,r){if(t=t||"untitled","jpg"==(r=r||"png")||"png"==r||"webp"==r)if(e instanceof OffscreenCanvas){const t=await e.convertToBlob({type:"image/"+r});e=await new Promise((e=>{const r=new FileReader;r.onloadend=()=>e(r.result),r.readAsDataURL(t)}))}else e=e.toDataURL("image/"+r);else{let t="text/plain";"json"==r&&("string"!=typeof e&&(e=JSON.stringify(e)),t="text/json"),e=new Blob([e],{type:t}),e=URL.createObjectURL(e)}let a=document.createElement("a");a.href=e,a.download=t+"."+r,a.click(),URL.revokeObjectURL(a.href)}if(e.width=200,e.height=200,e._pixelDensity=1,e.displayDensity=()=>window.devicePixelRatio||1,r&&(r.width=200,r.height=200,"image"!=e._scope&&(r.renderer=e._renderer,r[e._renderer]=!0,e._pixelDensity=Math.ceil(e.displayDensity()))),e._adjustDisplay=()=>{r.style&&(r.style.width=r.w+"px",r.style.height=r.h+"px")},e.createCanvas=function(t,a,n){"object"==typeof t&&(n=t,t=null),n??=arguments[3];let i=Object.assign({},Q5.canvasOptions);if("object"==typeof n&&Object.assign(i,n),"image"!=e._scope)if("graphics"==e._scope)e._pixelDensity=this._pixelDensity;else if(window.IntersectionObserver){let t=!1;new IntersectionObserver((a=>{r.visible=a[0].isIntersecting,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,a),Object.assign(r,i);let o=e._createCanvas(r.w,r.h,i);if(e._hooks)for(let t of e._hooks.postCanvas)t();return e._beginRender&&e._beginRender(),o},e.createGraphics=function(t,r,a){let n=new Q5("graphics");return a??={},a.alpha??=!0,a.colorSpace??=e.canvas.colorSpace,n.createCanvas.call(e,t,r,a),n.defaultWidth=t,n.defaultHeight=r,n},e.save=(t,r,n)=>{if((!t||"string"==typeof t&&(!r||!n&&r.length<5))&&(n=r,r=t,t=e.canvas),n)return a(t,r,n);r?a(t,(r=r.split("."))[0],r.at(-1)):a(t)},e._setCanvasSize=(a,n)=>{a??=window.innerWidth,n??=window.innerHeight,e.defaultWidth=r.w=a=Math.ceil(a),e.defaultHeight=r.h=n=Math.ceil(n),r.hw=a/2,r.hh=n/2,r.width=Math.ceil(a*e._pixelDensity),r.height=Math.ceil(n*e._pixelDensity),e._da?e.flexibleCanvas(e._dau):(t.width=a,t.height=n),e.displayMode&&!r.displayMode?e.displayMode():e._adjustDisplay()},e._setImageSize=(a,n)=>{t.width=r.w=a,t.height=r.h=n,r.hw=a/2,r.hh=n/2,r.width=Math.ceil(a*e._pixelDensity),r.height=Math.ceil(n*e._pixelDensity)},e.defaultImageScale=t=>t?e._defaultImageScale=t:e._defaultImageScale,e.defaultImageScale(.5),"image"!=e._scope){if(r&&"graphics"!=e._scope){function n(){let t=e._parent;t??=document.getElementsByTagName("main")[0],t||(t=document.createElement("main"),document.body.append(t)),r.parent(t)}r.parent=t=>{function a(){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(a),e._ro.observe(t)):e.frameCount||window.addEventListener("resize",a)},document.body?n():document.addEventListener("DOMContentLoaded",n)}e.resizeCanvas=(t,a)=>{if(!e.ctx)return e.createCanvas(t,a);t==r.w&&a==r.h||e._resizeCanvas(t,a)},r&&!Q5._createServerCanvas&&(r.resize=e.resizeCanvas,r.save=e.saveCanvas=e.save),e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._setCanvasSize(r.w,r.h),t):e._pixelDensity,e.flexibleCanvas=(a=400)=>{a?(e._da=r.width/(a*e._pixelDensity),t.width=e._dau=a,t.height=r.h/r.w*a):e._da=0},e._styleNames=["_fill","_stroke","_strokeWeight","_doStroke","_doFill","_strokeSet","_fillSet","_shadow","_shadowOffsetX","_shadowOffsetY","_shadowBlur","_tint","_imageMode","_rectMode","_ellipseMode","_textSize","_textAlign","_textBaseline"],e._styles=[],e.pushStyles=()=>{let t={};for(let r of e._styleNames)t[r]=e[r];e._styles.push(t)},e.popStyles=()=>{let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r]},window&&"graphics"!=e._scope&&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.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.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.P2D="2d",Q5.WEBGL="webgl",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.q2d={},Q5.renderers.q2d.canvas=(e,t)=>{let r=e.canvas;e.colorMode&&e.colorMode("srgb"!=Q5.canvasOptions.colorSpace?"rgb":"srgb",255),e._createCanvas=function(a,n,i){if(r)return t.ctx=t.drawingContext=r.getContext("2d",i),"image"!=e._scope&&(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.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()},"image"!=e._scope&&(e._resizeCanvas=(t,a)=>{let n,i={};for(let t in e.ctx)"function"!=typeof e.ctx[t]&&(i[t]=e.ctx[t]);if(delete i.canvas,e.frameCount>1){n=new e._OffscreenCanvas(r.width,r.height),n.w=r.w,n.h=r.h,n.getContext("2d").drawImage(r,0,0)}e._setCanvasSize(t,a);for(let t in i)e.ctx[t]=i[t];e.scale(e._pixelDensity),n&&e.ctx.drawImage(n,0,0,n.w,n.h)},e.fill=function(t){if(e._doFill=e._fillSet=!0,Q5.Color&&(t._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),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._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=e._stroke=t.toString()},e.strokeWeight=t=>{t||(e._doStroke=!1),e._da&&(t*=e._da),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._shadowOffsetX=e._shadowOffsetY=e._shadowBlur=10,e.shadow=function(t){Q5.Color&&(t._q5Color||("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t])))),e.ctx.shadowColor=e._shadow=t.toString(),e.ctx.shadowOffsetX||=e._shadowOffsetX,e.ctx.shadowOffsetY||=e._shadowOffsetY,e.ctx.shadowBlur||=e._shadowBlur},e.shadowBox=(t,r,a)=>{e.ctx.shadowOffsetX=e._shadowOffsetX=t,e.ctx.shadowOffsetY=e._shadowOffsetY=r||t,e.ctx.shadowBlur=e._shadowBlur=a||0},e.noShadow=()=>{e.ctx.shadowOffsetX=e.ctx.shadowOffsetY=e.ctx.shadowBlur=0},e.translate=(t,r)=>{e._da&&(t*=e._da,r*=e._da),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,a,n,i,o)=>e.ctx.transform(t,r,a,n,i,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.pushMatrix=()=>e.ctx.save(),e.popMatrix=()=>e.ctx.restore(),e.popStyles=()=>{let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r];e.ctx.fillStyle=e._fill,e.ctx.strokeStyle=e._stroke,e.ctx.lineWidth=e._strokeWeight},e.push=()=>{e.ctx.save(),e.pushStyles()},e.pop=()=>{e.ctx.restore(),e.popStyles()},e.createCapture=e=>{var t=document.createElement("video");return t.playsinline="playsinline",t.autoplay="autoplay",navigator.mediaDevices.getUserMedia(e).then((e=>{t.srcObject=e})),t.style.position="absolute",t.style.opacity=1e-5,t.style.zIndex=-1e3,document.body.append(t),t})},Q5.renderers.q2d.drawing=e=>{e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=Q5.CENTER,e._rectMode=Q5.CORNER,e._curveDetail=20,e._curveAlpha=0;let t=!0,r=[];function a(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}function n(t,r,a,n,i,o,s){e._angleMode&&(i=e.radians(i),o=e.radians(o));let l=e.TAU;if((i%=l)<0&&(i+=l),(o%=l)<0&&(o+=l),i>o&&(o+=l),i==o)return e.ellipse(t,r,a,n);if(a/=2,n/=2,e._doFill||s!=e.PIE_OPEN||(s=e.CHORD_OPEN),e.ctx.beginPath(),e.ctx.ellipse(t,r,a,n,0,i,o),s!=e.PIE&&s!=e.PIE_OPEN||e.ctx.lineTo(t,r),e._doFill&&e.ctx.fill(),e._doStroke){if(s!=e.PIE&&s!=e.CHORD||e.ctx.closePath(),s!=e.PIE_OPEN)return e.ctx.stroke();e.ctx.beginPath(),e.ctx.ellipse(t,r,a,n,0,i,o),e.ctx.stroke()}}function i(t,r,n,i){e.ctx.beginPath(),e.ctx.ellipse(t,r,n/2,i/2,0,0,e.TAU),a()}function o(t,r,n,i,s,l,d,c){return void 0===s?function(t,r,n,i){e._da&&(t*=e._da,r*=e._da,n*=e._da,i*=e._da),e.ctx.beginPath(),e.ctx.rect(t,r,n,i),a()}(t,r,n,i):void 0===l?o(t,r,n,i,s,s,s,s):(e._da&&(t*=e._da,r*=e._da,n*=e._da,i*=e._da,s*=e._da,l*=e._da,c*=e._da,d*=e._da),e.ctx.roundRect(t,r,n,i,[s,l,d,c]),void a())}e.blendMode=t=>e.ctx.globalCompositeOperation=t,e.strokeCap=t=>e.ctx.lineCap=t,e.strokeJoin=t=>e.ctx.lineJoin=t,e.ellipseMode=t=>e._ellipseMode=t,e.rectMode=t=>e._rectMode=t,e.curveDetail=t=>e._curveDetail=t,e.curveAlpha=t=>e._curveAlpha=t,e.curveTightness=t=>e._curveAlpha=t,e.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._q5Color&&("string"!=typeof t?t=e.color(...arguments):e._namedColors[t]&&(t=e.color(...e._namedColors[t]))),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height)),e.ctx.restore()},e.line=(t,r,a,n)=>{e._doStroke&&(e._da&&(t*=e._da,r*=e._da,a*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(a,n),e.ctx.stroke())},e.arc=(t,r,a,i,o,s,l)=>{if(o==s)return e.ellipse(t,r,a,i);e._da&&(t*=e._da,r*=e._da,a*=e._da,i*=e._da),l??=e.PIE_OPEN,e._ellipseMode==e.CENTER?n(t,r,a,i,o,s,l):e._ellipseMode==e.RADIUS?n(t,r,2*a,2*i,o,s,l):e._ellipseMode==e.CORNER?n(t+a/2,r+i/2,a,i,o,s,l):e._ellipseMode==e.CORNERS&&n((t+a)/2,(r+i)/2,a-t,i-r,o,s,l)},e.ellipse=(t,r,a,n)=>{n??=a,e._da&&(t*=e._da,r*=e._da,a*=e._da,n*=e._da),e._ellipseMode==e.CENTER?i(t,r,a,n):e._ellipseMode==e.RADIUS?i(t,r,2*a,2*n):e._ellipseMode==e.CORNER?i(t+a/2,r+n/2,a,n):e._ellipseMode==e.CORNERS&&i((t+a)/2,(r+n)/2,a-t,n-r)},e.circle=(t,r,n)=>{e._ellipseMode==e.CENTER?(e._da&&(t*=e._da,r*=e._da,n*=e._da),e.ctx.beginPath(),e.ctx.arc(t,r,n/2,0,e.TAU),a()):e.ellipse(t,r,n,n)},e.point=(t,r)=>{e._doStroke&&(t.x&&(r=t.y,t=t.x),e._da&&(t*=e._da,r*=e._da),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(t,r),e.ctx.stroke())},e.rect=(t,r,a,n=a,i,s,l,d)=>{e._rectMode==e.CENTER?o(t-a/2,r-n/2,a,n,i,s,l,d):e._rectMode==e.RADIUS?o(t-a,r-n,2*a,2*n,i,s,l,d):e._rectMode==e.CORNER?o(t,r,a,n,i,s,l,d):e._rectMode==e.CORNERS&&o(t,r,a-t,n-r,i,s,l,d)},e.square=(t,r,a,n,i,o,s)=>e.rect(t,r,a,a,n,i,o,s),e.beginShape=()=>{r.length=0,e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),r.length=0,t=!0},e.endContour=()=>{r.length=0,t=!0},e.vertex=(a,n)=>{e._da&&(a*=e._da,n*=e._da),r.length=0,t?e.ctx.moveTo(a,n):e.ctx.lineTo(a,n),t=!1},e.bezierVertex=(t,a,n,i,o,s)=>{e._da&&(t*=e._da,a*=e._da,n*=e._da,i*=e._da,o*=e._da,s*=e._da),r.length=0,e.ctx.bezierCurveTo(t,a,n,i,o,s)},e.quadraticVertex=(t,a,n,i)=>{e._da&&(t*=e._da,a*=e._da,n*=e._da,i*=e._da),r.length=0,e.ctx.quadraticCurveTo(t,a,n,i)},e.bezier=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(a,n,i,o,s,l),e.endShape()},e.triangle=(t,r,a,n,i,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.endShape(e.CLOSE)},e.quad=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{r.length=0,t&&e.ctx.closePath(),a()},e.curveVertex=(a,n)=>{if(e._da&&(a*=e._da,n*=e._da),r.push([a,n]),r.length<4)return;let i=r.at(-4),o=r.at(-3),s=r.at(-2),l=r.at(-1),d=o[0]+(s[0]-i[0])/6,c=o[1]+(s[1]-i[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,a,n,i,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(a,n),e.curveVertex(i,o),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,r,a,n)=>{const i=n*n*n,o=n*n;return e*(-.5*i+o-.5*n)+t*(1.5*i-2.5*o+1)+r*(-1.5*i+2*o+.5*n)+a*(.5*i-.5*o)},e.bezierPoint=(e,t,r,a,n)=>{const i=1-n;return Math.pow(i,3)*e+3*Math.pow(i,2)*n*t+3*i*Math.pow(n,2)*r+Math.pow(n,3)*a},e.curveTangent=(e,t,r,a,n)=>{const i=n*n;return e*(-3*i/2+2*n-.5)+t*(9*i/2-5*n)+r*(-9*i/2+4*n+.5)+a*(3*i/2-n)},e.bezierTangent=(e,t,r,a,n)=>{const i=1-n;return 3*a*Math.pow(n,2)-3*r*Math.pow(n,2)+6*r*i*n-6*t*i*n+3*t*Math.pow(i,2)-3*e*Math.pow(i,2)},e.erase=function(t=255,r=255){e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgba(0, 0, 0, ${t/255})`,e.ctx.strokeStyle=`rgba(0, 0, 0, ${r/255})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,r)=>{const a=e._pixelDensity;return e.ctx.isPointInPath(t*a,r*a)},e.inStroke=(t,r)=>{const a=e._pixelDensity;return e.ctx.isPointInStroke(t*a,r*a)}},Q5.renderers.q2d.image=(e,t)=>{Q5.Image??=class{constructor(e,t,r){let a=this;a._scope="image",a.canvas=a.ctx=a.drawingContext=null,a.pixels=[],Q5.modules.canvas(a,a);let n=Q5.renderers.q2d;for(let e of["canvas","image","soft_filters"])n[e]&&n[e](a,a);a._pixelDensity=r.pixelDensity||1,a.createCanvas(e,t,r),delete a.createCanvas,a._loop=!1}get w(){return this.width}get h(){return this.height}},e._tint=null;let r=null;e.createImage=(t,r,a)=>{a??={},a.alpha??=!0,a.colorSpace??=e.canvas.colorSpace||Q5.canvasOptions.colorSpace;let n=new Q5.Image(t,r,a);return n.defaultWidth=t*e._defaultImageScale,n.defaultHeight=r*e._defaultImageScale,n},e.loadImage=function(r,a,n){if(r.canvas)return r;if("gif"==r.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");t._preloadCount++;let i=[...arguments].at(-1);"object"==typeof i?(n=i,a=null):n=null;let o=e.createImage(1,1,n),s=o._pixelDensity=n?.pixelDensity||1;let l=new window.Image;return l.crossOrigin="Anonymous",l.onload=()=>function(r){r._pixelDensity=s,o.defaultWidth=r.width*e._defaultImageScale,o.defaultHeight=r.height*e._defaultImageScale,o.naturalWidth=r.naturalWidth||r.width,o.naturalHeight=r.naturalHeight||r.height,o._setImageSize(Math.ceil(o.naturalWidth/s),Math.ceil(o.naturalHeight/s)),o.ctx.drawImage(r,0,0),t._preloadCount--,a&&a(o)}(l),l.onerror=e=>{throw t._preloadCount--,e},l.src=r,o},e.imageMode=t=>e._imageMode=t,e.image=(t,r,a,n,i,o=0,s=0,l,d)=>{if(!t)return;let c=t.canvas||t;n??=t.defaultWidth||c.width||t.videoWidth,i??=t.defaultHeight||c.height||t.videoHeight,"center"==e._imageMode&&(r-=.5*n,a-=.5*i),e._da&&(r*=e._da,a*=e._da,n*=e._da,i*=e._da,o*=e._da,s*=e._da,l*=e._da,d*=e._da);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}e.ctx.drawImage(c,o*h,s*h,l,d,r,a,n,i)},e.filter=(t,r)=>{if(!e.ctx.filter)return e._softFilter(t,r);let a="";if("string"==typeof t)a=t;else if(t===Q5.GRAY)a="saturate(0%)";else if(t===Q5.INVERT)a="invert(100%)";else if(t===Q5.BLUR){a=`blur(${Math.ceil(r*e._pixelDensity)||1}px)`}else if(t===Q5.THRESHOLD){r??=.5;a=`saturate(0%) brightness(${Math.floor(.5/Math.max(r,1e-5)*100)}%) contrast(1000000%)`}else if(t===Q5.SEPIA)a=`sepia(${r??1})`;else if(t===Q5.BRIGHTNESS)a=`brightness(${r??1})`;else if(t===Q5.SATURATION)a=`saturate(${r??1})`;else if(t===Q5.CONTRAST)a=`contrast(${r??1})`;else{if(t!==Q5.HUE_ROTATE)return void e._softFilter(t,r);a=`hue-rotate(${r}${0===e._angleMode?"rad":"deg"})`}if(e.ctx.filter=a,"none"==e.ctx.filter)throw new Error(`Invalid filter format: ${t}`);e.ctx.drawImage(e.canvas,0,0,e.canvas.width,e.canvas.height),e.ctx.filter="none",e._retint=!0},"image"==e._scope&&(e.resize=(t,r)=>{let a=e.canvas,n=new e._OffscreenCanvas(a.width,a.height);n.getContext("2d",{colorSpace:a.colorSpace}).drawImage(a,0,0),e._setImageSize(t,r),e.defaultWidth=a.width*e._defaultImageScale,e.defaultHeight=a.height*e._defaultImageScale,e.ctx.clearRect(0,0,a.width,a.height),e.ctx.drawImage(n,0,0,a.width,a.height),e._retint=!0}),e._getImageData=(t,r,a,n)=>e.ctx.getImageData(t,r,a,n,{colorSpace:e.canvas.colorSpace}),e.trim=()=>{let t=e._pixelDensity||1,r=e.canvas.width,a=e.canvas.height,n=e._getImageData(0,0,r,a).data,i=r,o=0,s=a,l=0,d=3;for(let e=0;eo&&(o=t),el&&(l=e)),d+=4;return s=Math.floor(s/t),l=Math.floor(l/t),i=Math.floor(i/t),o=Math.floor(o/t),e.get(i,s,o-i+1,l-s+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._retint=!0},e.inset=(t,r,a,n,i,o,s,l)=>{let d=e._pixelDensity||1;e.ctx.drawImage(e.canvas,t*d,r*d,a*d,n*d,i,o,s,l),e._retint=!0},e.copy=()=>e.get(),e.get=(t,r,a,n)=>{let i=e._pixelDensity||1;if(void 0!==t&&void 0===a){let a=e._getImageData(t*i,r*i,1,1).data;return[a[0],a[1],a[2],a[3]/255]}t=Math.floor(t||0)*i,r=Math.floor(r||0)*i;let o=a=a||e.width,s=n=n||e.height;a*=i,n*=i;let l=e.createImage(a,n);return l.ctx.drawImage(e.canvas,t,r,a,n,0,0,a,n),l._pixelDensity=i,l.width=o,l.height=s,l},e.set=(t,r,a)=>{if(t=Math.floor(t),r=Math.floor(r),e._retint=!0,a.canvas){let n=e._tint;return e._tint=null,e.image(a,t,r),void(e._tint=n)}e.pixels.length||e.loadPixels();let n=e._pixelDensity||1;for(let i=0;i{r=e._getImageData(0,0,e.canvas.width,e.canvas.height),t.pixels=r.data},e.updatePixels=()=>{null!=r&&(e.ctx.putImageData(r,0,0),e._retint=!0)},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,"image"!=e._scope&&(e.tint=function(t){e._tint=(t._q5Color?t:e.color(...arguments)).toString()},e.noTint=()=>e._tint=null)},Q5.renderers.q2d.soft_filters=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=(a,n)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let r=0;r=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t{for(let t=0;t{for(let t=0;t{let r=t-1;for(let a=0;a>8)/r,e[a+1]=255*(e[a+1]*t>>8)/r,e[a+2]=255*(e[a+2]*t>>8)/r},e._filters[Q5.DILATE]=(a,n)=>{n??=Math.max,r(),t.set(a);let[i,o]=[e.canvas.width,e.canvas.height];for(let e=0;e{e._filters[Q5.DILATE](t,Math.min)},e._filters[Q5.BLUR]=(a,n)=>{n=n||1,n=Math.floor(n*e._pixelDensity),r(),t.set(a);let i=2*n+1,o=function(e){let t=new Float32Array(e),r=.3*n+.8,a=r*r*2;for(let n=0;n{e._textAlign="left",e._textBaseline="alphabetic",e._textSize=12;let r="sans-serif",a=!1,n=15,i=3,o="normal",s=!1,l=0,d=[],c=!1,h=!1,u=0,p=12e3,f=e._textCache={};e.loadFont=(r,a)=>{t._preloadCount++;let n=r.split("/").pop().split(".")[0].replace(" ",""),i=new FontFace(n,`url(${r})`);return document.fonts.add(i),i.load().then((()=>{t._preloadCount--,a&&a(n)})),e.textFont(n),n},e.textFont=e=>{if(!e||e==r)return r;r=e,s=!0,l=-1},e.textSize=t=>{if(null==t||t==e._textSize)return e._textSize;e._da&&(t*=e._da),e._textSize=t,s=!0,l=-1,a||(n=1.25*t,i=n-t)},e.textStyle=e=>{if(!e||e==o)return o;o=e,s=!0,l=-1},e.textLeading=t=>null==t?n||1.25*e._textSize:(a=!0,t==n?n:(e._da&&(t*=e._da),n=t,i=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)};const _=()=>{e.ctx.font=`${o} ${e._textSize}px ${r}`,s=!1};e.textWidth=t=>(s&&_(),e.ctx.measureText(t).width),e.textAscent=t=>(s&&_(),e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(s&&_(),e.ctx.measureText(t).actualBoundingBoxDescent),e.textFill=e.fill,e.textStroke=e.stroke;e.textCache=(e,t)=>(t&&(p=t),void 0!==e&&(c=e),c),e.createTextImage=(t,r,a)=>(h=!0,img=e.text(t,0,0,r,a),h=!1,img);let g=[];e.text=(t,a,_,m,x)=>{if(void 0===t||!e._doFill&&!e._doStroke)return;t=t.toString(),e._da&&(a*=e._da,_*=e._da);let v,y,w,b,S=e.ctx;if(s&&(S.font=`${o} ${e._textSize}px ${r}`,s=!1),(c||h)&&(-1==l&&(()=>{let t=r+e._textSize+o+n,a=5381;for(let e=0;e>>0})(),v=f[t],v&&(v=v[l]),v)){if(v._fill==e._fill&&v._stroke==e._stroke&&v._strokeWeight==e._strokeWeight)return h?v:e.textImage(v,a,_);v.clear()}if(-1==t.indexOf("\n")?g[0]=t:g=t.split("\n"),t.length>m){let e=[];for(let t of g){let r=0;for(;r=t.length){e.push(t.slice(r));break}let n=t.lastIndexOf(" ",a);(-1===n||n=x)break;if(g.length=0,e._fillSet||(S.fillStyle=b),c||h){if(d.push(l),(f[t]??={})[l]=v,u++,u>p){let e=Math.ceil(u/2),t=d.splice(0,e);for(let e in f){e=f[e];for(let r of t)delete e[r]}u-=e}if(h)return v;e.textImage(v,a,_)}},e.textImage=(t,r,a)=>{"string"==typeof t&&(t=e.createTextImage(t));let n=e._imageMode;e._imageMode="corner";let i=e._textAlign;"center"==i?r-=t.canvas.hw:"right"==i&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?a-=t._leading:"middle"==o?a-=t._middle:"bottom"==o?a-=t._bottom:"top"==o&&(a-=t._top),e.image(t,r,a),e._imageMode=n},e.nf=(e,t,r)=>{let a=e<0,n=(e=Math.abs(e)).toFixed(r).split(".");n[0]=n[0].padStart(t,"0");let i=n.join(".");return a&&(i="-"+i),i}},Q5.modules.ai=e=>{e.askAI=(e="")=>{throw Q5.disableFriendlyErrors=!1,Error("Ask AI ✨ "+e)},e._askAI=async e=>{let t=e.message?.includes("Ask AI ✨"),r=e.stack?.split("\n");if(!e.stack||r.length<=1)return;let a=1,n="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(a=0,n="@");r[a].indexOf("q5")>=0;)a++;let i=r[a].split(n).at(-1);i.startsWith("blob:")&&(i=i.slice(5));let o=i.split(":"),s=parseInt(o.at(-2));t&&s++,o[3]=o[3].split(")")[0];let l=o.slice(0,2).join(":"),d=l.split("/").at(-1);try{let r=(await(await fetch(l)).text()).split("\n"),a=r[s-1].trim(),n="",i=1;for(;n.length<1600&&(s-i>=0&&(n=r[s-i].trim()+"\n"+n),s+i10?e.message.slice(10):"Whats+wrong+with+this+line%3F+short+answer")+(t?"":"%0A%0A"+encodeURIComponent(e.name+": "+e.message))+"%0A%0ALine%3A+"+encodeURIComponent(a)+"%0A%0AExcerpt+for+context%3A%0A%0A"+encodeURIComponent(n);if(console.warn("Error in "+d+" on line "+s+":\n\n"+a),console.warn("Ask AI ✨ "+o),t)return window.open(o,"_blank")}catch(e){}}},Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e._colorMode="rgb",e.SRGB="srgb",e.OKLCH="oklch",e.colorMode=(r,a)=>{e._colorMode=r;let n="srgb"==e.canvas.colorSpace||"srgb"==r;a??=n?"integer":"float",e._colorFormat="float"==a||1==a?1:255,"oklch"==r?t.Color=Q5.ColorOKLCH:(255==e._colorFormat?t.Color=n?Q5.ColorRGBA_8:Q5.ColorRGBA_P3_8:t.Color=n?Q5.ColorRGBA:Q5.ColorRGBA_P3,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],crimson:[220,20,60],cyan:[0,255,255],darkviolet:[148,0,211],gold:[255,215,0],green:[0,128,0],gray:[128,128,128],grey:[128,128,128],hotpink:[255,105,180],indigo:[75,0,130],khaki:[240,230,140],lightgreen:[144,238,144],lime:[0,255,0],magenta:[255,0,255],navy:[0,0,128],orange:[255,165,0],olive:[128,128,0],peachpuff:[255,218,185],pink:[255,192,203],purple:[128,0,128],red:[255,0,0],skyblue:[135,206,235],tan:[210,180,140],turquoise:[64,224,208],transparent:[0,0,0,0],white:[255,255,255],violet:[238,130,238],yellow:[255,255,0]},e.color=(t,r,a,n)=>{let i=e.Color;if(t._q5Color)return new i(...t.levels);if(null==r){if("string"==typeof t){if("#"==t[0])t.length<=5?(t.length>4&&(n=parseInt(t[4]+t[4],16)),a=parseInt(t[3]+t[3],16),r=parseInt(t[2]+t[2],16),t=parseInt(t[1]+t[1],16)):(t.length>7&&(n=parseInt(t.slice(7,9),16)),a=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])return console.error("q5 can't parse color: "+t+"\nOnly numeric input, hex, and common named colors are supported."),new i(0,0,0);[t,r,a,n]=e._namedColors[t]}1==e._colorFormat&&(t/=255,r&&(r/=255),a&&(a/=255),n&&(n/=255))}Array.isArray(t)&&([t,r,a,n]=t)}return null==a?e._colorMode==Q5.OKLCH?new i(t,0,0,r):new i(t,t,t,r):new i(t,r,a,n)},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=e=>e.l?e.l:100*(.2126*e.r+.7152*e.g+.0722*e.b)/255,e.hue=t=>{if(t.h)return t.h;let r=t.r,a=t.g,n=t.b;255==e._colorFormat&&(r/=255,a/=255,n/=255);let i,o=Math.max(r,a,n),s=Math.min(r,a,n);return i=o==s?0:o==r?60*(a-n)/(o-s):o==a?60*(n-r)/(o-s)+120:60*(r-a)/(o-s)+240,i<0&&(i+=360),i},e.lerpColor=(t,r,a)=>{if(a=Math.max(0,Math.min(1,a)),"rgb"==e._colorMode)return new e.Color(e.lerp(t.r,r.r,a),e.lerp(t.g,r.g,a),e.lerp(t.b,r.b,a),e.lerp(t.a,r.a,a));{let n=r.h-t.h;n>180&&(n-=360),n<-180&&(n+=360);let i=t.h+a*n;return i<0&&(i+=360),i>360&&(i-=360),new e.Color(e.lerp(t.l,r.l,a),e.lerp(t.c,r.c,a),i,e.lerp(t.a,r.a,a))}}},Q5.Color=class{constructor(){this._q5Color=!0}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,r,a){super(),this.l=e,this.c=t,this.h=r,this.a=a??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}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorRGBA=class extends Q5.Color{constructor(e,t,r,a){super(),this.r=e,this.g=t,this.b=r,this.a=a??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}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorRGBA_P3=class extends Q5.ColorRGBA{toString(){return`color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`}},Q5.ColorRGBA_8=class extends Q5.ColorRGBA{constructor(e,t,r,a){super(e,t,r,a??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.ColorRGBA_P3_8=class extends Q5.ColorRGBA{constructor(e,t,r,a){super(e,t,r,a??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),a=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${r} / ${a})`,this._edited=!1}return this._css}},Q5.modules.display=e=>{if(!e.canvas||"graphics"==e._scope)return;let t=e.canvas;e.CENTERED="centered",e.FULLSCREEN="fullscreen",e.MAXED="maxed",e.PIXELATED="pixelated",0!=Q5._instanceCount||Q5._server||document.head.insertAdjacentHTML("beforeend",""),e._adjustDisplay=()=>{let r=t.style,a=t.parentElement;r&&a&&t.displayMode&&("pixelated"==t.renderQuality&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.defaultImageScale(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),"default"==t.displayMode||"normal"==t.displayMode?(a.classList.remove("q5-centered","q5-maxed","q5-fullscreen"),r.width=t.w*t.displayScale+"px",r.height=t.h*t.displayScale+"px"):(a.classList.add("q5-"+t.displayMode),a=a.getBoundingClientRect(),t.w/t.h>a.width/a.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",a="smooth",n=1)=>{"string"==typeof n&&(n=parseFloat(n.slice(1))),"center"==r&&(r="centered"),Object.assign(t,{displayMode:r,renderQuality:a,displayScale:n}),e._adjustDisplay()},e.fullscreen=e=>{if(void 0===e)return document.fullscreenElement;e?document.body.requestFullscreen():document.body.exitFullscreen()}},Q5.modules.input=(e,t)=>{if("graphics"==e._scope)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.mouseButton="",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={},a=[Q5.LEFT,Q5.CENTER,Q5.RIGHT],n=e.canvas;function i(t){const r=e.canvas.getBoundingClientRect(),a=e.canvas.scrollWidth/e.width||1,n=e.canvas.scrollHeight/e.height||1;return{x:(t.clientX-r.left)/a,y:(t.clientY-r.top)/n,id:t.identifier}}if(e._startAudio=()=>{Q5.aud&&"suspended"!=Q5.aud?.state||e.userStartAudio()},e._updateMouse=r=>{if(!r.changedTouches){if(n){let a=n.getBoundingClientRect(),i=n.scrollWidth/e.width||1,o=n.scrollHeight/e.height||1;t.mouseX=(r.clientX-a.left)/i,t.mouseY=(r.clientY-a.top)/o,"webgpu"==n.renderer&&(t.mouseX-=n.hw,t.mouseY-=n.hh)}else t.mouseX=r.clientX,t.mouseY=r.clientY;t.moveX=r.movementX,t.moveY=r.movementY}},e._onmousedown=r=>{e._startAudio(),e._updateMouse(r),t.mouseIsPressed=!0,t.mouseButton=a[r.button],e.mousePressed(r)},e._onmousemove=t=>{e._updateMouse(t),e.mouseIsPressed?e.mouseDragged(t):e.mouseMoved(t)},e._onmouseup=r=>{e._updateMouse(r),t.mouseIsPressed=!1,e.mouseReleased(r)},e._onclick=r=>{e._updateMouse(r),t.mouseIsPressed=!0,e.mouseClicked(r),t.mouseIsPressed=!1},e._onwheel=t=>{e._updateMouse(t),t.delta=t.deltaY,0==e.mouseWheel(t)&&t.preventDefault()},e.cursor=(t,r,a)=>{let n="";t.includes(".")&&(t=`url("${t}")`,n=", auto"),void 0!==r&&(t+=" "+r+" "+a),e.canvas.style.cursor=t+n},e.noCursor=()=>{e.canvas.style.cursor="none"},window&&(e.requestPointerLock=document.body?.requestPointerLock,e.exitPointerLock=document.exitPointerLock),e._onkeydown=a=>{a.repeat||(e._startAudio(),t.keyIsPressed=!0,t.key=a.key,t.keyCode=a.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!0,e.keyPressed(a),1==a.key.length&&e.keyTyped(a))},e._onkeyup=a=>{t.keyIsPressed=!1,t.key=a.key,t.keyCode=a.keyCode,r[e.keyCode]=r[e.key.toLowerCase()]=!1,e.keyReleased(a)},e.keyIsDown=e=>!!r["string"==typeof e?e.toLowerCase():e],e._ontouchstart=r=>{e._startAudio(),t.touches=[...r.touches].map(i),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,t.mouseIsPressed=!0,t.mouseButton=e.LEFT,e.mousePressed(r)||r.preventDefault()),e.touchStarted(r)||r.preventDefault()},e._ontouchmove=r=>{t.touches=[...r.touches].map(i),e._isTouchAware||(t.mouseX=e.touches[0].x,t.mouseY=e.touches[0].y,e.mouseDragged(r)||r.preventDefault()),e.touchMoved(r)||r.preventDefault()},e._ontouchend=r=>{t.touches=[...r.touches].map(i),e._isTouchAware||e.touches.length||(t.mouseIsPressed=!1,e.mouseReleased(r)||r.preventDefault()),e.touchEnded(r)||r.preventDefault()},window){let t=window.addEventListener;t("keydown",(t=>e._onkeydown(t)),!1),t("keyup",(t=>e._onkeyup(t)),!1),t("mousedown",(t=>e._onmousedown(t))),t("mousemove",(t=>e._onmousemove(t)),!1),t("mouseup",(t=>e._onmouseup(t))),t("wheel",(t=>e._onwheel(t))),t("click",(t=>e._onclick(t))),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.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.round=Math.round,e.pow=Math.pow,e.sqrt=Math.sqrt,e.SHR3=1,e.LCG=2;let r=e._angleMode=0;e.angleMode=t=>(r=e._angleMode=0==t||"radians"==t?0:1,r?"degrees":"radians");let a=e._DEGTORAD=Math.PI/180,n=e._RADTODEG=180/Math.PI;function i(){let e,t,r=4294967295;return{setSeed(a){e=t=(a??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,a,n,i)=>{let o=a+1*(e-t)/(r-t)*(n-a);return i?ae*(1-r)+t*r,e.constrain=(e,t,r)=>Math.min(Math.max(e,t),r),e.norm=(t,r,a)=>e.map(t,r,a,0,1),e.sq=e=>e*e,e.fract=e=>e-Math.floor(e),e.sin=e=>Math.sin(r?e*a:e),e.cos=e=>Math.cos(r?e*a:e),e.tan=e=>Math.tan(r?e*a:e),e.asin=e=>{let t=Math.asin(e);return r?t*n:t},e.acos=e=>{let t=Math.acos(e);return r?t*n:t},e.atan=e=>{let t=Math.atan(e);return r?t*n:t},e.atan2=(e,t)=>{let a=Math.atan2(e,t);return r?a*n:a};let o=i();o.setSeed(),e.randomSeed=e=>o.setSeed(e),e.random=(e,t)=>void 0===e?o.rand():"number"==typeof e?void 0!==t?o.rand()*(t-e)+e:o.rand()*e:e[Math.trunc(e.length*o.rand())],e.randomGenerator=t=>{t==e.LCG?o=function(){const e=4294967296;let t,r;return{setSeed(a){r=t=(a??Math.random()*e)>>>0},getSeed:()=>t,rand:()=>(r=(1664525*r+1013904223)%e,r/e)}}():t==e.SHR3&&(o=i()),o.setSeed()};var s=new function(){var e,t,r,a=new Array(128),n=new Array(256),i=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,n,o,l,d=3.44262;;){if(t=r*i[e],0==e){do{o=h(),l=h(),t=.2904764*-Math.log(o),n=-Math.log(l)}while(n+n0?d+t:-d-t}if(s[e]+h()*(s[e-1]-s[e]){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])(r=c(),e=127&r,Math.abs(r)(t=c()>>>0){var e,t,r=2147483648,o=4294967296,c=3.442619855899,h=c,u=.00991256303526217,p=7.697117470131487,f=p,_=.003949659822581572;for(e=u/Math.exp(-.5*c*c),a[0]=Math.floor(c/e*r),a[1]=0,i[0]=e/r,i[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))),a[t+1]=Math.floor(c/h*r),h=c,s[t]=Math.exp(-.5*c*c),i[t]=c/r;for(e=_/Math.exp(-p),n[0]=Math.floor(p/e*o),n[1]=0,l[0]=e/o,l[255]=p/o,d[0]=1,d[255]=Math.exp(-p),t=254;t>=1;t--)p=-Math.log(_/p+Math.exp(-p)),n[t+1]=Math.floor(p/f*o),f=p,d[t]=Math.exp(-p),l[t]=p/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.Noise=Q5.PerlinNoise,e.noiseMode=e=>{t.Noise=Q5[e[0].toUpperCase()+e.slice(1)+"Noise"],l=null},e.noiseSeed=t=>{l=new e.Noise(t)},e.noise=(t=0,r=0,a=0)=>(l??=new e.Noise,l.noise(t,r,a)),e.noiseDetail=(t,r)=>{l??=new e.Noise,t>0&&(l.octaves=t),r>0&&(l.falloff=r)}},Q5.Noise=class{},Q5.PerlinNoise=class extends Q5.Noise{constructor(e){super(),this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.octaves=1,this.falloff=.5,this.p=null==e?Array.from({length:256},(()=>Math.floor(256*Math.random()))):this.seedPermutation(e),this.p=this.p.concat(this.p)}seedPermutation(e){let t,r,a=[];for(let e=0;e<256;e++)a[e]=e;for(let n=255;n>0;n--)t=(e=16807*e%2147483647)%(n+1),r=a[n],a[n]=a[t],a[t]=r;return a}dot(e,t,r,a){return e[0]*t+e[1]*r+e[2]*a}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 a=this,n=0,i=1,o=1,s=0;for(let l=0;l{e.Sound=Q5.Sound;let r=[];e.loadSound=(e,a)=>{t._preloadCount++;let n=new Q5.Sound(e,a);return n.crossOrigin="Anonymous",n.addEventListener("canplaythrough",(()=>{n.loaded||(t._preloadCount--,n.loaded=!0,Q5.aud&&n.init(),a&&a(n))})),r.push(n),n},e.getAudioContext=()=>Q5.aud,e.userStartAudio=()=>{if(window.AudioContext){if(!Q5.aud){Q5.aud=new window.AudioContext;for(let e of r)e.init()}return Q5.aud.resume()}}},window.Audio&&(Q5.Sound??=class extends Audio{init(){let e=this;e.panner=Q5.aud.createStereoPanner(),e.source=Q5.aud.createMediaElementSource(e),e.source.connect(e.panner),e.panner.connect(Q5.aud.destination);let t=e.pan;Object.defineProperty(e,"pan",{get:()=>e.panner.pan.value,set:t=>e.panner.pan.value=t}),t&&(e.pan=t)}setVolume(e){this.volume=e}setLoop(e){this.loop=e}setPan(e){this.pan=e}isLoaded(){return this.loaded}isPlaying(){return!this.paused}}),Q5.modules.util=(e,t)=>{e._loadFile=(r,a,n)=>{t._preloadCount++;let i={};return fetch(r).then((e=>"json"==n?e.json():e.text())).then((r=>{t._preloadCount--,"csv"==n&&(r=e.CSV.parse(r)),Object.assign(i,r),a&&a(r)})),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.CSV={},e.CSV.parse=(e,t=",",r="\n")=>{let a=[],n=e.split(r),i=n[0].split(t);for(let e=1;er[e]=JSON.parse(o[t]))),a.push(r)}return a},"object"==typeof localStorage&&(e.storeItem=localStorage.setItem,e.getItem=localStorage.getItem,e.removeItem=localStorage.removeItem,e.clearStorage=localStorage.clear),e.year=()=>(new Date).getFullYear(),e.day=()=>(new Date).getDay(),e.hour=()=>(new Date).getHours(),e.minute=()=>(new Date).getMinutes(),e.second=()=>(new Date).getSeconds()},Q5.modules.vector=e=>{e.createVector=(t,r,a)=>new Q5.Vector(t,r,a,e)},Q5.Vector=class{constructor(e,t,r,a){this.x=e||0,this.y=t||0,this.z=r||0,this._$=a||window,this._cn=null,this._cnsq=null}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}}_calcNorm(){this._cnsq=this.x*this.x+this.y*this.y+this.z*this.z,this._cn=Math.sqrt(this._cnsq)}add(){let e=this._arg2v(...arguments);return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}rem(){let e=this._arg2v(...arguments);return this.x%=e.x,this.y%=e.y,this.z%=e.z,this}sub(){let e=this._arg2v(...arguments);return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}mult(){let e=this._arg2v(...arguments);return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}div(){let e=this._arg2v(...arguments);return e.x?this.x/=e.x:this.x=0,e.y?this.y/=e.y:this.y=0,e.z?this.z/=e.z:this.z=0,this}mag(){return this._calcNorm(),this._cn}magSq(){return this._calcNorm(),this._cnsq}dot(){let e=this._arg2v(...arguments);return this.x*e.x+this.y*e.y+this.z*e.z}dist(){let e=this._arg2v(...arguments),t=this.x-e.x,r=this.y-e.y,a=this.z-e.z;return Math.sqrt(t*t+r*r+a*a)}cross(){let e=this._arg2v(...arguments),t=this.y*e.z-this.z*e.y,r=this.z*e.x-this.x*e.z,a=this.x*e.y-this.y*e.x;return this.x=t,this.y=r,this.z=a,this}normalize(){this._calcNorm();let e=this._cn;return 0!=e&&(this.x/=e,this.y/=e,this.z/=e),this._cn=1,this._cnsq=1,this}limit(e){this._calcNorm();let t=this._cn;if(t>e){let r=e/t;this.x*=r,this.y*=r,this.z*=r,this._cn=e,this._cnsq=e*e}return this}setMag(e){this._calcNorm();let t=e/this._cn;return this.x*=t,this.y*=t,this.z*=t,this._cn=e,this._cnsq=e*e,this}heading(){return this._$.atan2(this.y,this.x)}setHeading(e){let t=this.mag();return this.x=t*this._$.cos(e),this.y=t*this._$.sin(e),this}rotate(e){let t=this._$.cos(e),r=this._$.sin(e),a=this.x*t-this.y*r,n=this.x*r+this.y*t;return this.x=a,this.y=n,this}angleBetween(){let e=this._arg2v(...arguments),t=Q5.Vector.cross(this,e);return this._$.atan2(t.mag(),this.dot(e))*Math.sign(t.z||1)}lerp(){let e=[...arguments],t=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 a=this.mag(),n=r.mag();if(0==a||0==n)return this.mult(1-t).add(r.mult(t));let i=Q5.Vector.cross(this,r),o=i.mag(),s=Math.atan2(o,this.dot(r));if(o>0)i.div(o);else{if(se.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.heading=e=>this._$.atan2(e.y,e.x),Q5.Vector.magSq=e=>e.x*e.x+e.y*e.y+e.z*e.z,Q5.Vector.mag=e=>Math.sqrt(Q5.Vector.magSq(e)),Q5.Vector.mult=(e,t)=>e.copy().mult(t),Q5.Vector.normalize=e=>e.copy().normalize(),Q5.Vector.rem=(e,t)=>e.copy().rem(t),Q5.Vector.sub=(e,t)=>e.copy().sub(t);for(let e of["fromAngle","fromAngles","random2D","random3D"])Q5.Vector[e]=(t,r,a)=>(new Q5.Vector)[e](t,r,a);Q5.renderers.webgpu={},Q5.renderers.webgpu.canvas=(e,t)=>{let r=e.canvas;r.width=e.width=500,r.height=e.height=500,e.colorMode&&e.colorMode("rgb",1);let a,n,i,o=1,s=8;e._pipelineConfigs=[],e._pipelines=[];let l=e.drawStack=[],d=e.colorStack=new Float32Array(1e6);d.set([0,0,0,1,1,1,1,1]),e._transformLayout=Q5.device.createBindGroupLayout({label:"transformLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",hasDynamicOffset:!1}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage",hasDynamicOffset:!1}}]}),i=Q5.device.createBindGroupLayout({label:"colorsLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"read-only-storage",hasDynamicOffset:!1}}]}),e.bindGroupLayouts=[e._transformLayout,i];let c=Q5.device.createBuffer({size:8,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),h=()=>{n=Q5.device.createTexture({size:[e.canvas.width,e.canvas.height],sampleCount:4,format:"bgra8unorm",usage:GPUTextureUsage.RENDER_ATTACHMENT}).createView()};e._createCanvas=(a,n,i)=>(t.ctx=t.drawingContext=r.getContext("webgpu"),i.format??=navigator.gpu.getPreferredCanvasFormat(),i.device??=Q5.device,i.alpha&&(i.alphaMode="premultiplied"),e.ctx.configure(i),Q5.device.queue.writeBuffer(c,0,new Float32Array([e.canvas.hw,e.canvas.hh])),h(),r),e._resizeCanvas=(t,r)=>{e._setCanvasSize(t,r),h()},e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._setCanvasSize(r.w,r.h),h(),t):e._pixelDensity;let u=(t,r,a,n=1)=>{"string"==typeof t?t=e.color(t):null==a&&(n=r??1,r=a=t),t._q5Color&&(n=t.a,a=t.b,r=t.g,t=t.r);let i=d,l=s;i[l++]=t,i[l++]=r,i[l++]=a,i[l++]=n,s=l,o++};e._stroke=0,e._fill=1,e._doFill=e._doStroke=!0,e.fill=(t,r,a,n)=>{u(t,r,a,n),e._doFill=e._fillSet=!0,e._fill=o},e.stroke=(t,r,a,n)=>{u(t,r,a,n),e._doStroke=e._strokeSet=!0,e._stroke=o},e.noFill=()=>e._doFill=!1,e.noStroke=()=>e._doStroke=!1,e._strokeWeight=1,e.strokeWeight=t=>e._strokeWeight=Math.abs(t),e.resetMatrix=()=>{e._matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e._transformIndex=0},e.resetMatrix(),e._matrixDirty=!1;let p=[e._matrix.slice()];e._transformIndexStack=[],e.translate=(t,r,a)=>{(t||r||a)&&(e._matrix[12]+=t,e._matrix[13]-=r,e._matrix[14]+=a||0,e._matrixDirty=!0)},e.rotate=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.cos(t),a=Math.sin(t),n=e._matrix,i=n[0],o=n[1],s=n[4],l=n[5];1!=i||o||s||1!=l?(n[0]=i*r+o*a,n[1]=o*r-i*a,n[4]=s*r+l*a,n[5]=l*r-s*a):(n[0]=r,n[1]=-a,n[4]=a,n[5]=r),e._matrixDirty=!0},e.scale=(t=1,r,a=1)=>{r??=t;let n=e._matrix;n[0]*=t,n[1]*=t,n[2]*=t,n[3]*=t,n[4]*=r,n[5]*=r,n[6]*=r,n[7]*=r,n[8]*=a,n[9]*=a,n[10]*=a,n[11]*=a,e._matrixDirty=!0},e.shearX=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),a=e._matrix[0],n=e._matrix[1],i=e._matrix[4],o=e._matrix[5];e._matrix[0]=a+i*r,e._matrix[1]=n+o*r,e._matrixDirty=!0},e.shearY=t=>{if(!t)return;e._angleMode&&(t*=e._DEGTORAD);let r=Math.tan(t),a=e._matrix[0],n=e._matrix[1],i=e._matrix[4],o=e._matrix[5];e._matrix[4]=i+a*r,e._matrix[5]=o+n*r,e._matrixDirty=!0},e.applyMatrix=(...t)=>{let r;if(r=1==t.length?t[0]:t,9==r.length)r=[r[0],r[1],0,r[2],r[3],r[4],0,r[5],0,0,1,0,r[6],r[7],0,r[8]];else if(16!=r.length)throw new Error("Matrix must be a 3x3 or 4x4 array.");e._matrix=r.slice(),e._matrixDirty=!0},e._saveMatrix=()=>{p.push(e._matrix.slice()),e._transformIndex=p.length-1,e._matrixDirty=!1},e.pushMatrix=()=>{e._matrixDirty&&e._saveMatrix(),e._transformIndexStack.push(e._transformIndex)},e.popMatrix=()=>{if(!e._transformIndexStack.length)return console.warn("Matrix index stack is empty!");let t=e._transformIndexStack.pop();e._matrix=p[t].slice(),e._transformIndex=t,e._matrixDirty=!1},e.push=()=>{e.pushMatrix(),e.pushStyles()},e.pop=()=>{e.popMatrix(),e.popStyles()},e._calcBox=(e,t,r,a,n)=>{let i,o,s,l,d=r/2,c=a/2;return n&&"corner"!=n?"center"==n?(i=e-d,o=e+d,s=-(t-c),l=-(t+c)):(i=e,o=r,s=-t,l=-a):(i=e,o=e+r,s=-t,l=-(t+a)),[i,o,s,l]};let f=["zero","one","src-alpha","one-minus-src-alpha","dst","dst-alpha","one-minus-dst-alpha","one-minus-src"],_=["add","subtract","reverse-subtract","min","max"];const g={normal:[2,3,0,2,3,0],additive:[1,1,0,1,1,0]};e.blendConfigs={};for(const[t,r]of Object.entries(g))e.blendConfigs[t]={color:{srcFactor:f[r[0]],dstFactor:f[r[1]],operation:_[r[2]]},alpha:{srcFactor:f[r[3]],dstFactor:f[r[4]],operation:_[r[5]]}};e._blendMode="normal",e.blendMode=t=>{if(t!=e._blendMode){"source-over"==t&&(t="normal"),"lighter"==t&&(t="additive"),t=t.toLowerCase().replace(/[ -]/g,"_"),e._blendMode=t;for(let r=0;r{},e._beginRender=()=>{e.encoder=Q5.device.createCommandEncoder(),a=t.pass=e.encoder.beginRenderPass({label:"q5-webgpu",colorAttachments:[{view:n,resolveTarget:e.ctx.getCurrentTexture().createView(),loadOp:"clear",storeOp:"store",clearValue:[0,0,0,0]}]})},e._render=()=>{if(p.length>1||!e._transformBindGroup){let t=Q5.device.createBuffer({size:64*p.length,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(p.flat()),t.unmap(),e._transformBindGroup=Q5.device.createBindGroup({layout:e._transformLayout,entries:[{binding:0,resource:{buffer:c}},{binding:1,resource:{buffer:t}}]})}a.setBindGroup(0,e._transformBindGroup);let t=Q5.device.createBuffer({size:4*s,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(d.slice(0,s)),t.unmap(),e._colorsBindGroup=Q5.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:t}}]}),e.pass.setBindGroup(1,e._colorsBindGroup);for(let t of e._hooks.preRender)t();let r=0,n=0,o=0,h=-1;for(let t=0;t{a.end();let r=e.encoder.finish();Q5.device.queue.submit([r]),t.pass=e.encoder=null,e.drawStack.length=0,o=1,s=8,rotation=0,p.length=1,e._transformIndexStack.length=0}},Q5.initWebGPU=async()=>{if(!navigator.gpu)return console.warn("q5 WebGPU not supported on this browser!"),!1;if(!Q5.device){let e=await navigator.gpu.requestAdapter();if(!e)throw new Error("No appropriate GPUAdapter found.");Q5.device=await e.requestDevice()}return!0},Q5.webgpu=async function(e,t){return e&&"global"!=e||(Q5._hasGlobal=!0),await Q5.initWebGPU()?new Q5(e,t,"webgpu"):new Q5(e,t,"webgpu-fallback")},Q5.renderers.webgpu.drawing=(e,t)=>{let r=e.canvas,a=e.drawStack,n=new Float32Array(1e7),i=0,o=Q5.device.createShaderModule({label:"drawingVertexShader",code:"\nstruct VertexInput {\n\t@location(0) pos: vec2f,\n\t@location(1) colorIndex: f32,\n\t@location(2) transformIndex: f32\n}\nstruct VertexOutput {\n\t@builtin(position) position: vec4f,\n\t@location(0) color: vec4f\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@group(1) @binding(0) var colors : array;\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n\tvar vert = vec4f(input.pos, 0.0, 1.0);\n\tvert = transforms[i32(input.transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output: VertexOutput;\n\toutput.position = vert;\n\toutput.color = colors[i32(input.colorIndex)];\n\treturn output;\n}\n"}),s=Q5.device.createShaderModule({label:"drawingFragmentShader",code:"\n@fragment\nfn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {\n\treturn color;\n}\n"}),l=Q5.device.createPipelineLayout({label:"drawingPipelineLayout",bindGroupLayouts:e.bindGroupLayouts});e._pipelineConfigs[0]={label:"drawingPipeline",layout:l,vertex:{module:o,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:s,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[0]=Q5.device.createRenderPipeline(e._pipelineConfigs[0]);const d=(e,t,r,a)=>{let o=n,s=i;o[s++]=e,o[s++]=t,o[s++]=r,o[s++]=a,i=s},c=(e,t,r,o,s,l,d,c,h,u)=>{let p=n,f=i;p[f++]=e,p[f++]=t,p[f++]=h,p[f++]=u,p[f++]=r,p[f++]=o,p[f++]=h,p[f++]=u,p[f++]=d,p[f++]=c,p[f++]=h,p[f++]=u,p[f++]=s,p[f++]=l,p[f++]=h,p[f++]=u,i=f,a.push(0,4)},h=(t,r,o,s,l,d,c)=>{r=-r;let h=0,u=e.TAU/l,p=n,f=i;for(let e=0;e<=l;e++){p[f++]=t,p[f++]=r,p[f++]=d,p[f++]=c;let e=t+o*Math.cos(h),a=r+s*Math.sin(h);p[f++]=e,p[f++]=a,p[f++]=d,p[f++]=c,h+=u}p[f++]=t,p[f++]=r,p[f++]=d,p[f++]=c,p[f++]=t+o,p[f++]=r,p[f++]=d,p[f++]=c,i=f,a.push(0,2*(l+1)+2)};e.rectMode=t=>e._rectMode=t,e.rect=(t,r,a,n)=>{let i,o,[s,l,d,h]=e._calcBox(t,r,a,n,e._rectMode);if(e._matrixDirty&&e._saveMatrix(),o=e._transformIndex,e._doFill&&(i=e._fill,c(s,d,l,d,l,h,s,h,i,o)),e._doStroke){i=e._stroke;let t=e._strokeWeight/2,r=s-t,a=l+t,n=d+t,u=h-t,p=s+t,f=l-t,_=d-t,g=h+t;c(r,_,a,_,a,n,r,n,i,o),c(r,u,a,u,a,g,r,g,i,o),n=d-t,u=h+t,c(r,n,p,n,p,u,r,u,i,o),c(f,n,a,n,a,u,f,u,i,o)}},e.square=(t,r,a)=>e.rect(t,r,a,a);const u=e=>e<4?6:e<6?8:e<10?10:e<16?12:e<20?14:e<22?16:e<24?18:e<28?20:e<34?22:e<42?24:e<48?26:e<56?28:e<64?30:e<72?32:e<84?34:e<96?36:e<98?38:e<113?40:e<149?44:e<199?48:e<261?52:e<353?56:e<461?60:e<585?64:e<1200?70:e<1800?80:e<2400?90:100;let p;e.ellipseMode=t=>e._ellipseMode=t,e.ellipse=(t,r,o,s)=>{let l=u(Math.max(o,s)),d=Math.max(o,1)/2,c=o==s?d:Math.max(s,1)/2;e._matrixDirty&&e._saveMatrix();let p=e._transformIndex;if(e._doFill&&h(t,r,d,c,l,e._fill,p),e._doStroke){let o=e._strokeWeight/2;((t,r,o,s,l,d,c,h,u)=>{r=-r;let p=e.TAU/c,f=0,_=n,g=i;for(let e=0;e<=c;e++){let e=t+o*Math.cos(f),a=r+s*Math.sin(f),n=t+l*Math.cos(f),i=r+d*Math.sin(f);_[g++]=e,_[g++]=a,_[g++]=h,_[g++]=u,_[g++]=n,_[g++]=i,_[g++]=h,_[g++]=u,f+=p}i=g,a.push(0,2*(c+1))})(t,r,d+o,c+o,d-o,c-o,l,e._stroke,p)}},e.circle=(t,r,a)=>e.ellipse(t,r,a,a),e.point=(t,r)=>{e._matrixDirty&&e._saveMatrix();let a=e._transformIndex,n=e._stroke,i=e._strokeWeight;if(i<2){let[o,s,l,d]=e._calcBox(t,r,i,i,"corner");c(o,l,s,l,s,d,o,d,n,a)}else{let e=u(i);i/=2,h(t,r,i,i,e,n,a)}},e.stokeJoin=t=>{e.log("q5 WebGPU doesn't support changing stroke join style.")},e.line=(t,r,a,n)=>{e._matrixDirty&&e._saveMatrix();let i=e._transformIndex,o=e._stroke,s=e._strokeWeight,l=s/2,d=a-t,p=n-r,f=Math.hypot(d,p),_=-p/f*l,g=d/f*l;if(c(t+_,-r-g,t-_,-r+g,a-_,-n+g,a+_,-n-g,o,i),s>2){let e=u(s);h(t,r,l,l,e,o,i),h(a,n,l,l,e,o,i)}};let f=[],_=[];e.beginShape=()=>{p=0,f=[],_=[]},e.vertex=(t,r)=>{e._matrixDirty&&e._saveMatrix(),f.push(t,-r,e._fill,e._transformIndex),p++},e.curveVertex=(t,r)=>{e._matrixDirty&&e._saveMatrix(),_.push({x:t,y:-r})},e.endShape=t=>{if(_.length>0){let t=[..._];if(t.length<4)for(;t.length<4;)t.unshift(t[0]),t.push(t[t.length-1]);for(let r=0;r{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.endShape(!0)},e.quad=(t,r,a,n,i,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(a,n),e.vertex(i,o),e.vertex(s,l),e.endShape(!0)},e.background=(t,a,n,i)=>{if(e.push(),e.resetMatrix(),e._doStroke=!1,t.src){let a=e._imageMode;e._imageMode="corner",e.image(t,-r.hw,-r.hh,r.w,r.h),e._imageMode=a}else{let o=e._rectMode;e._rectMode="corner",e.fill(t,a,n,i),e.rect(-r.hw,-r.hh,r.w,r.h),e._rectMode=o}e.pop(),e._fillSet||(e._fill=1)},e._hooks.preRender.push((()=>{e.pass.setPipeline(e._pipelines[0]);let t=Q5.device.createBuffer({size:4*i,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(n.slice(0,i)),t.unmap(),e.pass.setVertexBuffer(0,t)})),e._hooks.postRender.push((()=>{i=0}))},Q5.renderers.webgpu.image=(e,t)=>{e._textureBindGroups=[];let r=[],a=Q5.device.createShaderModule({label:"imageVertexShader",code:"\nstruct VertexOutput {\n\t@builtin(position) position: vec4f,\n\t@location(0) texCoord: vec2f\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@vertex\nfn vertexMain(@location(0) pos: vec2f, @location(1) texCoord: vec2f, @location(2) transformIndex: f32) -> VertexOutput {\n\tvar vert = vec4f(pos, 0.0, 1.0);\n\tvert = transforms[i32(transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output: VertexOutput;\n\toutput.position = vert;\n\toutput.texCoord = texCoord;\n\treturn output;\n}\n\t"}),n=Q5.device.createShaderModule({label:"imageFragmentShader",code:"\n@group(2) @binding(0) var samp: sampler;\n@group(2) @binding(1) var texture: texture_2d;\n\n@fragment\nfn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {\n\t// Sample the texture using the interpolated texture coordinate\n\treturn textureSample(texture, samp, texCoord);\n}\n\t"}),i=Q5.device.createBindGroupLayout({label:"textureLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{viewDimension:"2d",sampleType:"float"}}]});const o=Q5.device.createPipelineLayout({label:"imagePipelineLayout",bindGroupLayouts:[...e.bindGroupLayouts,i]});let s;e._pipelineConfigs[1]={label:"imagePipeline",layout:o,vertex:{module:a,entryPoint:"vertexMain",buffers:[{arrayStride:0,attributes:[]},{arrayStride:20,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"},{shaderLocation:2,offset:16,format:"float32"}]}]},fragment:{module:n,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[1]=Q5.device.createRenderPipeline(e._pipelineConfigs[1]);let l=e=>{s=Q5.device.createSampler({magFilter:e,minFilter:e})};l("linear"),e.smooth=()=>{l("linear")},e.noSmooth=()=>{l("nearest")};e._textures=[];let d=0;e._createTexture=t=>{t.canvas&&(t=t.canvas);let r=[t.width,t.height,1],a=Q5.device.createTexture({size:r,format:"bgra8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:t},{texture:a,colorSpace:e.canvas.colorSpace},r),e._textures[d]=a,t.textureIndex=d;const n=Q5.device.createBindGroup({layout:i,entries:[{binding:0,resource:s},{binding:1,resource:a.createView()}]});e._textureBindGroups[d]=n,d=(d+1)%12e3,e._textures[d]&&(e._textures[d].destroy(),delete e._textures[d],delete e._textureBindGroups[d])},e.loadImage=(r,a)=>{t._preloadCount++;const n=new Image;return n.crossOrigin="Anonymous",n.onload=()=>{n.defaultWidth=n.width*e._defaultImageScale,n.defaultHeight=n.height*e._defaultImageScale,n.pixelDensity=1,e._createTexture(n),t._preloadCount--,a&&a(n)},n.src=r,n},e.imageMode=t=>e._imageMode=t,e.image=(t,a,n,i,o,s=0,l=0,d,c)=>{if(t.canvas&&(t=t.canvas),null==t.textureIndex)return;e._matrixDirty&&e._saveMatrix();let h=e._transformIndex,u=t.width,p=t.height;i??=t.defaultWidth,o??=t.defaultHeight,d??=u,c??=p;let f=t.pixelDensity||1;i*=f,o*=f;let[_,g,m,x]=e._calcBox(a,n,i,o,e._imageMode),v=s/u,y=l/p,w=(s+d)/u,b=(l+c)/p;r.push(_,m,v,y,h,g,m,w,y,h,_,x,v,b,h,g,x,w,b,h),e.drawStack.push(1,t.textureIndex)},e._hooks.preRender.push((()=>{if(!e._textureBindGroups.length)return;e.pass.setPipeline(e._pipelines[1]);const t=Q5.device.createBuffer({size:4*r.length,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(t.getMappedRange()).set(r),t.unmap(),e.pass.setVertexBuffer(1,t)})),e._hooks.postRender.push((()=>{r.length=0}))},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.renderers.webgpu.text=(e,t)=>{let r=Q5.device.createShaderModule({label:"MSDF text shader",code:"\n// Positions for simple quad geometry\nconst pos = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));\n\nstruct VertexInput {\n\t@builtin(vertex_index) vertex : u32,\n\t@builtin(instance_index) instance : u32\n}\nstruct VertexOutput {\n\t@builtin(position) position : vec4f,\n\t@location(0) texCoord : vec2f,\n\t@location(1) fillColor : vec4f\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\ttransformIndex: f32,\n\tfillIndex: f32,\n\tstrokeIndex: f32\n}\nstruct Uniforms {\n\thalfWidth: f32,\n\thalfHeight: f32\n}\n\n@group(0) @binding(0) var uniforms: Uniforms;\n@group(0) @binding(1) var transforms: array>;\n\n@group(1) @binding(0) var colors : array;\n\n@group(2) @binding(0) var fontTexture: texture_2d;\n@group(2) @binding(1) var fontSampler: sampler;\n@group(2) @binding(2) var fontChars: array;\n\n@group(3) @binding(0) var textChars: array;\n@group(3) @binding(1) var textMetadata: array;\n\n@vertex\nfn vertexMain(input : VertexInput) -> VertexOutput {\n\tlet char = textChars[input.instance];\n\n\tlet text = textMetadata[i32(char.w)];\n\n\tlet fontChar = fontChars[i32(char.z)];\n\n\tlet charPos = ((pos[input.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;\n\n\tvar vert = vec4f(charPos, 0.0, 1.0);\n\tvert = transforms[i32(text.transformIndex)] * vert;\n\tvert.x /= uniforms.halfWidth;\n\tvert.y /= uniforms.halfHeight;\n\n\tvar output : VertexOutput;\n\toutput.position = vert;\n\toutput.texCoord = (pos[input.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;\n\toutput.fillColor = colors[i32(text.fillIndex)];\n\treturn output;\n}\n\nfn sampleMsdf(texCoord: vec2f) -> f32 {\n\tlet c = textureSample(fontTexture, fontSampler, texCoord);\n\treturn max(min(c.r, c.g), min(max(c.r, c.g), c.b));\n}\n\n@fragment\nfn fragmentMain(input : VertexOutput) -> @location(0) vec4f {\n\t// pxRange (AKA distanceRange) comes from the msdfgen tool,\n\t// uses the default which is 4.\n\tlet pxRange = 4.0;\n\tlet sz = vec2f(textureDimensions(fontTexture, 0));\n\tlet dx = sz.x*length(vec2f(dpdxFine(input.texCoord.x), dpdyFine(input.texCoord.x)));\n\tlet dy = sz.y*length(vec2f(dpdxFine(input.texCoord.y), dpdyFine(input.texCoord.y)));\n\tlet toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);\n\tlet sigDist = sampleMsdf(input.texCoord) - 0.5;\n\tlet pxDist = sigDist * toPixels;\n\tlet edgeWidth = 0.5;\n\tlet alpha = smoothstep(-edgeWidth, edgeWidth, pxDist);\n\tif (alpha < 0.001) {\n\t\tdiscard;\n\t}\n\treturn vec4f(input.fillColor.rgb, input.fillColor.a * alpha);\n}\n"}),a=Q5.device.createBindGroupLayout({label:"MSDF text group layout",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"}}]}),n=Q5.device.createSampler({minFilter:"linear",magFilter:"linear",mipmapFilter:"linear",maxAnisotropy:16}),i=Q5.device.createBindGroupLayout({label:"MSDF font group layout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:2,visibility:GPUShaderStage.VERTEX,buffer:{type:"read-only-storage"}}]}),o=Q5.device.createPipelineLayout({bindGroupLayouts:[...e.bindGroupLayouts,i,a]});e._pipelineConfigs[2]={label:"msdf font pipeline",layout:o,vertex:{module:r,entryPoint:"vertexMain"},fragment:{module:r,entryPoint:"fragmentMain",targets:[{format:"bgra8unorm",blend:e.blendConfigs.normal}]},primitive:{topology:"triangle-strip",stripIndexFormat:"uint32"},multisample:{count:4}},e._pipelines[2]=Q5.device.createRenderPipeline(e._pipelineConfigs[2]);class s{constructor(e,t,r,a){this.bindGroup=e,this.lineHeight=t,this.chars=r,this.kernings=a;let n=Object.values(r);this.charCount=n.length,this.defaultChar=n[0]}getChar(e){return this.chars[e]??this.defaultChar}getXAdvance(e,t=-1){let r=this.getChar(e);if(t>=0){let a=this.kernings.get(e);if(a)return r.xadvance+(a.get(t)??0)}return r.xadvance}}e._fonts=[];let l={},d=e.createGraphics(1,1);d.colorMode(e.RGB,1),e.loadFont=(r,a)=>{if("json"!=r.slice(r.lastIndexOf(".")+1))return d.loadFont(r,a);let o=r.slice(r.lastIndexOf("/")+1,r.lastIndexOf("-"));return(async(r,a,o)=>{t._preloadCount++;let d=await fetch(r);if(404==d.status)return t._preloadCount--,"";let c=await d.json(),h=r.lastIndexOf("/"),u=-1!=h?r.substring(0,h+1):"";d=await fetch(u+c.pages[0]);let p=await createImageBitmap(await d.blob()),f=[p.width,p.height,1],_=Q5.device.createTexture({label:`MSDF ${a}`,size:f,format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});Q5.device.queue.copyExternalImageToTexture({source:p},{texture:_},f),"string"==typeof c.chars&&(c.chars=e.CSV.parse(c.chars," "),c.kernings=e.CSV.parse(c.kernings," "));let g=c.chars.length,m=Q5.device.createBuffer({size:32*g,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),x=new Float32Array(m.getMappedRange()),v=1/c.common.scaleW,y=1/c.common.scaleH,w={},b=0;for(let[e,t]of c.chars.entries())w[t.id]=t,w[t.id].charIndex=e,x[b]=t.x*v,x[b+1]=t.y*y,x[b+2]=t.width*v,x[b+3]=t.height*y,x[b+4]=t.width,x[b+5]=t.height,x[b+6]=t.xoffset,x[b+7]=-t.yoffset,b+=8;m.unmap();let S=Q5.device.createBindGroup({label:"msdf font bind group",layout:i,entries:[{binding:0,resource:_.createView()},{binding:1,resource:n},{binding:2,resource:{buffer:m}}]}),M=new Map;if(c.kernings)for(let e of c.kernings){let t=M.get(e.first);t||(t=new Map,M.set(e.first,t)),t.set(e.second,e.amount)}e._font=new s(S,c.common.lineHeight,w,M),e._font.index=e._fonts.length,e._fonts.push(e._font),l[a]=e._font,t._preloadCount--,o&&o(a)})(r,o,a),o},e._textSize=18,e._textAlign="left",e._textBaseline="alphabetic";let c=!1,h=22.5,u=4.5,p=1.25;e.textFont=t=>{e._font=l[t]},e.textSize=t=>{e._textSize=t,c||(h=t*p,u=h-t)},e.textLeading=t=>{e._font.lineHeight=h=t,u=h-e._textSize,p=h/e._textSize,c=!0},e.textAlign=(t,r)=>{e._textAlign=t,r&&(e._textBaseline=r)},e._charStack=[],e._textStack=[];let f,_=(e,t,r)=>{let a=0,n=0,i=0,o=0,s=0,l=[],d=t.charCodeAt(0);for(let c=0;c{if(!e._font)return void(navigator.onLine&&!f&&(f=!0,e.loadFont("https://q5js.org/fonts/YaHei-msdf.json")));if(t.length>n){let e=[],r=0;for(;r=t.length){e.push(t.slice(r));break}let i=t.lastIndexOf(" ",a);(-1==i||i{let i=0;"center"==d?i=-.5*s.width- -.5*(s.width-s.lineWidths[a]):"right"==d&&(i=s.width-s.lineWidths[a]),l[p]=e+i,l[p+1]=t+r,l[p+2]=n.charIndex,l[p+3]=u,p+=4}))}else s=_(e._font,t,((e,t,r,a)=>{l[p]=e,l[p+1]=t,l[p+2]=a.charIndex,l[p+3]=u,p+=4})),"alphabetic"==c?a-=e._textSize:"center"==c?a-=.5*e._textSize:"bottom"==c&&(a-=h);e._charStack.push(l);let g=[];e._matrixDirty&&e._saveMatrix(),g[0]=r,g[1]=-a,g[2]=e._textSize/44,g[3]=e._transformIndex,g[4]=e._fillSet?e._fill:0,g[5]=e._stroke,e._textStack.push(g),e.drawStack.push(2,s.printedCharCount,e._font.index)},e.textWidth=t=>e._font?_(e._font,t).width:0,e.createTextImage=(t,r,a)=>{if(d.textSize(e._textSize),e._doFill){let t=4*e._fill;d.fill(colorStack.slice(t,t+4))}if(e._doStroke){let t=4*e._stroke;d.stroke(colorStack.slice(t,t+4))}let n=d.createTextImage(t,r,a);if(null==n.canvas.textureIndex)e._createTexture(n);else if(n.modified){let t=n.canvas,r=[t.width,t.height,1],a=e._textures[t.textureIndex];Q5.device.queue.copyExternalImageToTexture({source:t},{texture:a,colorSpace:e.canvas.colorSpace},r),n.modified=!1}return n},e.textImage=(t,r,a)=>{"string"==typeof t&&(t=e.createTextImage(t));let n=e._imageMode;e._imageMode="corner";let i=e._textAlign;"center"==i?r-=t.canvas.hw:"right"==i&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?a-=t._leading:"center"==o?a-=t._middle:"bottom"==o?a-=t._bottom:"top"==o&&(a-=t._top),e.image(t,r,a),e._imageMode=n},e._hooks.preRender.push((()=>{if(!e._charStack.length)return;let t=0;for(let r of e._charStack)t+=4*r.length;let r=Q5.device.createBuffer({size:t,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(r.getMappedRange()).set(e._charStack.flat()),r.unmap();let n=6*e._textStack.length*4,i=Q5.device.createBuffer({label:"textBuffer",size:n,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});new Float32Array(i.getMappedRange()).set(e._textStack.flat()),i.unmap(),e._textBindGroup=Q5.device.createBindGroup({label:"msdf text bind group",layout:a,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:i}}]})})),e._hooks.postRender.push((()=>{e._charStack.length=0,e._textStack.length=0}))};