q5
Version:
Beginner friendly graphics powered by WebGPU and optimized for interactive art!
9 lines • 125 kB
JavaScript
/**
* q5.js
* @version 3.7
* @author quinton-ashley
* @contributors evanalulu, Tezumie, ormaq, Dukemz, LingDong-
* @license LGPL-3.0
* @class Q5
*/
function Q5(e,t,r){let n,i=this;i._isQ5=i._q5=!0,i._parent=t,i.ready=new Promise((e=>{n=e})),"webgpu-fallback"==r?(i._renderer="c2d",i._webgpu=i._webgpuFallback=!0):(i._renderer=r||"c2d",i["_"+i._renderer]=!0);let a,o="auto"==e;if(e??="global","auto"==e){if(!(window.setup||window.update||Q5.update||window.draw||Q5.draw))return;e="global"}"global"==e&&(Q5._hasGlobal=i._isGlobal=!0,a=Q5._esm?globalThis:Q5._server?global:window),"graphics"==e&&(i._isGraphics=!0),"image"==e&&(i._isImage=!0);let s=new Proxy(i,{set:(e,t,r)=>(i[t]=r,i._isGlobal&&(a[t]=r),!0)});i.canvas=i.ctx=i.drawingContext=null,i.pixels=[];let l=null,d=!0;async function c(e){for(let t of Q5.hooks[e])await t.call(i,s)}i.frameCount=0,i.deltaTime=16,i._targetFrameRate=0,i._targetFrameDuration=16.666666666666668,i._frameRate=i._fps=60,i._loop=!0;let u=0;i.millis=()=>performance.now()-u,i.noCanvas=()=>{i.canvas?.remove&&i.canvas.remove(),i.canvas=0,s.ctx=s.drawingContext=0},window&&(i.windowWidth=window.innerWidth,i.windowHeight=window.innerHeight,i.deviceOrientation=window.screen?.orientation?.type),i._loaders=[],i.loadAll=()=>{let e=[...i._loaders];return i._loaders=[],i._g&&(e=e.concat(i._g._loaders),i._g._loaders=[]),Promise.all(e)},i.isPreloadSupported=()=>!0,i.disablePreload=()=>i._disablePreload=!0;const h=[];async function f(e){let t=e||performance.now();if(i._didResize&&(i.windowResized(),i._didResize=!1),i._loop)if(d)l=g(f);else{let e=t+i._targetFrameDuration,r=e-performance.now();for(;r<0;)r+=i._targetFrameDuration;l=setTimeout((()=>f(e)),r)}else if(i.frameCount&&!i._redraw)return;if(i.frameCount&&d&&!i._redraw){if(t-i._lastFrameTime<i._targetFrameDuration-4)return}s.deltaTime=t-i._lastFrameTime,i._frameRate=1e3/i.deltaTime,s.frameCount++;let r=performance.now();i.resetMatrix(),i._beginRender&&i._beginRender(),await c("predraw");try{await i.draw()}catch(e){throw Q5.errorTolerant||i.noLoop(),i._fes&&i._fes(e),e}await c("postdraw"),await i.postProcess(),i._render&&i._render(),i._finishRender&&i._finishRender(),s.pmouseX=i.mouseX,s.pmouseY=i.mouseY,s.moveX=s.moveY=0,i._lastFrameTime=t;let n=performance.now();i._fps=Math.round(1e3/(n-r))}i._incrementPreload=()=>{i._loaders.push(new Promise((e=>h.push(e))))},i._decrementPreload=()=>{h.length&&h.pop()()},i.noLoop=()=>{i._loop=!1,null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l)),l=null},i.loop=()=>{i._loop=!0,i._setupDone&&null==l&&f()},i.isLooping=()=>i._loop,i.redraw=async(e=1)=>{i._redraw=!0;for(let t=0;t<e;t++)await f();i._redraw=!1},i.remove=async()=>{i.noLoop(),i.canvas.remove(),await c("remove")},i.frameRate=e=>(e&&e!=i._targetFrameRate&&(i._targetFrameRate=e,i._targetFrameDuration=1e3/e,i._loop&&null!=l&&(d&&window.cancelAnimationFrame?cancelAnimationFrame(l):clearTimeout(l),l=null),d=e<=60,i._setupDone&&(l=d?g(f):setTimeout((()=>f()),i._targetFrameDuration))),i._frameRate),i.getTargetFrameRate=()=>i._targetFrameRate||60,i.getFPS=()=>i._fps,i.Element=function(e){this.elt=e},i._elements=[],i.describe=()=>{},i.log=i.print=console.log;for(let e in Q5.modules)Q5.modules[e](i,s);let p=Q5.renderers[i._renderer];for(let e in p)p[e](i,s);for(let e in Q5)"_"!=e[1]&&e[1]==e[1].toUpperCase()&&(i[e]=Q5[e]);if(i._isGraphics)return;if(i._isGlobal){let e=Object.assign({},i);delete e.Color,Object.assign(Q5,e),delete Q5.Q5}for(let e of Q5.hooks.init)e.call(i,s);for(let[e,t]of Object.entries(Q5.prototype))"_"!=e[0]&&"function"==typeof i[e]&&(i[e]=t.bind(i));for(let[e,t]of Object.entries(Q5.preloadMethods))i[e]=function(){return i._incrementPreload(),t.apply(i,arguments)};if(i._isGlobal){let e=Object.getOwnPropertyNames(i);for(let t of e)"_"!=t[0]&&(a[t]=i[t]);for(let e of["_incrementPreload","_decrementPreload"])a[e]=i[e]}"function"==typeof e&&e(i),Q5._instanceCount++;let g=window.requestAnimationFrame||function(e){const t=i._lastFrameTime+i._targetFrameDuration;return setTimeout((()=>{e(t)}),t-performance.now())},m=a||i,_=Q5._userFns.slice(0,15);for(let e of _)i[e]??=()=>{};if(i._isGlobal){let e=Q5._userFns.slice(0,17);for(let t of e)Q5[t]?i[t]=Q5[t]:Object.defineProperty(Q5,t,{get:()=>i[t],set:e=>i[t]=e})}function x(e){const t=m[e]||i[e];i[e]=e=>{try{return t(e)}catch(e){throw i._fes&&i._fes(e),e}}}async function v(){await c("presetup"),n(),(m.preload||i.preload)&&(x("preload"),i.preload()),await Promise.race([new Promise((e=>{!function t(){i.setup||i.update||i.draw||m.setup||m.update||m.draw?e():i._setupDone||(i.canvas?.ready&&i._render&&(i._beginRender(),i._render(),i._finishRender()),g(t))}()})),new Promise((e=>{setTimeout((()=>{i._loaders.length||e()}),500)}))]),i._disablePreload||await i.loadAll(),i.setup??=m.setup||(()=>{}),x("setup");for(let e of _)x(e);i.draw??=m.draw||(()=>{}),u=performance.now(),await i.setup(),i._setupDone=!0,null===i.ctx&&i.createCanvas(200,200),await c("postsetup"),i.frameCount||(i._lastFrameTime=performance.now()-15,g(f))}Q5.instances.push(i),o||Q5._esm?v():setTimeout(v,32)}function createCanvas(e,t,r){if(Q5._hasGlobal)return;if("c2d"==e||"c2d"==t||"c2d"==r||"c2d"==r?.renderer||!Q5._esm){let n=new Q5,i=n.createCanvas(e,t,r);return n.ready.then((()=>i))}return Q5.WebGPU().then((n=>n.createCanvas(e,t,r)))}Q5.renderers={},Q5.modules={},Q5._server="object"==typeof process,Q5._esm=void 0===this,Q5._instanceCount=0,Q5.instances=[],Q5._friendlyError=(e,t)=>{Q5.disableFriendlyErrors||console.error(t+": "+e)},Q5._validateParameters=()=>!0,Q5._userFns=["postProcess","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","doubleClicked","mouseWheel","keyPressed","keyReleased","keyTyped","touchStarted","touchMoved","touchEnded","windowResized","update","draw"],Q5.hooks={init:[],presetup:[],postsetup:[],predraw:[],postdraw:[],remove:[]},Q5.addHook=(e,t)=>Q5.hooks[e].push(t),Q5.registerAddon=e=>{let t={};e(Q5,Q5.prototype,t);for(let e in t)Q5.hooks[e].push(t[e])},Q5.prototype.registerMethod=(e,t)=>{("beforeSetup"==e||e.includes("Preload"))&&(e="presetup"),"afterSetup"==e&&(e="postsetup"),"pre"==e&&(e="predraw"),"post"==e&&(e="postdraw"),Q5.hooks[e].push(t)},Q5.preloadMethods={},Q5.prototype.registerPreloadMethod=(e,t)=>Q5.preloadMethods[e]=t[e],Q5._server&&(global.q5=global.Q5=Q5,global.p5??=Q5),"object"==typeof window?(window.q5=window.Q5=Q5,window.p5??=Q5,window.createCanvas=createCanvas,window.C2D="c2d",window.WEBGPU="webgpu"):global.window=0,Q5.version=Q5.VERSION="3.7","object"==typeof document&&document.addEventListener("DOMContentLoaded",(()=>{Q5._hasGlobal||(Q5.update||Q5.draw?Q5.WebGPU():new Q5("auto"))})),Q5.modules.canvas=(e,t)=>{e._Canvas=window.OffscreenCanvas||function(){return document.createElement("canvas")},Q5._server?Q5._createServerCanvas&&(t.canvas=Q5._createServerCanvas(200,200)):(e._isImage||e._isGraphics)&&(t.canvas=new e._Canvas(200,200)),e.canvas||("object"==typeof document?(t.canvas=document.createElement("canvas"),e.canvas.id="q5Canvas"+Q5._instanceCount,e.canvas.classList.add("q5Canvas")):e.noCanvas()),e.displayDensity=()=>window.devicePixelRatio||1,e.width=200,e.height=200,e._pixelDensity=1;let r=e.canvas;if(r&&(r.width=200,r.height=200,r.colorSpace=Q5.canvasOptions.colorSpace,e._isImage||(r.renderer=e._renderer,r[e._renderer]=!0,e._pixelDensity=Math.ceil(e.displayDensity()))),e._adjustDisplay=e=>{let t=r.style;t&&e&&(t.width=r.w+"px",t.height=r.h+"px")},e.createCanvas=function(t,i,a){(isNaN(t)||"string"==typeof t&&!t.includes(":"))&&(a=t,t=null),"number"!=typeof i&&(a=i,i=null),a??=arguments[3],"string"==typeof a&&(a={renderer:a});let o=Object.assign({},Q5.canvasOptions);if("object"==typeof a&&Object.assign(o,a),!e._isImage)if(e._isGraphics)e._pixelDensity=this._pixelDensity;else if(Q5._server)r.visible=!0;else{let t=r,i=document.body||document.documentElement;for(;t&&t.parentElement!=i;)t=t.parentElement;if(t||(document.getElementById(r.id)?.remove(),n()),window.IntersectionObserver){let t=!1;new IntersectionObserver((n=>{if(n[0].isIntersecting)r.visible=!0;else{let e=r.getBoundingClientRect();r.visible=e.top<window.innerHeight&&e.bottom>0&&e.left<window.innerWidth&&e.right>0}t||(e._wasLooping=e._loop,t=!0),r.visible?e._wasLooping&&!e._loop&&e.loop():(e._wasLooping=e._loop,e.noLoop())})).observe(r)}}e._setCanvasSize(t,i),Object.assign(r,o);let s=e._createCanvas(r.w,r.h,o);return e._addEventMethods&&e._addEventMethods(r),e.canvas.ready=!0,s},e.createGraphics=function(t,r,n={}){"string"==typeof n&&(n={renderer:n});let i=new Q5("graphics",void 0,n.renderer||(e._webgpuFallback?"webgpu-fallback":e._renderer));n.alpha??=!0,n.colorSpace??=e.canvas.colorSpace,n.pixelDensity??=e._pixelDensity,i._defaultImageScale=e._defaultImageScale,i.createCanvas.call(e,t,r,n);let a=i._pixelDensity*e._defaultImageScale;return i.defaultWidth=t*a,i.defaultHeight=r*a,i},e._setCanvasSize=(n,i)=>{i??=n??window.innerHeight,n??=window.innerWidth,r.w=n=Math.ceil(n),r.h=i=Math.ceil(i),t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity),t.width=n,t.height=i,e.displayMode&&!r.displayMode?e.displayMode():e._adjustDisplay(!0)},e._setImageSize=(n,i)=>{t.width=r.w=n,t.height=r.h=i,t.halfWidth=r.hw=n/2,t.halfHeight=r.hh=i/2,r.width=Math.ceil(n*e._pixelDensity),r.height=Math.ceil(i*e._pixelDensity)},e.defaultImageScale=t=>t?(e._g&&(e._g._defaultImageScale=t),e._defaultImageScale=t):e._defaultImageScale,e.defaultImageScale(.5),!e._isImage){if(r&&!e._isGraphics){function n(){let t=e._parent;if(t??=document.getElementsByTagName("main")[0],!t){t=document.createElement("main"),(document.body||document.documentElement).appendChild(t)}r.parent(t),document.body||document.addEventListener("DOMContentLoaded",(()=>{document.body&&document.body.appendChild(t)}))}r.parent=t=>{function n(){e.frameCount>1&&(e._didResize=!0,e._adjustDisplay())}r.parentElement&&r.parentElement.removeChild(r),"string"==typeof t&&(t=document.getElementById(t)),t.append(r),"function"==typeof ResizeObserver?(e._ro&&e._ro.disconnect(),e._ro=new ResizeObserver(n),e._ro.observe(t)):e.frameCount||window.addEventListener("resize",n)},n()}e.resizeCanvas=(t,n)=>{if(!e.ctx)return e.createCanvas(t,n);t==r.w&&n==r.h||e._resizeCanvas(t,n)},r&&!Q5._createServerCanvas&&(r.resize=e.resizeCanvas),e.pixelDensity=t=>t&&t!=e._pixelDensity?(e._pixelDensity=t,e._resizeCanvas(r.w,r.h),e._g&&e._g.pixelDensity(t),t):e._pixelDensity,window&&!e._isGraphics&&window.addEventListener("resize",(()=>{e._didResize=!0,t.windowWidth=window.innerWidth,t.windowHeight=window.innerHeight,t.deviceOrientation=window.screen?.orientation?.type}))}},Q5.CENTER="center",Q5.LEFT="left",Q5.RIGHT="right",Q5.TOP="top",Q5.BOTTOM="bottom",Q5.BASELINE="alphabetic",Q5.MIDDLE="middle",Q5.NORMAL="normal",Q5.ITALIC="italic",Q5.BOLD="bold",Q5.BOLDITALIC="italic bold",Q5.ROUND="round",Q5.SQUARE="butt",Q5.PROJECT="square",Q5.MITER="miter",Q5.BEVEL="bevel",Q5.NONE="none",Q5.SIMPLE="simple",Q5.CHORD_OPEN=0,Q5.PIE_OPEN=1,Q5.PIE=2,Q5.CHORD=3,Q5.RADIUS="radius",Q5.CORNER="corner",Q5.CORNERS="corners",Q5.OPEN=0,Q5.CLOSE=1,Q5.VIDEO="video",Q5.AUDIO="audio",Q5.LANDSCAPE="landscape",Q5.PORTRAIT="portrait",Q5.BLEND="source-over",Q5.REMOVE="destination-out",Q5.ADD="lighter",Q5.DARKEST="darken",Q5.LIGHTEST="lighten",Q5.DIFFERENCE="difference",Q5.SUBTRACT="subtract",Q5.EXCLUSION="exclusion",Q5.MULTIPLY="multiply",Q5.SCREEN="screen",Q5.REPLACE="copy",Q5.OVERLAY="overlay",Q5.HARD_LIGHT="hard-light",Q5.SOFT_LIGHT="soft-light",Q5.DODGE="color-dodge",Q5.BURN="color-burn",Q5.THRESHOLD=1,Q5.GRAY=2,Q5.OPAQUE=3,Q5.INVERT=4,Q5.POSTERIZE=5,Q5.DILATE=6,Q5.ERODE=7,Q5.BLUR=8,Q5.SEPIA=9,Q5.BRIGHTNESS=10,Q5.SATURATION=11,Q5.CONTRAST=12,Q5.HUE_ROTATE=13,Q5.C2D=Q5.P2D=Q5.P2DHDR="c2d",Q5.WEBGL="webgl",Q5.GPU=Q5.WEBGPU="webgpu",Q5.canvasOptions={alpha:!1,colorSpace:"display-p3"},window.matchMedia&&matchMedia("(dynamic-range: high) and (color-gamut: p3)").matches?Q5.supportsHDR=!0:Q5.canvasOptions.colorSpace="srgb",Q5.renderers.c2d={},Q5.renderers.c2d.canvas=(e,t)=>{let r=e.canvas;function n(){let t=e._styles.pop();for(let r of e._styleNames)e[r]=t[r]}e.colorMode&&e.colorMode("rgb",e._webgpu?1:255),e._createCanvas=function(n,i,a){if(r)return t.ctx=t.drawingContext=r.getContext("2d",a),e._isImage||(e.ctx.fillStyle=e._fill="white",e.ctx.strokeStyle=e._stroke="black",e.ctx.lineCap="round",e.ctx.lineJoin="miter",e.ctx.textAlign="left",e._strokeWeight=1),e.ctx.scale(e._pixelDensity,e._pixelDensity),e.ctx.save(),r;console.error("q5 canvas could not be created. skia-canvas and jsdom packages not found.")},e.clear=()=>{e.ctx.save(),e.ctx.resetTransform(),e.ctx.clearRect(0,0,e.canvas.width,e.canvas.height),e.ctx.restore()},e._isImage||(e.background=function(t){e.ctx.save(),e.ctx.resetTransform(),e.ctx.globalAlpha=1,t.canvas?e.image(t,0,0,e.canvas.width,e.canvas.height):(Q5.Color&&!t._isColor&&(t=e.color(...arguments)),e.ctx.fillStyle=t.toString(),e.ctx.fillRect(0,0,e.canvas.width,e.canvas.height)),e.ctx.restore()},e._resizeCanvas=(t,n)=>{let i,a={};for(let t in e.ctx)"function"!=typeof e.ctx[t]&&(a[t]=e.ctx[t]);if(delete a.canvas,e.frameCount>1){i=new e._Canvas(r.width,r.height),i.w=r.w,i.h=r.h,i.getContext("2d").drawImage(r,0,0)}e._setCanvasSize(t,n);for(let t in a)e.ctx[t]=a[t];e.scale(e._pixelDensity),i&&e.ctx.drawImage(i,0,0,i.w,i.h)},e.fill=function(t){if(e._doFill=e._fillSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doFill=!1;e.ctx.fillStyle=e._fill=t.toString()},e.stroke=function(t){if(e._doStroke=e._strokeSet=!0,Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doStroke=!1;e.ctx.strokeStyle=e._stroke=t.toString()},e.strokeWeight=t=>{t||(e._doStroke=!1),e.ctx.lineWidth=e._strokeWeight=t||1e-4},e.noFill=()=>e._doFill=!1,e.noStroke=()=>e._doStroke=!1,e.opacity=t=>e.ctx.globalAlpha=t,e._getFillIdx=()=>e._fill,e._setFillIdx=t=>e._fill=t,e._getStrokeIdx=()=>e._stroke,e._setStrokeIdx=t=>e._stroke=t,e._doShadow=!1,e._shadowOffsetX=e._shadowOffsetY=e._shadowBlur=10,e.shadow=function(t){if(Q5.Color&&(t._isColor||"string"==typeof t&&!e._namedColors[t]||(t=e.color(...arguments)),t.a<=0))return e._doShadow=!1;e.ctx.shadowColor=e._shadow=t.toString(),e._doShadow=!0,e.ctx.shadowOffsetX||=e._shadowOffsetX,e.ctx.shadowOffsetY||=e._shadowOffsetY,e.ctx.shadowBlur||=e._shadowBlur},e.shadowBox=(t,r,n)=>{e.ctx.shadowOffsetX=e._shadowOffsetX=t,e.ctx.shadowOffsetY=e._shadowOffsetY=r||t,e.ctx.shadowBlur=e._shadowBlur=n||0},e.noShadow=()=>{e._doShadow=!1,e.ctx.shadowOffsetX=e.ctx.shadowOffsetY=e.ctx.shadowBlur=0},e.translate=(t,r)=>{t.x&&(r=t.y,t=t.x),e.ctx.translate(t,r)},e.rotate=t=>{e._angleMode&&(t=e.radians(t)),e.ctx.rotate(t)},e.scale=(t,r)=>{t.x&&(r=t.y,t=t.x),r??=t,e.ctx.scale(t,r)},e.applyMatrix=(t,r,n,i,a,o)=>e.ctx.transform(t,r,n,i,a,o),e.shearX=t=>e.ctx.transform(1,0,e.tan(t),1,0,0),e.shearY=t=>e.ctx.transform(1,e.tan(t),0,1,0,0),e.resetMatrix=()=>{e.ctx&&(e.ctx.resetTransform(),e.scale(e._pixelDensity),e._webgpu&&e.translate(e.halfWidth,e.halfHeight))},e._styleNames=["_fill","_stroke","_strokeWeight","_doFill","_doStroke","_fillSet","_strokeSet","_shadow","_doShadow","_shadowOffsetX","_shadowOffsetY","_shadowBlur","_tint","_textSize","_textAlign","_textBaseline","_imageMode","_rectMode","_ellipseMode","_colorMode","_colorFormat","Color"],e._styles=[],e.pushStyles=()=>{let t={};for(let r of e._styleNames)t[r]=e[r];e._styles.push(t),e._fontMod&&e._updateFont()},e.popStyles=()=>{n(),e.ctx.fillStyle=e._fill,e.ctx.strokeStyle=e._stroke,e.ctx.lineWidth=e._strokeWeight,e.ctx.shadowColor=e._shadow,e.ctx.shadowOffsetX=e._doShadow?e._shadowOffsetX:0,e.ctx.shadowOffsetY=e._doShadow?e._shadowOffsetY:0,e.ctx.shadowBlur=e._doShadow?e._shadowBlur:0},e.pushMatrix=()=>e.ctx.save(),e.popMatrix=()=>e.ctx.restore(),e.push=()=>{e.pushStyles(),e.ctx.save()},e.pop=()=>{e.ctx.restore(),n()})},Q5.renderers.c2d.shapes=e=>{e._doStroke=!0,e._doFill=!0,e._strokeSet=!1,e._fillSet=!1,e._ellipseMode=Q5.CENTER,e._rectMode=Q5.CORNER;let t=!0,r=[];function n(){e._doFill&&e.ctx.fill(),e._doStroke&&e.ctx.stroke()}e.blendMode=t=>e.ctx.globalCompositeOperation=t,e.strokeCap=t=>e.ctx.lineCap=t,e.strokeJoin=t=>e.ctx.lineJoin=t,e.ellipseMode=t=>e._ellipseMode=t,e.rectMode=t=>e._rectMode=t,e.curveDetail=()=>{},e.line=(t,r,n,i)=>{e._doStroke&&(e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(n,i),e.ctx.stroke())};const i=2*Math.PI;function a(t,r,n,a,o,s,l){if(e._angleMode&&(o=e.radians(o),s=e.radians(s)),(o%=i)<0&&(o+=i),(s%=i)<0&&(s+=i),o>s&&(s+=i),o==s)return e.ellipse(t,r,n,a);if(n/=2,a/=2,n=Math.abs(n),a=Math.abs(a),e._doFill||l!=e.PIE_OPEN||(l=e.CHORD_OPEN),e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),l!=e.PIE&&l!=e.PIE_OPEN||e.ctx.lineTo(t,r),e._doFill&&e.ctx.fill(),e._doStroke){if(l!=e.PIE&&l!=e.CHORD||e.ctx.closePath(),l!=e.PIE_OPEN)return e.ctx.stroke();e.ctx.beginPath(),e.ctx.ellipse(t,r,n,a,0,o,s),e.ctx.stroke()}}function o(t,r,a,o){e.ctx.beginPath(),e.ctx.ellipse(t,r,Math.abs(a/2),Math.abs(o/2),0,0,i),n()}function s(t,r,i,a,o,l,d,c){return void 0===o?function(t,r,i,a){e.ctx.beginPath(),e.ctx.rect(t,r,i,a),n()}(t,r,i,a):void 0===l?s(t,r,i,a,o,o,o,o):(e.ctx.beginPath(),e.ctx.roundRect(t,r,i,a,[o,l,d,c]),void n())}e.arc=(t,r,n,i,o,s,l)=>{if(o==s)return e.ellipse(t,r,n,i);l??=e.PIE_OPEN,e._ellipseMode==e.CENTER?a(t,r,n,i,o,s,l):e._ellipseMode==e.RADIUS?a(t,r,2*n,2*i,o,s,l):e._ellipseMode==e.CORNER?a(t+n/2,r+i/2,n,i,o,s,l):e._ellipseMode==e.CORNERS&&a((t+n)/2,(r+i)/2,n-t,i-r,o,s,l)},e.ellipse=(t,r,n,i)=>{i??=n,e._ellipseMode==e.CENTER?o(t,r,n,i):e._ellipseMode==e.RADIUS?o(t,r,2*n,2*i):e._ellipseMode==e.CORNER?o(t+n/2,r+i/2,n,i):e._ellipseMode==e.CORNERS&&o((t+n)/2,(r+i)/2,n-t,i-r)},e.circle=(t,r,a)=>{e._ellipseMode==e.CENTER?(e.ctx.beginPath(),e.ctx.arc(t,r,Math.abs(a/2),0,i),n()):e.ellipse(t,r,a,a)},e.point=(t,r)=>{e._doStroke&&(t.x&&(r=t.y,t=t.x),e.ctx.beginPath(),e.ctx.moveTo(t,r),e.ctx.lineTo(t,r),e.ctx.stroke())},e.rect=(t,r,n,i=n,a,o,l,d)=>{e._rectMode==e.CENTER?s(t-n/2,r-i/2,n,i,a,o,l,d):e._rectMode==e.RADIUS?s(t-n,r-i,2*n,2*i,a,o,l,d):e._rectMode==e.CORNER?s(t,r,n,i,a,o,l,d):e._rectMode==e.CORNERS&&s(t,r,n-t,i-r,a,o,l,d)},e.square=(t,r,n,i,a,o,s)=>e.rect(t,r,n,n,i,a,o,s),e.capsule=(t,r,i,a,o)=>{const s=i-t,l=a-r,d=Math.hypot(s,l);if(0===d)return e.circle(t,r,2*o);const c=Math.atan2(l,s),u=-l/d*o,h=s/d*o;e.ctx.beginPath(),e.ctx.moveTo(t-u,r-h),e.ctx.arc(t,r,o,c-e.HALF_PI,c+e.HALF_PI,!0),e.ctx.lineTo(i+u,a+h),e.ctx.arc(i,a,o,c+e.HALF_PI,c-e.HALF_PI,!0),e.ctx.closePath(),n()},e.beginShape=()=>{r=[],e.ctx.beginPath(),t=!0},e.beginContour=()=>{e.ctx.closePath(),r=[],t=!0},e.endContour=()=>{r=[],t=!0},e.vertex=(n,i)=>{r=[],t?e.ctx.moveTo(n,i):e.ctx.lineTo(n,i),t=!1},e.bezierVertex=(t,n,i,a,o,s)=>{r=[],e.ctx.bezierCurveTo(t,n,i,a,o,s)},e.quadraticVertex=(t,n,i,a)=>{r=[],e.ctx.quadraticCurveTo(t,n,i,a)},e.bezier=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.bezierVertex(n,i,a,o,s,l),e.endShape()},e.triangle=(t,r,n,i,a,o)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.endShape(e.CLOSE)},e.quad=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.vertex(t,r),e.vertex(n,i),e.vertex(a,o),e.vertex(s,l),e.endShape(e.CLOSE)},e.endShape=t=>{r=[],t&&e.ctx.closePath(),n()},e.curveVertex=(n,i)=>{if(r.push([n,i]),r.length<4)return;let a=r.at(-4),o=r.at(-3),s=r.at(-2),l=r.at(-1),d=o[0]+(s[0]-a[0])/6,c=o[1]+(s[1]-a[1])/6,u=s[0]-(l[0]-o[0])/6,h=s[1]-(l[1]-o[1])/6;t&&(e.ctx.moveTo(o[0],o[1]),t=!1),e.ctx.bezierCurveTo(d,c,u,h,s[0],s[1])},e.curve=(t,r,n,i,a,o,s,l)=>{e.beginShape(),e.curveVertex(t,r),e.curveVertex(n,i),e.curveVertex(a,o),e.curveVertex(s,l),e.endShape()},e.curvePoint=(e,t,r,n,i)=>{const a=i*i*i,o=i*i;return e*(-.5*a+o-.5*i)+t*(1.5*a-2.5*o+1)+r*(-1.5*a+2*o+.5*i)+n*(.5*a-.5*o)},e.bezierPoint=(e,t,r,n,i)=>{const a=1-i;return Math.pow(a,3)*e+3*Math.pow(a,2)*i*t+3*a*Math.pow(i,2)*r+Math.pow(i,3)*n},e.curveTangent=(e,t,r,n,i)=>{const a=i*i;return e*(-3*a/2+2*i-.5)+t*(9*a/2-5*i)+r*(-9*a/2+4*i+.5)+n*(3*a/2-i)},e.bezierTangent=(e,t,r,n,i)=>{const a=1-i;return 3*n*Math.pow(i,2)-3*r*Math.pow(i,2)+6*r*a*i-6*t*a*i+3*t*Math.pow(a,2)-3*e*Math.pow(a,2)},e.erase=function(t,r){255==e._colorFormat&&(t&&(t/=255),r&&(r/=255)),e.ctx.save(),e.ctx.globalCompositeOperation="destination-out",e.ctx.fillStyle=`rgb(0 0 0 / ${t||1})`,e.ctx.strokeStyle=`rgb(0 0 0 / ${r||1})`},e.noErase=function(){e.ctx.globalCompositeOperation="source-over",e.ctx.restore()},e.inFill=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInPath(t*n,r*n)},e.inStroke=(t,r)=>{const n=e._pixelDensity;return e.ctx.isPointInStroke(t*n,r*n)}},Q5.renderers.c2d.image=(e,t)=>{const r=e.canvas;r&&(r.convertToBlob??=e=>new Promise((t=>{r.toBlob((e=>t(e)),e.type,e.quality)}))),e._tint=null;let n=null,i=null;e.createImage=(t,r,n={})=>(n.colorSpace??=e.canvas.colorSpace,n.defaultImageScale??=e._defaultImageScale,new Q5.Image(t,r,n)),e.loadImage=function(t,r,n){if(t.canvas)return t;if("gif"==t.slice(-3).toLowerCase())throw new Error("q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84");let i=[...arguments].at(-1);"object"==typeof i?(n=i,r=null):n=void 0;let a=e.createImage(1,1,n),o=a._pixelDensity,s=new window.Image;return s.crossOrigin="Anonymous",a.promise=new Promise(((t,i)=>{s.onload=()=>{delete a.then,a._usedAwait&&(a=e.createImage(1,1,n)),s._pixelDensity=o,a.defaultWidth=s.width*e._defaultImageScale,a.defaultHeight=s.height*e._defaultImageScale,a.naturalWidth=s.naturalWidth||s.width,a.naturalHeight=s.naturalHeight||s.height,a._setImageSize(Math.ceil(a.naturalWidth/o),Math.ceil(a.naturalHeight/o)),a.ctx.drawImage(s,0,0),r&&r(a),t(a)},s.onerror=i})),e._loaders.push(a.promise),a.then=(e,t)=>(a._usedAwait=!0,a.promise.then(e,t)),a.src=s.src=t,a},e._imageMode=Q5.CORNER,e.imageMode=t=>e._imageMode=t,e.image=(t,r,n,i,a,o=0,s=0,l,d)=>{if(!t)return;let c=t.canvas||t;i??=t.defaultWidth||c.width||t.videoWidth,a??=t.defaultHeight||c.height||t.videoHeight,"center"==e._imageMode&&(r-=.5*i,n-=.5*a);let u=t._pixelDensity||1;if(l?l*=u:l=c.width||c.videoWidth,d?d*=u:d=c.height||c.videoHeight,e._tint){if(t._retint||t._tint!=e._tint){t._tintImg??=e.createImage(t.w,t.h,{pixelDensity:u}),t._tintImg.width==t.width&&t._tintImg.height==t.height||t._tintImg.resize(t.w,t.h);let r=t._tintImg.ctx;r.globalCompositeOperation="copy",r.fillStyle=e._tint,r.fillRect(0,0,t.width,t.height),t?.canvas?.alpha&&(r.globalCompositeOperation="destination-in",r.drawImage(c,0,0,t.width,t.height)),r.globalCompositeOperation="multiply",r.drawImage(c,0,0,t.width,t.height),t._tint=e._tint,t._retint=!1}c=t._tintImg.canvas}t.flipped&&(e.ctx.save(),e.ctx.translate(r+i,0),e.ctx.scale(-1,1),r=0),e.ctx.drawImage(c,o*u,s*u,l,d,r,n,i,a),t.flipped&&e.ctx.restore()},e.filter=(t,n)=>{e.ctx.save();let i="";if(e.ctx.filter){if("string"==typeof t)i=t;else if(t==Q5.GRAY)i="saturate(0%)";else if(t==Q5.INVERT)i="invert(100%)";else if(t==Q5.BLUR){i=`blur(${Math.ceil(n*e._pixelDensity)||1}px)`}else if(t==Q5.THRESHOLD){n??=.5,i=`saturate(0%) brightness(${Math.floor(.5/Math.max(n,1e-5)*100)}%) contrast(1000000%)`}else if(t==Q5.SEPIA)i=`sepia(${n??1})`;else if(t==Q5.BRIGHTNESS)i=`brightness(${n??1})`;else if(t==Q5.SATURATION)i=`saturate(${n??1})`;else if(t==Q5.CONTRAST)i=`contrast(${n??1})`;else if(t==Q5.HUE_ROTATE){i=`hue-rotate(${n}${0==e._angleMode?"rad":"deg"})`}if(i&&(e.ctx.filter=i,"none"==e.ctx.filter))throw new Error(`Invalid filter format: ${t}`)}i||e._softFilter(t,n),e.ctx.globalCompositeOperation="source-over",e.ctx.drawImage(r,0,0,r.w,r.h),e.ctx.restore(),e.modified=e._retint=!0},e._isImage&&(e.resize=(t,n)=>{let i=new e._Canvas(r.width,r.height);i.getContext("2d",{colorSpace:r.colorSpace}).drawImage(r,0,0),e._setImageSize(t,n),e.defaultWidth=r.width*e._defaultImageScale,e.defaultHeight=r.height*e._defaultImageScale,e.ctx.clearRect(0,0,r.width,r.height),e.ctx.drawImage(i,0,0,r.width,r.height),e.modified=e._retint=!0}),e._getImageData=(t,n,i,a)=>e.ctx.getImageData(t,n,i,a,{colorSpace:r.colorSpace}),e.trim=()=>{let t=e._pixelDensity||1,n=r.width,i=r.height,a=e._getImageData(0,0,n,i).data,o=n,s=0,l=i,d=0,c=3;for(let e=0;e<i;e++)for(let t=0;t<n;t++)0!==a[c]&&(t<o&&(o=t),t>s&&(s=t),e<l&&(l=e),e>d&&(d=e)),c+=4;return l=Math.floor(l/t),d=Math.floor(d/t),o=Math.floor(o/t),s=Math.floor(s/t),e.get(o,l,s-o+1,d-l+1)},e.mask=t=>{e.ctx.save(),e.ctx.resetTransform();let r=e.ctx.globalCompositeOperation;e.ctx.globalCompositeOperation="destination-in",e.ctx.drawImage(t.canvas,0,0),e.ctx.globalCompositeOperation=r,e.ctx.restore(),e.modified=e._retint=!0},e.inset=(t,n,i,a,o,s,l,d)=>{let c=e._pixelDensity||1;e.ctx.drawImage(r,t*c,n*c,i*c,a*c,o,s,l,d),e.modified=e._retint=!0},e.copy=()=>{let t=e.get();for(let r in e)"function"==typeof e[r]||/(canvas|ctx|texture)/.test(r)||(t[r]=e[r]);return t},e.get=(t,n,a,o)=>{let s=e._pixelDensity||1;if(void 0!==t&&void 0===a){i||e.loadPixels();let a=Math.floor(t*s),o=4*(Math.floor(n*s)*r.width+a);return[i[o],i[o+1],i[o+2],i[o+3]]}t=Math.floor(t||0)*s,n=Math.floor(n||0)*s,a??=e.width,o??=e.height;let l=e.createImage(a,o,{pixelDensity:s});return l.ctx.drawImage(r,t,n,a*s,o*s,0,0,a,o),l.width=a,l.height=o,e._owner?._makeDrawable&&e._owner._makeDrawable(l),l},e.set=(t,n,a)=>{if(t=Math.floor(t),n=Math.floor(n),e.modified=e._retint=!0,a.canvas){let r=e._tint;return e._tint=null,e.image(a,t,n),void(e._tint=r)}i||e.loadPixels();let o=e._pixelDensity||1,s=a.r,l=a.g,d=a.b,c=a.a;1==(e._colorFormat||e._owner?._colorFormat)&&(s*=255,l*=255,d*=255,c*=255);for(let e=0;e<o;e++)for(let a=0;a<o;a++){let u=4*((n*o+e)*r.width+t*o+a);i[u]=s,i[u+1]=l,i[u+2]=d,i[u+3]=c}},e.loadPixels=()=>{n=e._getImageData(0,0,r.width,r.height),t.pixels=i=n.data},e.updatePixels=()=>{null!=n&&(e.ctx.putImageData(n,0,0),e.modified=e._retint=!0)},e.smooth=()=>e.ctx.imageSmoothingEnabled=!0,e.noSmooth=()=>e.ctx.imageSmoothingEnabled=!1,e._isImage||(e.tint=function(t){e._tint=(t._isColor?t:e.color(...arguments)).toString()},e.noTint=()=>e._tint=null)},Q5.Image=class{constructor(e,t,r={}){r.alpha??=!0,r.colorSpace??=Q5.canvasOptions.colorSpace;let n=this;n._isImage=!0,n.canvas=n.ctx=n.drawingContext=null,n.pixels=[],Q5.modules.canvas(n,n);let i=Q5.renderers.c2d;for(let e of["canvas","image","softFilters"])i[e]&&i[e](n,n);n._pixelDensity=r.pixelDensity||1,n._defaultImageScale=r.defaultImageScale||2,n.createCanvas(e,t,r);let a=n._pixelDensity*n._defaultImageScale;n.defaultWidth=e*a,n.defaultHeight=t*a,delete n.createCanvas,n._loop=!1}get w(){return this.width}get h(){return this.height}},Q5.renderers.c2d.softFilters=e=>{let t=null;function r(){let r=e.canvas.width*e.canvas.height*4;t&&t.length==r||(t=new Uint8ClampedArray(r))}e._softFilter=(n,i)=>{e._filters||(e._filters=[],e._filters[Q5.THRESHOLD]=(e,t)=>{void 0===t?t=127.5:t*=255;for(let r=0;r<e.length;r+=4){const n=.2126*e[r]+.7152*e[r+1]+.0722*e[r+2];e[r]=e[r+1]=e[r+2]=n>=t?255:0}},e._filters[Q5.GRAY]=e=>{for(let t=0;t<e.length;t+=4){const r=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];e[t]=e[t+1]=e[t+2]=r}},e._filters[Q5.OPAQUE]=e=>{for(let t=0;t<e.length;t+=4)e[t+3]=255},e._filters[Q5.INVERT]=e=>{for(let t=0;t<e.length;t+=4)e[t]=255-e[t],e[t+1]=255-e[t+1],e[t+2]=255-e[t+2]},e._filters[Q5.POSTERIZE]=(e,t=4)=>{let r=t-1;for(let n=0;n<e.length;n+=4)e[n]=255*(e[n]*t>>8)/r,e[n+1]=255*(e[n+1]*t>>8)/r,e[n+2]=255*(e[n+2]*t>>8)/r},e._filters[Q5.DILATE]=(n,i)=>{i??=Math.max,r(),t.set(n);let[a,o]=[e.canvas.width,e.canvas.height];for(let e=0;e<o;e++)for(let r=0;r<a;r++){let s=4*Math.max(r-1,0),l=4*Math.min(r+1,a-1),d=4*Math.max(e-1,0)*a,c=4*Math.min(e+1,o-1)*a,u=4*e*a,h=4*r;for(let e=0;e<4;e++){let r=e+d,a=e+c,o=e+u;n[u+h+e]=i(t[r+h],t[o+s],t[o+h],t[o+l],t[a+h])}}},e._filters[Q5.ERODE]=t=>{e._filters[Q5.DILATE](t,Math.min)},e._filters[Q5.BLUR]=(n,i)=>{i=i||1,i=Math.floor(i*e._pixelDensity),r(),t.set(n);let a=2*i+1,o=function(e){let t=new Float32Array(e),r=.3*i+.8,n=r*r*2;for(let i=0;i<e;i++){let a=i-e/2,o=Math.exp(-a*a/n)/(2.5066282746*r);t[i]=o}return t}(a),[s,l]=[e.canvas.width,e.canvas.height];for(let e=0;e<l;e++)for(let r=0;r<s;r++){let l=0,d=0,c=0,u=0;for(let n=0;n<a;n++){let a=4*(e*s+Math.min(Math.max(r-i+n,0),s-1));l+=t[a]*o[n],d+=t[a+1]*o[n],c+=t[a+2]*o[n],u+=t[a+3]*o[n]}let h=4*(e*s+r);n[h]=l,n[h+1]=d,n[h+2]=c,n[h+3]=u}t.set(n);for(let e=0;e<l;e++)for(let r=0;r<s;r++){let d=0,c=0,u=0,h=0;for(let n=0;n<a;n++){let a=4*(Math.min(Math.max(e-i+n,0),l-1)*s+r);d+=t[a]*o[n],c+=t[a+1]*o[n],u+=t[a+2]*o[n],h+=t[a+3]*o[n]}let f=4*(e*s+r);n[f]=d,n[f+1]=c,n[f+2]=u,n[f+3]=h}});let a=e._getImageData(0,0,e.canvas.width,e.canvas.height);e._filters[n](a.data,i),e.ctx.putImageData(a,0,0)}},Q5.renderers.c2d.text=(e,t)=>{e._textAlign="left",e._textBaseline="alphabetic",e._textSize=12;let r="sans-serif",n=!1,i=15,a=3,o="normal",s="normal",l=0,d=!1,c=0;e._fontMod=!1;let u=e._textCache={};e.loadFont=(t,r)=>{let n;if(t.includes("fonts.googleapis.com/css"))n=function(e,t){e.startsWith("http")||(e="https://"+e);const r=new URL(e).searchParams,n=r.get("family");if(!n)return console.error("Invalid Google Fonts URL: missing family parameter"),null;const i=n.split(":")[0];let a={family:i};return a.promise=(async()=>{try{const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch Google Font: ${r.status} ${r.statusText}`);let n,o=await r.text(),s=/@font-face\s*{([^}]*)}/g,l=/src:\s*url\(([^)]+)\)[^;]*;/,d=/font-family:\s*['"]([^'"]+)['"]/,c=/font-weight:\s*([^;]+);/,u=/font-style:\s*([^;]+);/,h=[];for(;null!==(n=s.exec(o));){let e=n[1],t=l.exec(e);if(!t)continue;let r=t[1],i=d.exec(e);if(!i)continue;let a=i[1],o=c.exec(e),s=o?o[1]:"400",f=u.exec(e),p=f?f[1]:"normal",g=`${a}-${s}-${p}`.replace(/\s+/g,"-"),m=new FontFace(a,`url(${r})`,{weight:s,style:p});document.fonts.add(m);try{await m.load(),h.push(m)}catch(e){console.error(`Failed to load font face: ${g}`,e)}}return a._usedAwait&&(a={family:i}),a.faces=h,delete a.then,t&&t(a),a}catch(e){throw console.error("Error loading Google Font:",e),e}})(),a}(t,r);else{let e=t.split("/").pop().split(".")[0].replace(" ","");n={family:e};let i=new FontFace(e,`url(${encodeURI(t)})`);document.fonts.add(i),n.promise=new Promise(((e,t)=>{i.load().then((()=>{delete n.then,r&&r(i),e(i)})).catch((e=>{t(e)}))}))}return e._loaders.push(n.promise),e.textFont(n.family),n.then=(e,t)=>(n._usedAwait=!0,n.promise.then(e,t)),n},e.textFont=t=>{if(t&&"string"!=typeof t&&(t=t.family),!t||t==r)return r;r=t,e._fontMod=!0,l=-1},e.textSize=t=>{if(null==t)return e._textSize;e._textSize=t,e._fontMod=!0,l=-1,n||(i=1.25*t,a=i-t)},e.textStyle=t=>{if(!t)return o;o=t,e._fontMod=!0,l=-1},e.textWeight=t=>{if(!t)return s;s=t,e._fontMod=!0,l=-1},e.textLeading=t=>null==t?i||1.25*e._textSize:(n=!0,t==i?i:(i=t,a=t-e._textSize,void(l=-1))),e.textAlign=(t,r)=>{e.ctx.textAlign=e._textAlign=t,r&&(e.ctx.textBaseline=e._textBaseline=r==e.CENTER?"middle":r)},e._updateFont=()=>{e.ctx.font=`${o} ${s} ${e._textSize}px ${r}`,e._fontMod=!1},e.textWidth=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).width),e.textAscent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxAscent),e.textDescent=t=>(e._fontMod&&e._updateFont(),e.ctx.measureText(t).actualBoundingBoxDescent),e.textFill=e.fill,e.textStroke=e.stroke;e.createTextImage=(t,r,n)=>{d=!0;let i=e.text(t,0,0,r,n);return d=!1,i};let h=[];e.text=(t,n,s,f,p)=>{if(void 0===t||!e._doFill&&!e._doStroke)return;t=t.toString();let g,m,_,x,v,b,y,w,S=e.ctx;if(e._fontMod&&e._updateFont(),d)if(-1==l&&(()=>{let t=r+e._textSize+o+i,n=5381;for(let e=0;e<t.length;e++)n=33*n^t.charCodeAt(e);l=n>>>0})(),m=e._fill+e._stroke+e._strokeWeight,_=u[t],_?x=_[l]:_=u[t]={},x){if(g=x[m],g)return g;if(x.size>=4){for(let e in x){g=x[e],delete x[e];break}v=!0}}else x=_[l]={};if(-1==t.indexOf("\n")?h[0]=t:h=t.split("\n"),t.length>f){let e=[];for(let t of h){let r=0;for(;r<t.length;){let n=r+f;if(n>=t.length){e.push(t.slice(r));break}let i=t.lastIndexOf(" ",n);(-1===i||i<r)&&(i=n),e.push(t.slice(r,i)),r=i+1}}h=e}if(d){if(b=0,y=i,g){let e=g.canvas;g.ctx.clearRect(0,0,e.width,e.height),g.modified=!0}else{let t=e.ctx.textBaseline;e.ctx.textBaseline="alphabetic";let r=S.measureText(" "),n=r.fontBoundingBoxAscent,o=r.fontBoundingBoxDescent;e.ctx.textBaseline=t;let s=0;for(let e of h){let t=S.measureText(e).width;t>s&&(s=t)}let l=Math.ceil(s),d=Math.ceil(i*h.length+o);g=e.createImage.call(e,l,d,{pixelDensity:e._pixelDensity,defaultImageScale:1/e._pixelDensity}),g._ascent=n,g._descent=o,g._top=o+a,g._middle=g._top+.5*n+i*(h.length-1)*.5,g._bottom=g._top+n+i*(h.length-1),g._leading=i}S=g.ctx,S.font=e.ctx.font,S.fillStyle=e._fill,S.strokeStyle=e._stroke,S.lineWidth=e.ctx.lineWidth}else b=n,y=s,"middle"==e._textBaseline?y-=i*(h.length-1)*.5:"bottom"==e._textBaseline&&(y-=i*(h.length-1));e._fillSet||(w=S.fillStyle,S.fillStyle="black");let Q=0;for(let t of h)if(e._doStroke&&e._strokeSet&&S.strokeText(t,b,y),e._doFill&&S.fillText(t,b,y),y+=i,Q++,Q>=p)break;if(h=[],e._fillSet||(S.fillStyle=w),d){if(x[m]=g,v||(x.size||(Object.defineProperty(x,"size",{writable:!0,enumerable:!1}),x.size=0),x.size++,c++),c>Q5.MAX_TEXT_IMAGES){for(const e in u){_=u[e];for(const e in _){x=_[e];for(let e in x){let t=x[e];t._texture&&t._texture.destroy(),delete x[e]}}}c=0}return g}},e.textImage=(t,r,n)=>{"string"==typeof t&&(t=e.createTextImage(t));let i=e._imageMode;e._imageMode="corner";let a=e._textAlign;"center"==a?r-=t.canvas.hw:"right"==a&&(r-=t.width);let o=e._textBaseline;"alphabetic"==o?n-=t._leading:"middle"==o?n-=t._middle:"bottom"==o?n-=t._bottom:"top"==o&&(n-=t._top),e.image(t,r,n),e._imageMode=i}},Q5.fonts=[],Q5.MAX_TEXT_IMAGES=5e3,Q5.modules.color=(e,t)=>{e.RGB=e.RGBA=e.RGBHDR=e._colorMode="rgb",e.HSL="hsl",e.HSB="hsb",e.OKLCH="oklch",e.SRGB="srgb",e.DISPLAY_P3="display-p3",e.colorMode=(r,n,i)=>{e._colorMode=r;let a="srgb"==e.canvas.colorSpace||"srgb"==i;e._srgb=a,n??="rgb"==r&&(e._c2d||a)?255:1,e._colorFormat="integer"==n||255==n?255:1,"oklch"==r?t.Color=Q5.ColorOKLCH:"hsl"==r?t.Color=a?Q5.ColorHSL:Q5.ColorHSL_P3:"hsb"==r?t.Color=a?Q5.ColorHSB:Q5.ColorHSB_P3:(255==e._colorFormat?t.Color=a?Q5.ColorRGB_8:Q5.ColorRGB_P3_8:t.Color=a?Q5.ColorRGB:Q5.ColorRGB_P3,e._colorMode="rgb")},e._namedColors={aqua:[0,255,255],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],coral:[255,127,80],crimson:[220,20,60],cyan:[0,255,255],darkviolet:[148,0,211],gold:[255,215,0],green:[0,128,0],gray:[128,128,128],grey:[128,128,128],hotpink:[255,105,180],indigo:[75,0,130],khaki:[240,230,140],lightgreen:[144,238,144],lime:[0,255,0],magenta:[255,0,255],navy:[0,0,128],orange:[255,165,0],olive:[128,128,0],peachpuff:[255,218,185],pink:[255,192,203],purple:[128,0,128],red:[255,0,0],silver:[192,192,192],skyblue:[135,206,235],tan:[210,180,140],turquoise:[64,224,208],transparent:[0,0,0,0],white:[255,255,255],violet:[238,130,238],yellow:[255,255,0]},e.color=(t,r,n,i)=>{let a=e.Color;if(t._isColor)return new a(...t.levels);if(null==r){if("string"==typeof t){if("#"==t[0])t.length<=5?(t.length>4&&(i=parseInt(t[4]+t[4],16)),n=parseInt(t[3]+t[3],16),r=parseInt(t[2]+t[2],16),t=parseInt(t[1]+t[1],16)):(t.length>7&&(i=parseInt(t.slice(7,9),16)),n=parseInt(t.slice(5,7),16),r=parseInt(t.slice(3,5),16),t=parseInt(t.slice(1,3),16));else{if(!e._namedColors[t]){let e=new a(0,0,0);return e._css=t,e.toString=function(){return this._css},e}if([t,r,n,i]=e._namedColors[t],"rgb"!=e._colorMode)return a=e._srgb?Q5.ColorRGB_8:Q5.ColorRGB_P3_8,new a(t,r,n,i)}1==e._colorFormat&&(t/=255,r&&(r/=255),n&&(n/=255),i&&(i/=255))}(Array.isArray(t)||t.constructor==Float32Array)&&([t,r,n,i]=t)}return null==n?e._colorMode==Q5.OKLCH?new a(t,0,0,r):new a(t,t,t,r):new a(t,r,n,i)},e.red=e=>e.r,e.green=e=>e.g,e.blue=e=>e.b,e.alpha=e=>e.a,e.lightness=t=>{if(t.l)return t.l;let r=100*(.2126*t.r+.7152*t.g+.0722*t.b);return 255==e._colorFormat?r/255:r},e.hue=t=>{if(t.h)return t.h;let r=t.r,n=t.g,i=t.b;255==e._colorFormat&&(r/=255,n/=255,i/=255);let a,o=Math.max(r,n,i),s=Math.min(r,n,i);return a=o==s?0:o==r?60*(n-i)/(o-s):o==n?60*(i-r)/(o-s)+120:60*(r-n)/(o-s)+240,a<0&&(a+=360),a},e.lerpColor=(t,r,n)=>{if(n=Math.max(0,Math.min(1,n)),"rgb"==e._colorMode)return new e.Color(e.lerp(t.r,r.r,n),e.lerp(t.g,r.g,n),e.lerp(t.b,r.b,n),e.lerp(t.a,r.a,n));{let i=r.h-t.h;i>180&&(i-=360),i<-180&&(i+=360);let a=t.h+n*i;return a<0&&(a+=360),a>360&&(a-=360),new e.Color(e.lerp(t.l,r.l,n),e.lerp(t.c,r.c,n),a,e.lerp(t.a,r.a,n))}}},Q5.Color=class{constructor(){this._isColor=!0,this._q5Color=!0}get alpha(){return this.a}set alpha(e){this.a=e}},Q5.ColorOKLCH=class extends Q5.Color{constructor(e,t,r,n){super(),this.l=e,this.c=t,this.h=r,this.a=n??1}get levels(){return[this.l,this.c,this.h,this.a]}equals(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h&&this.a==e.a}isSameColor(e){return e&&this.l==e.l&&this.c==e.c&&this.h==e.h}toString(){return`oklch(${this.l} ${this.c} ${this.h} / ${this.a})`}get lightness(){return this.l}set lightness(e){this.l=e}get chroma(){return this.c}set chroma(e){this.c=e}get hue(){return this.h}set hue(e){this.h=e}},Q5.ColorRGB=class extends Q5.Color{constructor(e,t,r,n){super(),this.r=e,this.g=t,this.b=r,this.a=n??1}get levels(){return[this.r,this.g,this.b,this.a]}equals(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.r==e.r&&this.g==e.g&&this.b==e.b}toString(){return`color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`}get red(){return this.r}set red(e){this.r=e}get green(){return this.g}set green(e){this.g=e}get blue(){return this.b}set blue(e){this.b=e}},Q5.ColorRGB_P3=class extends Q5.ColorRGB{toString(){return`color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`}},Q5.ColorRGB_8=class extends Q5.ColorRGB{constructor(e,t,r,n){super(e,t,r,n??255)}setRed(e){this.r=e}setGreen(e){this.g=e}setBlue(e){this.b=e}setAlpha(e){this.a=e}toString(){return`rgb(${this.r} ${this.g} ${this.b} / ${this.a/255})`}},Q5.ColorRGB_P3_8=class extends Q5.ColorRGB_8{constructor(e,t,r,n){super(e,t,r,n??255),this._edited=!0}get r(){return this._r}set r(e){this._r=e,this._edited=!0}get g(){return this._g}set g(e){this._g=e,this._edited=!0}get b(){return this._b}set b(e){this._b=e,this._edited=!0}get a(){return this._a}set a(e){this._a=e,this._edited=!0}toString(){if(this._edited){let e=(this._r/255).toFixed(3),t=(this._g/255).toFixed(3),r=(this._b/255).toFixed(3),n=(this._a/255).toFixed(3);this._css=`color(display-p3 ${e} ${t} ${r} / ${n})`,this._edited=!1}return this._css}},Q5.ColorHSL=class extends Q5.Color{constructor(e,t,r,n){super(),this.h=e,this.s=t,this.l=r,this.a=n??1}get levels(){return[this.h,this.s,this.l,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.l==e.l}toString(){return`hsl(${this.h} ${this.s} ${this.l} / ${this.a})`}get hue(){return this.h}set hue(e){this.h=e}get saturation(){return this.s}set saturation(e){this.s=e}get lightness(){return this.l}set lightness(e){this.l=e}},Q5.ColorHSL_P3=class extends Q5.ColorHSL{toString(){return`color(display-p3 ${Q5.HSLtoRGB(this.h,this.s,this.l).join(" ")} / ${this.a})`}},Q5.ColorHSB=class extends Q5.ColorHSL{constructor(e,t,r,n){super(e,t,r,n),delete this.l,this.b=r}get levels(){return[this.h,this.s,this.b,this.a]}equals(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b&&this.a==e.a}isSameColor(e){return e&&this.h==e.h&&this.s==e.s&&this.b==e.b}toString(){return`hsl(${Q5.HSBtoHSL(this.h,this.s,this.b).join(" ")} / ${this.a})`}get v(){return this.b}set v(e){this.b=e}get brightness(){return this.b}set brightness(e){this.b=e}get value(){return this.b}set value(e){this.b=e}},Q5.ColorHSB_P3=class extends Q5.ColorHSB{toString(){return`color(display-p3 ${Q5.HSLtoRGB(...Q5.HSBtoHSL(this.h,this.s,this.b)).join(" ")} / ${this.a})`}},Q5.HSLtoRGB=(e,t,r)=>{r/=100;let n=t/100*Math.min(r,1-r),i=(t,i=(t+e/30)%12)=>r-n*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]},Q5.HSBtoHSL=(e,t,r,n=r*(1-t/200))=>[e,n&&100!=n?(r-n)/Math.min(n,100-n)*100:0,n];{const e=(e,t)=>[e[0]*t[0]+e[1]*t[1]+e[2]*t[2],e[3]*t[0]+e[4]*t[1]+e[5]*t[2],e[6]*t[0]+e[7]*t[1]+e[8]*t[2]],t=(e,t,r)=>[e,isNaN(r)?0:t*Math.cos(r*Math.PI/180),isNaN(r)?0:t*Math.sin(r*Math.PI/180)],r=e=>e.map((e=>Math.max(0,Math.min(1,Math.abs(e)>.0031308?(e<0?-1:1)*(1.055*Math.abs(e)**(1/2.4)-.055):12.92*e)))),n=t=>{const r=e([1,.3963377773761749,.2158037573099136,1,-.1055613458156586,-.0638541728258133,1,-.0894841775298119,-1.2914855480194092],t);return e([1.2268798758459243,-.5578149944602171,.2813910456659647,-.0405757452148008,1.112286803280317,-.0717110580655164,-.0763729366746601,-.4214933324022432,1.5869240198367816],r.map((e=>e**3)))},i=t=>e([3.2409699419045226,-1.537383177570094,-.4986107602930034,-.9692436362808796,1.8759675015077202,.04155505740717559,.05563007969699366,-.20397695888897652,1.0569715142428786],t);Q5.OKLCHtoRGB=(e,a,o)=>r(i(n(t(e,a,o))))}Q5.modules.display=e=>{if(!e.canvas||e._isGraphics)return;let t=e.canvas;e.MAXED="maxed",e.SMOOTH="smooth",e.PIXELATED="pixelated",0!=Q5._instanceCount||Q5._server||document.head.insertAdjacentHTML("beforeend","<style>\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\n.q5Canvas {\n\toutline: none;\n\t-webkit-touch-callout: none;\n\t-webkit-text-size-adjust: none;\n\t-webkit-user-select: none;\n\toverscroll-behavior: none;\n}\n.q5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.q5-centered,\n.q5-maxed {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.q5-centered,\nmain.q5-maxed {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>"),e._adjustDisplay=e=>{let r=t.style;if(r)if("normal"==t.displayMode){if(!e)return;r.width=t.w*t.displayScale+"px",r.height=t.h*t.displayScale+"px"}else{let e=t.parentElement.getBoundingClientRect();t.w/t.h>e.width/e.height?("centered"==t.displayMode?(r.width=t.w*t.displayScale+"px",r.maxWidth="100%"):r.width="100%",r.height="auto",r.maxHeight=""):(r.width="auto",r.maxWidth="","centered"==t.displayMode?(r.height=t.h*t.displayScale+"px",r.maxHeight="100%"):r.height="100%")}},e.displayMode=(r="normal",n="smooth",i=1)=>{Q5._server||("string"==typeof i&&(i=parseFloat(i.slice(1))),"fullscreen"==r&&(r="maxed"),"center"==r&&(r="centered"),t.displayMode&&(t.parentElement.classList.remove("q5-"+t.displayMode),t.classList.remove("q5-pixelated")),t.parentElement.classList.add("q5-"+r),"pixelated"==n&&(t.classList.add("q5-pixelated"),e.pixelDensity(1),e.defaultImageScale(1),e.noSmooth&&e.noSmooth(),e.textFont&&e.textFont("monospace")),Object.assign(t,{displayMode:r,renderQuality:n,displayScale:i}),e.ctx&&e.pushStyles(),e._adjustDisplay(!0),e.ctx&&e.popStyles())},e.fullscreen=e=>{if(null==e)return document.fullscreenElement;e?document.body.requestFullscreen():document.exitFullscreen()}},Q5.modules.dom=(e,t)=>{e.elementMode=t=>e._elementMode=t,e.createElement=(t,r)=>{let n=document.createElement(t);return"center"==e._elementMode&&(n.style.transform="translate(-50%, -50%)"),r&&(n.innerHTML=r),Object.defineProperty(n,"x",{get:()=>n._x,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetLeft+t;n.style.left=i+"px",n._x=i}}),Object.defineProperty(n,"y",{get:()=>n._y,set:t=>{let r=n.style.position;r&&"relative"!=r||(n.style.position="absolute");let i=e.canvas.offsetTop+t;n.style.top=i+"px",n._y=i}}),Object.defineProperty(n,"width",{get:()=>parseFloat(n.style.width||0),set:e=>n.style.width=e+"px"}),Object.defineProperty(n,"height",{get:()=>parseFloat(n.style.height||0),set:e=>n.style.height=e+"px"}),n.position=(e,t,r)=>(r&&(n.style.position=r),n.x=e,n.y=t,n),Object.defineProperty(n,"size",{writable:!0}),n.size=(e,t)=>(n.width=e,n.height=t,n),n.center=()=>(n.style.position="absolute",n.x=e.canvas.hw,n.y=e.canvas.hh,n),n.show=()=>(n.style.display="",n),n.hide=()=>(n.style.display="none",n),n.parent=e=>(e.append(n),n),e._addEventMethods(n),e._elements.push(n),e.canvas?e.canvas.parentElement.append(n):document.body.append(n),n.elt=n,n},e.createEl=e.createElement,e._addEventMethods=e=>{let t=e.addEventListener;e.mousePressed=e=>t("mousedown",e),e.mouseReleased=e=>t("mouseup",e),e.mouseClicked=e=>t("click",e),e.mouseMoved=e=>t("mousemove",e),e.mouseWheel=e=>t("wheel",e)},e.createA=(t,r,n)=>{let i=e.createEl("a",r);return i.href=t,i.target=n?"_blank":"_self",i},e.createButton=t=>e.createEl("button",t),e.createCheckbox=(t="",r=!1)=>{let n=e.createEl("input");n.type="checkbox",n.checked=r;let i=e.createEl("label",t);return i.addEventListener("click",(()=>{n.checked=!n.checked,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))})),n.insertAdjacentElement("afterend",i),n.label=i,n},e.createColorPicker=(t="#ffffff")=>{let r=e.createEl("input");return r.type="color",r.value=t.toString(),r},e.createDiv=t=>e.createEl("div",t),e.createImg=t=>{let r=e.createEl("img");return r.crossOrigin="anonymous",r.src=t,r},e.createInput=(t="",r="text")=>{let n=e.createEl("input");return n.value=t,n.type=r,n.style.boxSizing="border-box",n},e.createP=t=>e.createEl("p",t);let r=0;function n(t){t.width||=t.videoWidth,t.height||=t.videoHeight,t.defaultWidth=t.width*e._defaultImageScale,t.defaultHeight=t.height*e._defaultImageScale,t.ready=!0}e.createRadio=t=>{let n=e.createEl("div");return n.name=t||"radio"+r++,n.buttons=[],Object.defineProperty(n,"value",{get:()=>n.selected?.value,set:e=>{let t=n.buttons.find((t=>t.value==e));t&&(t.checked=!0,n.selected=t)}}),n.option=(t,r)=>{let i=e.createEl("input");i.type="radio",i.name=n.name,i.value=r||t,i.addEventListener("input",(()=>n.selected=i));let a=e.createEl("label",t);return a.addEventListener("click",(()=>{i.checked=!0,n.selected=i,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0}))})),i.label=a,n.append(i),n.append(a),n.buttons.push(i),n},n},e.createSelect=t=>{let r=e.createEl("select");if(t){let n=e.createEl("option",t);n.disabled=!0,n.selected=!0,r.append(n)}return Object.defineProperty(r,"selected",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.textContent)):r.selectedOptions[0]?.textContent,set:e=>{if(r.multiple)Array.from(r.options).forEach((t=>{t.selected=e.includes(t.textContent)}));else{const t=Array.from(r.options).find((t=>t.textContent===e));t&&(t.selected=!0)}}}),Object.defineProperty(r,"value",{get:()=>r.multiple?Array.from(r.selectedOptions).map((e=>e.value)):r.selectedOptions[0]?.value,set:e=>{if(r.multiple)r.options.forEach((t=>t.selected=e.includes(t.value)));else{let t;for(let n=0;n<r.options.length;n++)if(r.options[n].value==e){t=r.options[n];break}t&&(t.selected=!0)}}}),r.option=(t,n)=>{let i=e.createEl("option",t);return i.value=n||t,r.append(i),r},r},e.createSlider=(t,r,n,i)=>{let a=e.createEl("input");return a.type="range",a.min=t,a.max=r,a.step=i,a.value=n,a.val=()=>parseFloat(a.value),a},e.createSpan=t=>e.createEl("span",t),e.createVideo=t=>{let r=e.createEl("video");return r.crossOrigin="anonymous",t&&(r.promise=new Promise((i=>{r.addEventListener("loadeddata",(()=>{delete r.then,r._usedAwait&&(r=e.createEl("video"),r.crossOrigin="anonymous",r.src=t),n(r),i(r)})),r.src=t})),e._loaders.push(r.promise),r.then=(e,t)=>(r._usedAwait=!0,r.promise.then(e,t))),r},e.createCapture=function(t,r=!0,i){let a="string"==typeof t?{[t]:!0}:t||{video:!0,audio:!0};!0===a.video&&(a.video={width:3840,height:2160}),a.video.facingMode??="user";let o=e.createVideo();return o.promise=(async()=>{let t;try{t=await navigator.mediaDevices.getUserMedia(a)}catch(e){throw e}return delete o.then,o._usedAwait&&(o=e.createVideo()),function(t){t.playsinline=t.autoplay=!0,r&&(t.flipped=!0,t.style.transform="scale(-1, 1)"),t.loadPixels=()=>{let r=e.createGraphics(t.videoWidth,t.videoHeight,{renderer:"c2d"});r.image(t,0,0),r.loadPixels(),t.pixels=r.pixels,r.remove()}}(o),o.srcObject=t,await new Promise((e=>o.addEventListener("loadeddata",e))),n(o),i&&i(o),o})(),e._loaders.push(o.promise),o.then=(e,t)=>(o._usedAwait=!0,o.promise.then(e,t)),o},e.findElement=e=>document.querySelector(e),e.findElements=e=>document.querySelectorAll(e)},Q5.modules.fes=e=>{if(e._fes=async t=>{if(Q5.disableFriendlyErrors)return;t._handledByFES=!0;let r=t.stack?.split("\n");if(!r?.length)return;let n=1,i="(";for(-1==navigator.userAgent.indexOf("Chrome")&&(n=0,i="@");r[n].indexOf("q5")>=0;)n++;let a=r[n].split(i).at(-1);a.startsWith("blob:")&&(a=a.slice(5)),a=a.split(")")[0];let o=a.split(":"),s=parseInt(o.at(-2));o[o.length-1]=o.at(-1).split(")")[0];let l=t.file||o.slice(0,-2).join(":"),d=l.split("/").at(-1);try{let t=(await(await fetch(l)).text()).split("\n"),r=t[s-1]?.trim()??"",n=["🐛","🐞","🐜","🦗","🦋","🪲"][Math.floor(6*Math.random())],i=window.self!==window.top,a=`q5.js ${n}`,o=` Error in ${d} on line ${s}:\n\n${r}`;i?e.log(a+o):e.log(`%c${a}%c${o}`,"background: #b7ebff; color: #000;","")}catch(e){}},"undefined"!=typeof window&&window.addEventListener){let t=new Error,r=t.stack?.split("\n")||"";for(let t of r){let r=t.match(/(https?:\/\/[^\s)]+\.js|\b\/[^\s)]+\.js)/);if(r){let t=r[1];if(!/q5|p5play/i.test(t)){e._sketchFile=t;break}}}e._sketchFile&&(window.addEventListener("error",(t=>{let r=t.error;t.filename!==e._sketchFile||r?._handledByFES||(r.file=t.filename,e._fes(r))})),window.addEventListener("unhandledrejection",(t=>{let r=t.reason;r?.stack?.includes(e._sketchFile)&&!r?._handledByFES&&e._fes(r)})))}if(e._isGlobal&&0!=Q5.online&&null!=typeof navigator&&navigator.onLine){!async function(){try{let e=await fetch("https://data.jsdelivr.com/v1/package/npm/q5");if(!e.ok)return;let t=(await e.json()).tags.latest;t=t.slice(0,t.lastIndexOf(".")),t!=Q5.version&&console.warn(`q5.js v${t} is now available! Consider updating from v${Q5.version}.`)}catch(e){}}()}},Q5.modules.input=(e,t)=>{if(e._isGraphics)return;e.mouseX=0,e.mouseY=0,e.pmouseX=0,e.pmouseY=0,e.touches=[],e.pointers={},e.mouseButton="",e.keyIsPressed=!1,e.mouseIsPressed=!1,e.key="",e.keyCode=0,e.UP_ARROW=38,e.DOWN_ARROW=40,e.LEFT_ARROW=37,e.RIGHT_ARROW=39,e.SHIFT=16,e.TAB=9,e.BACKSPACE=8,e.ENTER=e.RETURN=13,e.ALT=e.OPTION=18,e.CONTROL=17,e.DELETE=46,e.ESCAPE=27,e.ARROW="default",e.CROSS="