7 lines
228 KiB
Text
7 lines
228 KiB
Text
{
|
|
"version": 3,
|
|
"sources": ["../src/kaboom.ts", "../src/utils.ts", "../src/math.ts", "../src/fps.ts", "../src/timer.ts"],
|
|
"sourcesContent": ["import {\n\tvec2,\n\tvec3,\n\tVec3,\n\tRect,\n\tLine,\n\tCircle,\n\tColor,\n\tVec2,\n\tMat4,\n\tQuad,\n\tRNG,\n\tquad,\n\trgb,\n\thsl2rgb,\n\trng,\n\trand,\n\trandi,\n\trandSeed,\n\tchance,\n\tchoose,\n\tclamp,\n\tlerp,\n\tmap,\n\tmapc,\n\twave,\n\ttestAreaRect,\n\ttestAreaLine,\n\ttestAreaCircle,\n\ttestAreaPolygon,\n\ttestAreaPoint,\n\ttestAreaArea,\n\ttestLineLineT,\n\ttestRectRect2,\n\ttestLineLine,\n\ttestRectRect,\n\ttestRectLine,\n\ttestRectPoint,\n\ttestPolygonPoint,\n\ttestLinePolygon,\n\ttestPolygonPolygon,\n\ttestCircleCircle,\n\ttestCirclePoint,\n\ttestRectPolygon,\n\tminkDiff,\n\tdeg2rad,\n\trad2deg,\n} from \"./math\";\n\nimport {\n\tIDList,\n\tdownloadURL,\n\tdownloadBlob,\n\tuid,\n\tdeprecate,\n\tdeprecateMsg,\n\tisDataURL,\n\tdeepEq,\n} from \"./utils\";\n\nimport {\n\tGfxShader,\n\tGfxFont,\n\tTexFilter,\n\tRenderProps,\n\tCharTransform,\n\tCharTransformFunc,\n\tTexWrap,\n\tFormattedText,\n\tFormattedChar,\n\tDrawRectOpt,\n\tDrawLineOpt,\n\tDrawLinesOpt,\n\tDrawTriangleOpt,\n\tDrawPolygonOpt,\n\tDrawCircleOpt,\n\tDrawEllipseOpt,\n\tDrawUVQuadOpt,\n\tVertex,\n\tSpriteData,\n\tSoundData,\n\tFontData,\n\tShaderData,\n\tSpriteLoadSrc,\n\tSpriteLoadOpt,\n\tSpriteAtlasData,\n\tFontLoadOpt,\n\tGfxTexData,\n\tKaboomCtx,\n\tKaboomOpt,\n\tAudioPlay,\n\tAudioPlayOpt,\n\tDrawSpriteOpt,\n\tDrawTextOpt,\n\tGameObj,\n\tEventCanceller,\n\tSceneID,\n\tSceneDef,\n\tCompList,\n\tComp,\n\tTag,\n\tKey,\n\tMouseButton,\n\tTouchID,\n\tCollision,\n\tPosComp,\n\tScaleComp,\n\tRotateComp,\n\tColorComp,\n\tOpacityComp,\n\tOrigin,\n\tOriginComp,\n\tLayerComp,\n\tZComp,\n\tFollowComp,\n\tMoveComp,\n\tOutviewCompOpt,\n\tOutviewComp,\n\tCleanupCompOpt,\n\tCleanupComp,\n\tAreaCompOpt,\n\tAreaComp,\n\tArea,\n\tSpriteComp,\n\tSpriteCompOpt,\n\tGfxTexture,\n\tSpriteAnimPlayOpt,\n\tTextComp,\n\tTextCompOpt,\n\tRectComp,\n\tRectCompOpt,\n\tUVQuadComp,\n\tCircleComp,\n\tOutlineComp,\n\tTimerComp,\n\tBodyComp,\n\tBodyCompOpt,\n\tUniform,\n\tShaderComp,\n\tSolidComp,\n\tFixedComp,\n\tStayComp,\n\tHealthComp,\n\tLifespanComp,\n\tLifespanCompOpt,\n\tStateComp,\n\tDebug,\n\tKaboomPlugin,\n\tMergeObj,\n\tLevel,\n\tLevelOpt,\n\tCursor,\n\tRecording,\n\tKaboom,\n} from \"./types\";\n\nimport FPSCounter from \"./fps\";\nimport Timer from \"./timer\";\n\n// @ts-ignore\nimport apl386Src from \"./assets/apl386.png\";\n// @ts-ignore\nimport apl386oSrc from \"./assets/apl386o.png\";\n// @ts-ignore\nimport sinkSrc from \"./assets/sink.png\";\n// @ts-ignore\nimport sinkoSrc from \"./assets/sinko.png\";\n// @ts-ignore\nimport beanSrc from \"./assets/bean.png\";\n// @ts-ignore\nimport burpBytes from \"./assets/burp.mp3\";\n// @ts-ignore\nimport kaSrc from \"./assets/ka.png\";\n// @ts-ignore\nimport boomSrc from \"./assets/boom.png\";\n\ntype ButtonState =\n\t\"up\"\n\t| \"pressed\"\n\t| \"rpressed\"\n\t| \"down\"\n\t| \"released\"\n\t;\n\ntype DrawTextureOpt = RenderProps & {\n\ttex: GfxTexture,\n\twidth?: number,\n\theight?: number,\n\ttiled?: boolean,\n\tflipX?: boolean,\n\tflipY?: boolean,\n\tquad?: Quad,\n\torigin?: Origin | Vec2,\n}\n\ninterface GfxTexOpt {\n\tfilter?: TexFilter,\n\twrap?: TexWrap,\n}\n\n// translate these key names to a simpler version\nconst KEY_ALIAS = {\n\t\"ArrowLeft\": \"left\",\n\t\"ArrowRight\": \"right\",\n\t\"ArrowUp\": \"up\",\n\t\"ArrowDown\": \"down\",\n\t\" \": \"space\",\n};\n\n// according to https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button\nconst MOUSE_BUTTONS = [\n\t\"left\",\n\t\"middle\",\n\t\"right\",\n\t\"back\",\n\t\"forward\",\n];\n\n// don't trigger browser default event when these keys are pressed\nconst PREVENT_DEFAULT_KEYS = [\n\t\"space\",\n\t\"left\",\n\t\"right\",\n\t\"up\",\n\t\"down\",\n\t\"tab\",\n\t\"f1\",\n\t\"f2\",\n\t\"f3\",\n\t\"f4\",\n\t\"f5\",\n\t\"f6\",\n\t\"f7\",\n\t\"f8\",\n\t\"f9\",\n\t\"f10\",\n\t\"f11\",\n\t\"s\",\n];\n\n// some default charsets for loading bitmap fonts\nconst ASCII_CHARS = \" !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\";\nconst CP437_CHARS = \" \u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\u00B6\u00A7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00A2\u00A3\u00A5\u20A7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u2310\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\u00DF\u0393\u03C0\u03A3\u03C3\u00B5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\u00B1\u2265\u2264\u2320\u2321\u00F7\u2248\u00B0\u2219\u00B7\u221A\u207F\u00B2\u25A0\";\n\n// audio gain range\nconst MIN_GAIN = 0;\nconst MAX_GAIN = 3;\n\n// audio speed range\nconst MIN_SPEED = 0;\nconst MAX_SPEED = 3;\n\n// audio detune range\nconst MIN_DETUNE = -1200;\nconst MAX_DETUNE = 1200;\n\nconst DEF_ORIGIN = \"topleft\";\nconst DEF_GRAVITY = 1600;\nconst QUEUE_COUNT = 65536;\nconst BG_GRID_SIZE = 64;\n\nconst DEF_FONT = \"apl386o\";\nconst DBG_FONT = \"sink\";\n\n// vertex format stride (vec3 pos, vec2 uv, vec4 color)\nconst STRIDE = 9;\n\n// vertex shader template, replace {{user}} with user vertex shader code\nconst VERT_TEMPLATE = `\nattribute vec3 a_pos;\nattribute vec2 a_uv;\nattribute vec4 a_color;\n\nvarying vec3 v_pos;\nvarying vec2 v_uv;\nvarying vec4 v_color;\n\nvec4 def_vert() {\n\treturn vec4(a_pos, 1.0);\n}\n\n{{user}}\n\nvoid main() {\n\tvec4 pos = vert(a_pos, a_uv, a_color);\n\tv_pos = a_pos;\n\tv_uv = a_uv;\n\tv_color = a_color;\n\tgl_Position = pos;\n}\n`;\n\n// fragment shader template, replace {{user}} with user fragment shader code\nconst FRAG_TEMPLATE = `\nprecision mediump float;\n\nvarying vec3 v_pos;\nvarying vec2 v_uv;\nvarying vec4 v_color;\n\nuniform sampler2D u_tex;\n\nvec4 def_frag() {\n\treturn v_color * texture2D(u_tex, v_uv);\n}\n\n{{user}}\n\nvoid main() {\n\tgl_FragColor = frag(v_pos, v_uv, v_color, u_tex);\n\tif (gl_FragColor.a == 0.0) {\n\t\tdiscard;\n\t}\n}\n`;\n\n// default {{user}} vertex shader code\nconst DEF_VERT = `\nvec4 vert(vec3 pos, vec2 uv, vec4 color) {\n\treturn def_vert();\n}\n`;\n\n// default {{user}} fragment shader code\nconst DEF_FRAG = `\nvec4 frag(vec3 pos, vec2 uv, vec4 color, sampler2D tex) {\n\treturn def_frag();\n}\n`;\n\nconst COMP_DESC = new Set([\n\t\"id\",\n\t\"require\",\n]);\n\nconst COMP_EVENTS = new Set([\n\t\"add\",\n\t\"load\",\n\t\"update\",\n\t\"draw\",\n\t\"destroy\",\n\t\"inspect\",\n]);\n\n// transform the button state to the next state\n// e.g. a button might become \"pressed\" one frame, and it should become \"down\" next frame\nfunction processButtonState(s: ButtonState): ButtonState {\n\tif (s === \"pressed\" || s === \"rpressed\") {\n\t\treturn \"down\";\n\t}\n\tif (s === \"released\") {\n\t\treturn \"up\";\n\t}\n\treturn s;\n}\n\n// wrappers around full screen functions to work across browsers\nfunction enterFullscreen(el: HTMLElement) {\n\tif (el.requestFullscreen) el.requestFullscreen();\n\t// @ts-ignore\n\telse if (el.webkitRequestFullscreen) el.webkitRequestFullscreen();\n};\n\nfunction exitFullscreen() {\n\tif (document.exitFullscreen) document.exitFullscreen();\n\t// @ts-ignore\n\telse if (document.webkitExitFullScreen) document.webkitExitFullScreen();\n};\n\nfunction getFullscreenElement(): Element | void {\n\treturn document.fullscreenElement\n\t\t// @ts-ignore\n\t\t|| document.webkitFullscreenElement\n\t\t;\n};\n\n// convert origin string to a vec2 offset\nfunction originPt(orig: Origin | Vec2): Vec2 {\n\tswitch (orig) {\n\t\tcase \"topleft\": return vec2(-1, -1);\n\t\tcase \"top\": return vec2(0, -1);\n\t\tcase \"topright\": return vec2(1, -1);\n\t\tcase \"left\": return vec2(-1, 0);\n\t\tcase \"center\": return vec2(0, 0);\n\t\tcase \"right\": return vec2(1, 0);\n\t\tcase \"botleft\": return vec2(-1, 1);\n\t\tcase \"bot\": return vec2(0, 1);\n\t\tcase \"botright\": return vec2(1, 1);\n\t\tdefault: return orig;\n\t}\n}\n\nfunction createEmptyAudioBuffer() {\n\treturn new AudioBuffer({\n\t\tlength: 1,\n\t\tnumberOfChannels: 1,\n\t\tsampleRate: 44100\n\t});\n}\n\n// only exports one kaboom() which contains all the state\nexport default (gopt: KaboomOpt = {}): KaboomCtx => {\n\nconst app = (() => {\n\n\tconst root = gopt.root ?? document.body;\n\n\t// if root is not defined (which falls back to <body>) we assume user is using kaboom on a clean page, and modify <body> to better fit a full screen canvas\n\tif (root === document.body) {\n\t\tdocument.body.style[\"width\"] = \"100%\";\n\t\tdocument.body.style[\"height\"] = \"100%\";\n\t\tdocument.body.style[\"margin\"] = \"0px\";\n\t\tdocument.documentElement.style[\"width\"] = \"100%\";\n\t\tdocument.documentElement.style[\"height\"] = \"100%\";\n\t}\n\n\t// create a <canvas> if user didn't provide one\n\tconst canvas = gopt.canvas ?? (() => {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\troot.appendChild(canvas);\n\t\treturn canvas;\n\t})();\n\n\t// global pixel scale\n\tconst gscale = gopt.scale ?? 1;\n\n\t// adjust canvas size according to user size / viewport settings\n\tif (gopt.width && gopt.height && !gopt.stretch && !gopt.letterbox) {\n\t\tcanvas.width = gopt.width * gscale;\n\t\tcanvas.height = gopt.height * gscale;\n\t} else {\n\t\tcanvas.width = canvas.parentElement.offsetWidth;\n\t\tcanvas.height = canvas.parentElement.offsetHeight;\n\t}\n\n\t// canvas css styles\n\tconst styles = [\n\t\t\"outline: none\",\n\t\t\"cursor: default\",\n\t];\n\n\tif (gopt.crisp) {\n\t\tstyles.push(\"image-rendering: pixelated\");\n\t\tstyles.push(\"image-rendering: crisp-edges\");\n\t}\n\n\t// TODO: .style is supposed to be readonly? alternative?\n\t// @ts-ignore\n\tcanvas.style = styles.join(\";\");\n\n\t// make canvas focusable\n\tcanvas.setAttribute(\"tabindex\", \"0\");\n\n\t// create webgl context\n\tconst gl = canvas\n\t\t.getContext(\"webgl\", {\n\t\t\tantialias: true,\n\t\t\tdepth: true,\n\t\t\tstencil: true,\n\t\t\talpha: true,\n\t\t\tpreserveDrawingBuffer: true,\n\t\t});\n\n\treturn {\n\n\t\tcanvas: canvas,\n\t\tscale: gscale,\n\t\tgl: gl,\n\n\t\t// keep track of all button states\n\t\tkeyStates: {} as Record<Key, ButtonState>,\n\t\tmouseStates: {} as Record<MouseButton, ButtonState>,\n\n\t\t// input states from last frame, should reset every frame\n\t\tcharInputted: [],\n\t\tisMouseMoved: false,\n\t\tisKeyPressed: false,\n\t\tisKeyPressedRepeat: false,\n\t\tisKeyReleased: false,\n\t\tmousePos: vec2(0, 0),\n\t\tmouseDeltaPos: vec2(0, 0),\n\n\t\t// total time elapsed\n\t\ttime: 0,\n\t\t// real total time elapsed (including paused time)\n\t\trealTime: 0,\n\t\t// if we should skip next dt, to prevent the massive dt surge if user switch to another tab for a while and comeback\n\t\tskipTime: false,\n\t\t// how much time last frame took\n\t\tdt: 0.0,\n\t\t// total frames elapsed\n\t\tnumFrames: 0,\n\n\t\t// if we're on a touch device\n\t\tisTouch: (\"ontouchstart\" in window) || navigator.maxTouchPoints > 0,\n\n\t\t// requestAnimationFrame id\n\t\tloopID: null,\n\t\t// if our game loop is currently stopped / paused\n\t\tstopped: false,\n\t\tpaused: false,\n\n\t\t// TODO: take fps counter out pure\n\t\tfpsCounter: new FPSCounter(),\n\n\t\t// if we finished loading all assets\n\t\tloaded: false,\n\n\t};\n\n})();\n\nconst gfx = (() => {\n\n\tconst gl = app.gl;\n\tconst defShader = makeShader(DEF_VERT, DEF_FRAG);\n\n\t// a 1x1 white texture to draw raw shapes like rectangles and polygons\n\t// we use a texture for those so we can use only 1 pipeline for drawing sprites + shapes\n\tconst emptyTex = makeTex(\n\t\tnew ImageData(new Uint8ClampedArray([ 255, 255, 255, 255, ]), 1, 1)\n\t);\n\n\tconst c = gopt.background ?? rgb(0, 0, 0);\n\n\tif (gopt.background) {\n\t\tconst c = Color.fromArray(gopt.background);\n\t\tgl.clearColor(c.r / 255, c.g / 255, c.b / 255, 1);\n\t}\n\n\tgl.enable(gl.BLEND);\n\tgl.enable(gl.SCISSOR_TEST);\n\tgl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n\t// we only use one vertex and index buffer that batches all draw calls\n\tconst vbuf = gl.createBuffer();\n\n\tgl.bindBuffer(gl.ARRAY_BUFFER, vbuf);\n\t// vec3 pos\n\tgl.vertexAttribPointer(0, 3, gl.FLOAT, false, STRIDE * 4, 0);\n\tgl.enableVertexAttribArray(0);\n\t// vec2 uv\n\tgl.vertexAttribPointer(1, 2, gl.FLOAT, false, STRIDE * 4, 12);\n\tgl.enableVertexAttribArray(1);\n\t// vec4 color\n\tgl.vertexAttribPointer(2, 4, gl.FLOAT, false, STRIDE * 4, 20);\n\tgl.enableVertexAttribArray(2);\n\tgl.bufferData(gl.ARRAY_BUFFER, QUEUE_COUNT * 4, gl.DYNAMIC_DRAW);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n\tconst ibuf = gl.createBuffer();\n\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibuf);\n\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, QUEUE_COUNT * 2, gl.DYNAMIC_DRAW);\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n\t// a checkerboard texture used for the default background\n\tconst bgTex = makeTex(\n\t\tnew ImageData(new Uint8ClampedArray([\n\t\t\t128, 128, 128, 255,\n\t\t\t190, 190, 190, 255,\n\t\t\t190, 190, 190, 255,\n\t\t\t128, 128, 128, 255,\n\t\t]), 2, 2), {\n\t\t\twrap: \"repeat\",\n\t\t\tfilter: \"nearest\",\n\t\t},\n\t);\n\n\treturn {\n\n\t\t// keep track of how many draw calls we're doing this frame\n\t\tdrawCalls: 0,\n\t\t// how many draw calls we're doing last frame, this is the number we give to users\n\t\tlastDrawCalls: 0,\n\n\t\t// gfx states\n\t\tdefShader: defShader,\n\t\tcurShader: defShader,\n\t\tdefTex: emptyTex,\n\t\tcurTex: emptyTex,\n\t\tcurUniform: {},\n\t\tvbuf: vbuf,\n\t\tibuf: ibuf,\n\n\t\t// local vertex / index buffer queue\n\t\tvqueue: [],\n\t\tiqueue: [],\n\n\t\ttransform: new Mat4(),\n\t\ttransformStack: [],\n\n\t\tbgTex: bgTex,\n\n\t\twidth: gopt.width,\n\t\theight: gopt.height,\n\n\t\tviewport: {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\twidth: gl.drawingBufferWidth,\n\t\t\theight: gl.drawingBufferHeight,\n\t\t},\n\n\t};\n\n})();\n\nupdateViewport();\n\nconst audio = (() => {\n\n\t// TODO: handle when audio context is unavailable\n\tconst ctx = new (window.AudioContext || (window as any).webkitAudioContext)() as AudioContext\n\tconst masterNode = ctx.createGain();\n\tmasterNode.connect(ctx.destination);\n\n\t// by default browsers can only load audio async, we don't deal with that and just start with an empty audio buffer\n\tconst burpSnd = {\n\t\tbuf: createEmptyAudioBuffer(),\n\t};\n\n\t// load that burp sound\n\tctx.decodeAudioData(burpBytes.buffer.slice(0), (buf) => {\n\t\tburpSnd.buf = buf;\n\t}, () => {\n\t\tthrow new Error(\"Failed to load burp.\")\n\t});\n\n\treturn {\n\t\tctx,\n\t\tmasterNode,\n\t\tburpSnd,\n\t};\n\n})();\n\nconst assets = {\n\n\t// keep track of how many assets are loading / loaded, for calculaating progress\n\tnumLoading: 0,\n\tnumLoaded: 0,\n\n\t// prefix for when loading from a url\n\turlPrefix: \"\",\n\n\t// asset holders\n\tsprites: {},\n\tsounds: {},\n\tshaders: {},\n\tfonts: {},\n\n};\n\nconst game = {\n\n\t// event callbacks\n\tevents: {},\n\tobjEvents: {},\n\n\t// root game object\n\t// these transforms are used as camera\n\troot: make([]),\n\n\ttimers: new IDList<Timer>(),\n\n\t// misc\n\tlayers: {},\n\tdefLayer: null,\n\tgravity: DEF_GRAVITY,\n\ton<F>(ev: string, cb: F): EventCanceller {\n\t\tif (!this.events[ev]) {\n\t\t\tthis.events[ev] = new IDList();\n\t\t}\n\t\treturn this.events[ev].pushd(cb);\n\t},\n\ttrigger(ev: string, ...args) {\n\t\tif (this.events[ev]) {\n\t\t\tthis.events[ev].forEach((cb) => cb(...args));\n\t\t}\n\t},\n\tscenes: {},\n\n\t// on screen log\n\tlogs: [],\n\n\t// camera\n\tcam: {\n\t\tpos: center(),\n\t\tscale: vec2(1),\n\t\tangle: 0,\n\t\tshake: 0,\n\t\ttransform: new Mat4(),\n\t},\n\n}\n\n// wrap individual loaders with global loader counter, for stuff like progress bar\nfunction load<T>(prom: Promise<T>): Promise<T> {\n\n\tassets.numLoading++;\n\n\t// wrapping another layer of promise because we are catching errors here internally and we also want users be able to catch errors, however only one catch is allowed per promise chain\n\treturn new Promise((resolve, reject) => {\n\t\tprom\n\t\t\t.then(resolve)\n\t\t\t.catch((err) => {\n\t\t\t\tdebug.error(err);\n\t\t\t\treject(err);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tassets.numLoading--;\n\t\t\t\tassets.numLoaded++;\n\t\t\t});\n\t}) as Promise<T>;\n\n}\n\n// get current load progress\nfunction loadProgress(): number {\n\treturn assets.numLoaded / (assets.numLoading + assets.numLoaded);\n}\n\n// global load path prefix\nfunction loadRoot(path?: string): string {\n\tif (path !== undefined) {\n\t\tassets.urlPrefix = path;\n\t}\n\treturn assets.urlPrefix;\n}\n\n// wrapper around fetch() that applies urlPrefix and basic error handling\nfunction fetchURL(path: string) {\n\tconst url = assets.urlPrefix + path;\n\treturn fetch(url)\n\t\t.then((res) => {\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new Error(`Failed to fetch ${url}`);\n\t\t\t}\n\t\t\treturn res;\n\t\t});\n}\n\n// wrapper around image loader to get a Promise\nfunction loadImg(src: string): Promise<HTMLImageElement> {\n\tconst img = new Image();\n\timg.src = isDataURL(src) ? src : assets.urlPrefix + src;\n\timg.crossOrigin = \"anonymous\";\n\treturn new Promise<HTMLImageElement>((resolve, reject) => {\n\t\timg.onload = () => resolve(img);\n\t\t// TODO: truncate for long dataurl src\n\t\timg.onerror = () => reject(`Failed to load image from \"${src}\"`);\n\t});\n}\n\n// TODO: support SpriteLoadSrc\nfunction loadFont(\n\tname: string | null,\n\tsrc: string,\n\tgw: number,\n\tgh: number,\n\topt: FontLoadOpt = {},\n): Promise<FontData> {\n\treturn load(loadImg(src)\n\t\t.then((img) => {\n\t\t\tconst font = makeFont(\n\t\t\t\tmakeTex(img, opt),\n\t\t\t\tgw,\n\t\t\t\tgh,\n\t\t\t\topt.chars ?? ASCII_CHARS\n\t\t\t);\n\t\t\tif (name) {\n\t\t\t\tassets.fonts[name] = font;\n\t\t\t}\n\t\t\treturn font;\n\t\t})\n\t);\n}\n\nfunction getSprite(name: string): SpriteData | null {\n\treturn assets.sprites[name] ?? null;\n}\n\nfunction getSound(name: string): SoundData | null {\n\treturn assets.sounds[name] ?? null;\n}\n\nfunction getFont(name: string): FontData | null {\n\treturn assets.fonts[name] ?? null;\n}\n\nfunction getShader(name: string): ShaderData | null {\n\treturn assets.shaders[name] ?? null;\n}\n\n// get an array of frames based on configuration on how to slice the image\nfunction slice(x = 1, y = 1, dx = 0, dy = 0, w = 1, h = 1): Quad[] {\n\tconst frames = [];\n\tconst qw = w / x;\n\tconst qh = h / y;\n\tfor (let j = 0; j < y; j++) {\n\t\tfor (let i = 0; i < x; i++) {\n\t\t\tframes.push(new Quad(\n\t\t\t\tdx + i * qw,\n\t\t\t\tdy + j * qh,\n\t\t\t\tqw,\n\t\t\t\tqh,\n\t\t\t));\n\t\t}\n\t}\n\treturn frames;\n}\n\nfunction loadSpriteAtlas(\n\tsrc: SpriteLoadSrc,\n\tdata: SpriteAtlasData | string\n): Promise<Record<string, SpriteData>> {\n\tif (typeof data === \"string\") {\n\t\t// TODO: this adds a new loader asyncly\n\t\treturn load(fetchURL(data)\n\t\t\t.then((res) => res.json())\n\t\t\t.then((data2) => loadSpriteAtlas(src, data2)));\n\t}\n\treturn load(loadSprite(null, src).then((atlas) => {\n\t\tconst map = {};\n\t\tconst w = atlas.tex.width;\n\t\tconst h = atlas.tex.height;\n\t\tfor (const name in data) {\n\t\t\tconst info = data[name];\n\t\t\tconst spr = {\n\t\t\t\ttex: atlas.tex,\n\t\t\t\tframes: slice(info.sliceX, info.sliceY, info.x / w, info.y / h, info.width / w, info.height / h),\n\t\t\t\tanims: info.anims,\n\t\t\t}\n\t\t\tassets.sprites[name] = spr;\n\t\t\tmap[name] = spr;\n\t\t}\n\t\treturn map;\n\t}));\n}\n\n// synchronously load sprite from local pixel data\nfunction loadRawSprite(\n\tname: string | null,\n\tsrc: GfxTexData,\n\topt: SpriteLoadOpt = {}\n) {\n\n\tconst tex = makeTex(src, opt);\n\tconst frames = slice(opt.sliceX || 1, opt.sliceY || 1);\n\n\tconst sprite = {\n\t\ttex: tex,\n\t\tframes: frames,\n\t\tanims: opt.anims || {},\n\t};\n\n\tif (name) {\n\t\tassets.sprites[name] = sprite;\n\t}\n\n\treturn sprite;\n\n}\n\n// load a sprite to asset manager\nfunction loadSprite(\n\tname: string | null,\n\tsrc: SpriteLoadSrc,\n\topt: SpriteLoadOpt = {\n\t\tsliceX: 1,\n\t\tsliceY: 1,\n\t\tanims: {},\n\t},\n): Promise<SpriteData> {\n\n\treturn load(new Promise<SpriteData>((resolve, reject) => {\n\n\t\tif (!src) {\n\t\t\treturn reject(`Expected sprite src for \"${name}\"`);\n\t\t}\n\n\t\t// from url\n\t\tif (typeof(src) === \"string\") {\n\t\t\tloadImg(src)\n\t\t\t\t.then((img) => resolve(loadRawSprite(name, img, opt)))\n\t\t\t\t.catch(reject);\n\t\t} else {\n\t\t\tresolve(loadRawSprite(name, src, opt));\n\t\t}\n\n\t}));\n\n}\n\n// TODO: accept raw json\nfunction loadPedit(name: string, src: string): Promise<SpriteData> {\n\n\treturn load(new Promise<SpriteData>((resolve, reject) => {\n\n\t\tfetchURL(src)\n\t\t\t.then((res) => res.json())\n\t\t\t.then(async (data) => {\n\n\t\t\t\tconst images = await Promise.all(data.frames.map(loadImg));\n\t\t\t\tconst canvas = document.createElement(\"canvas\");\n\t\t\t\tcanvas.width = data.width;\n\t\t\t\tcanvas.height = data.height * data.frames.length;\n\n\t\t\t\tconst ctx = canvas.getContext(\"2d\");\n\n\t\t\t\timages.forEach((img: HTMLImageElement, i) => {\n\t\t\t\t\tctx.drawImage(img, 0, i * data.height);\n\t\t\t\t});\n\n\t\t\t\treturn loadSprite(name, canvas, {\n\t\t\t\t\tsliceY: data.frames.length,\n\t\t\t\t\tanims: data.anims,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.then(resolve)\n\t\t\t.catch(reject)\n\t\t\t;\n\n\t}));\n\n}\n\n// TODO: accept raw json\nfunction loadAseprite(\n\tname: string | null,\n\timgSrc: SpriteLoadSrc,\n\tjsonSrc: string\n): Promise<SpriteData> {\n\n\treturn load(new Promise<SpriteData>((resolve, reject) => {\n\n\t\tloadSprite(name, imgSrc)\n\t\t\t.then((sprite: SpriteData) => {\n\t\t\t\tfetchURL(jsonSrc)\n\t\t\t\t\t.then((res) => res.json())\n\t\t\t\t\t.then((data) => {\n\t\t\t\t\t\tconst size = data.meta.size;\n\t\t\t\t\t\tsprite.frames = data.frames.map((f: any) => {\n\t\t\t\t\t\t\treturn new Quad(\n\t\t\t\t\t\t\t\tf.frame.x / size.w,\n\t\t\t\t\t\t\t\tf.frame.y / size.h,\n\t\t\t\t\t\t\t\tf.frame.w / size.w,\n\t\t\t\t\t\t\t\tf.frame.h / size.h,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfor (const anim of data.meta.frameTags) {\n\t\t\t\t\t\t\tif (anim.from === anim.to) {\n\t\t\t\t\t\t\t\tsprite.anims[anim.name] = anim.from\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsprite.anims[anim.name] = {\n\t\t\t\t\t\t\t\t\tfrom: anim.from,\n\t\t\t\t\t\t\t\t\tto: anim.to,\n\t\t\t\t\t\t\t\t\t// TODO: let users define these\n\t\t\t\t\t\t\t\t\tspeed: 10,\n\t\t\t\t\t\t\t\t\tloop: true,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve(sprite);\n\t\t\t\t\t})\n\t\t\t\t\t.catch(reject)\n\t\t\t\t\t;\n\t\t\t})\n\t\t\t.catch(reject);\n\n\t}));\n\n}\n\nfunction loadShader(\n\tname: string | null,\n\tvert?: string,\n\tfrag?: string,\n\tisUrl: boolean = false,\n): Promise<ShaderData> {\n\n\tfunction loadRawShader(\n\t\tname: string | null,\n\t\tvert: string | null,\n\t\tfrag: string | null,\n\t): ShaderData {\n\t\tconst shader = makeShader(vert, frag);\n\t\tif (name) {\n\t\t\tassets.shaders[name] = shader;\n\t\t}\n\t\treturn shader;\n\t}\n\n\treturn load(new Promise<ShaderData>((resolve, reject) => {\n\n\t\tif (!vert && !frag) {\n\t\t\treturn reject(\"no shader\");\n\t\t}\n\n\t\tfunction resolveUrl(url?: string) {\n\t\t\treturn url ?\n\t\t\t\tfetchURL(url)\n\t\t\t\t\t.then((res) => res.text())\n\t\t\t\t\t.catch(reject)\n\t\t\t\t: new Promise((r) => r(null));\n\t\t}\n\n\t\tif (isUrl) {\n\t\t\tPromise.all([resolveUrl(vert), resolveUrl(frag)])\n\t\t\t\t.then(([vcode, fcode]: [string | null, string | null]) => {\n\t\t\t\t\tresolve(loadRawShader(name, vcode, fcode));\n\t\t\t\t})\n\t\t\t\t.catch(reject);\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tresolve(loadRawShader(name, vert, frag));\n\t\t\t} catch (err) {\n\t\t\t\treject(err);\n\t\t\t}\n\t\t}\n\n\t}));\n\n}\n\n// TODO: accept dataurl\n// load a sound to asset manager\nfunction loadSound(\n\tname: string | null,\n\tsrc: string,\n): Promise<SoundData> {\n\n\treturn load(new Promise<SoundData>((resolve, reject) => {\n\n\t\tif (!src) {\n\t\t\treturn reject(`expected sound src for \"${name}\"`);\n\t\t}\n\n\t\t// from url\n\t\tif (typeof(src) === \"string\") {\n\t\t\tfetchURL(src)\n\t\t\t\t.then((res) => res.arrayBuffer())\n\t\t\t\t.then((data) => {\n\t\t\t\t\treturn new Promise((resolve2, reject2) =>\n\t\t\t\t\t\taudio.ctx.decodeAudioData(data, resolve2, reject2)\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.then((buf: AudioBuffer) => {\n\t\t\t\t\tconst snd = {\n\t\t\t\t\t\tbuf: buf,\n\t\t\t\t\t}\n\t\t\t\t\tif (name) {\n\t\t\t\t\t\tassets.sounds[name] = snd;\n\t\t\t\t\t}\n\t\t\t\t\tresolve(snd);\n\t\t\t\t})\n\t\t\t\t.catch(reject);\n\t\t}\n\n\t}));\n\n}\n\nfunction loadBean(name: string = \"bean\"): Promise<SpriteData> {\n\treturn loadSprite(name, beanSrc);\n}\n\n// get / set master volume\nfunction volume(v?: number): number {\n\tif (v !== undefined) {\n\t\taudio.masterNode.gain.value = clamp(v, MIN_GAIN, MAX_GAIN);\n\t}\n\treturn audio.masterNode.gain.value;\n}\n\n// plays a sound, returns a control handle\nfunction play(\n\tsrc: SoundData | string,\n\topt: AudioPlayOpt = {\n\t\tloop: false,\n\t\tvolume: 1,\n\t\tspeed: 1,\n\t\tdetune: 0,\n\t\tseek: 0,\n\t},\n): AudioPlay {\n\n\t// TODO: clean?\n\tif (typeof src === \"string\") {\n\n\t\tconst pb = play({\n\t\t\tbuf: createEmptyAudioBuffer(),\n\t\t});\n\n\t\tonLoad(() => {\n\t\t\tconst snd = assets.sounds[src];\n\t\t\tif (!snd) {\n\t\t\t\tthrow new Error(`Sound not found: \"${src}\"`);\n\t\t\t}\n\t\t\tconst pb2 = play(snd, opt);\n\t\t\tfor (const k in pb2) {\n\t\t\t\tpb[k] = pb2[k];\n\t\t\t}\n\t\t});\n\n\t\treturn pb;\n\n\t}\n\n\tconst ctx = audio.ctx;\n\tlet stopped = false;\n\tlet srcNode = ctx.createBufferSource();\n\n\tsrcNode.buffer = src.buf;\n\tsrcNode.loop = opt.loop ? true : false;\n\n\tconst gainNode = ctx.createGain();\n\n\tsrcNode.connect(gainNode);\n\tgainNode.connect(audio.masterNode);\n\n\tconst pos = opt.seek ?? 0;\n\n\tsrcNode.start(0, pos);\n\n\tlet startTime = ctx.currentTime - pos;\n\tlet stopTime: number | null = null;\n\n\tconst handle = {\n\n\t\tstop() {\n\t\t\tif (stopped) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pause();\n\t\t\tstartTime = ctx.currentTime;\n\t\t},\n\n\t\tplay(seek?: number) {\n\n\t\t\tif (!stopped) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst oldNode = srcNode;\n\n\t\t\tsrcNode = ctx.createBufferSource();\n\t\t\tsrcNode.buffer = oldNode.buffer;\n\t\t\tsrcNode.loop = oldNode.loop;\n\t\t\tsrcNode.playbackRate.value = oldNode.playbackRate.value;\n\n\t\t\tif (srcNode.detune) {\n\t\t\t\tsrcNode.detune.value = oldNode.detune.value;\n\t\t\t}\n\n\t\t\tsrcNode.connect(gainNode);\n\n\t\t\tconst pos = seek ?? this.time();\n\n\t\t\tsrcNode.start(0, pos);\n\t\t\tstartTime = ctx.currentTime - pos;\n\t\t\tstopped = false;\n\t\t\tstopTime = null;\n\n\t\t},\n\n\t\tpause() {\n\t\t\tif (stopped) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsrcNode.stop();\n\t\t\tstopped = true;\n\t\t\tstopTime = ctx.currentTime;\n\t\t},\n\n\t\tisPaused(): boolean {\n\t\t\treturn stopped;\n\t\t},\n\n\t\tpaused(): boolean {\n\t\t\tdeprecateMsg(\"paused()\", \"isPaused()\");\n\t\t\treturn this.isPaused();\n\t\t},\n\n\t\tisStopped(): boolean {\n\t\t\treturn stopped;\n\t\t},\n\n\t\tstopped(): boolean {\n\t\t\tdeprecateMsg(\"stopped()\", \"isStopped()\");\n\t\t\treturn this.isStopped();\n\t\t},\n\n\t\t// TODO: affect time()\n\t\tspeed(val?: number): number {\n\t\t\tif (val !== undefined) {\n\t\t\t\tsrcNode.playbackRate.value = clamp(val, MIN_SPEED, MAX_SPEED);\n\t\t\t}\n\t\t\treturn srcNode.playbackRate.value;\n\t\t},\n\n\t\tdetune(val?: number): number {\n\t\t\tif (!srcNode.detune) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (val !== undefined) {\n\t\t\t\tsrcNode.detune.value = clamp(val, MIN_DETUNE, MAX_DETUNE);\n\t\t\t}\n\t\t\treturn srcNode.detune.value;\n\t\t},\n\n\t\tvolume(val?: number): number {\n\t\t\tif (val !== undefined) {\n\t\t\t\tgainNode.gain.value = clamp(val, MIN_GAIN, MAX_GAIN);\n\t\t\t}\n\t\t\treturn gainNode.gain.value;\n\t\t},\n\n\t\tloop() {\n\t\t\tsrcNode.loop = true;\n\t\t},\n\n\t\tunloop() {\n\t\t\tsrcNode.loop = false;\n\t\t},\n\n\t\tduration(): number {\n\t\t\treturn src.buf.duration;\n\t\t},\n\n\t\ttime(): number {\n\t\t\tif (stopped) {\n\t\t\t\treturn stopTime - startTime;\n\t\t\t} else {\n\t\t\t\treturn ctx.currentTime - startTime;\n\t\t\t}\n\t\t},\n\n\t};\n\n\thandle.speed(opt.speed);\n\thandle.detune(opt.detune);\n\thandle.volume(opt.volume);\n\n\treturn handle;\n\n}\n\n// core kaboom logic\nfunction burp(opt?: AudioPlayOpt): AudioPlay {\n\treturn play(audio.burpSnd, opt);\n}\n\n// TODO: take these webgl structures out pure\nfunction makeTex(\n\tdata: GfxTexData,\n\topt: GfxTexOpt = {}\n): GfxTexture {\n\n\tconst gl = app.gl;\n\tconst id = gl.createTexture();\n\n\tgl.bindTexture(gl.TEXTURE_2D, id);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);\n\n\tconst filter = (() => {\n\t\tswitch (opt.filter ?? gopt.texFilter) {\n\t\t\tcase \"linear\": return gl.LINEAR;\n\t\t\tcase \"nearest\": return gl.NEAREST;\n\t\t\tdefault: return gl.NEAREST;\n\t\t}\n\t})();\n\n\tconst wrap = (() => {\n\t\tswitch (opt.wrap) {\n\t\t\tcase \"repeat\": return gl.REPEAT;\n\t\t\tcase \"clampToEdge\": return gl.CLAMP_TO_EDGE;\n\t\t\tdefault: return gl.CLAMP_TO_EDGE;\n\t\t}\n\t})();\n\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);\n\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\treturn {\n\t\twidth: data.width,\n\t\theight: data.height,\n\t\tbind() {\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, id);\n\t\t},\n\t\tunbind() {\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\t},\n\t};\n\n}\n\nfunction makeShader(\n\tvertSrc: string | null = DEF_VERT,\n\tfragSrc: string | null = DEF_FRAG,\n): GfxShader {\n\n\tconst gl = app.gl;\n\tlet msg;\n\tconst vcode = VERT_TEMPLATE.replace(\"{{user}}\", vertSrc ?? DEF_VERT);\n\tconst fcode = FRAG_TEMPLATE.replace(\"{{user}}\", fragSrc ?? DEF_FRAG);\n\tconst vertShader = gl.createShader(gl.VERTEX_SHADER);\n\tconst fragShader = gl.createShader(gl.FRAGMENT_SHADER);\n\n\tgl.shaderSource(vertShader, vcode);\n\tgl.shaderSource(fragShader, fcode);\n\tgl.compileShader(vertShader);\n\tgl.compileShader(fragShader);\n\n\tif ((msg = gl.getShaderInfoLog(vertShader))) {\n\t\tthrow new Error(msg);\n\t}\n\n\tif ((msg = gl.getShaderInfoLog(fragShader))) {\n\t\tthrow new Error(msg);\n\t}\n\n\tconst id = gl.createProgram();\n\n\tgl.attachShader(id, vertShader);\n\tgl.attachShader(id, fragShader);\n\n\tgl.bindAttribLocation(id, 0, \"a_pos\");\n\tgl.bindAttribLocation(id, 1, \"a_uv\");\n\tgl.bindAttribLocation(id, 2, \"a_color\");\n\n\tgl.linkProgram(id);\n\n\tif ((msg = gl.getProgramInfoLog(id))) {\n\t\t// for some reason on safari it always has a \"\\n\" msg\n\t\tif (msg !== \"\\n\") {\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\n\treturn {\n\n\t\tbind() {\n\t\t\tgl.useProgram(id);\n\t\t},\n\n\t\tunbind() {\n\t\t\tgl.useProgram(null);\n\t\t},\n\n\t\tsend(uniform: Uniform) {\n\t\t\tthis.bind();\n\t\t\tfor (const name in uniform) {\n\t\t\t\tconst val = uniform[name];\n\t\t\t\tconst loc = gl.getUniformLocation(id, name);\n\t\t\t\tif (typeof val === \"number\") {\n\t\t\t\t\tgl.uniform1f(loc, val);\n\t\t\t\t} else if (val instanceof Mat4) {\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tgl.uniformMatrix4fv(loc, false, new Float32Array(val.m));\n\t\t\t\t} else if (val instanceof Color) {\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tgl.uniform4f(loc, val.r, val.g, val.b, val.a);\n\t\t\t\t} else if (val instanceof Vec3) {\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tgl.uniform3f(loc, val.x, val.y, val.z);\n\t\t\t\t} else if (val instanceof Vec2) {\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tgl.uniform2f(loc, val.x, val.y);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.unbind();\n\t\t},\n\n\t};\n\n}\n\nfunction makeFont(\n\ttex: GfxTexture,\n\tgw: number,\n\tgh: number,\n\tchars: string,\n): GfxFont {\n\n\tconst cols = tex.width / gw;\n\tconst rows = tex.height / gh;\n\tconst qw = 1.0 / cols;\n\tconst qh = 1.0 / rows;\n\tconst map: Record<string, Vec2> = {};\n\tconst charMap = chars.split(\"\").entries();\n\n\tfor (const [i, ch] of charMap) {\n\t\tmap[ch] = vec2(\n\t\t\t(i % cols) * qw,\n\t\t\tMath.floor(i / cols) * qh,\n\t\t);\n\t}\n\n\treturn {\n\t\ttex: tex,\n\t\tmap: map,\n\t\tqw: qw,\n\t\tqh: qh,\n\t};\n\n}\n\n// TODO: expose\nfunction drawRaw(\n\tverts: Vertex[],\n\tindices: number[],\n\tfixed: boolean,\n\ttex: GfxTexture = gfx.defTex,\n\tshader: GfxShader = gfx.defShader,\n\tuniform: Uniform = {},\n) {\n\n\ttex = tex ?? gfx.defTex;\n\tshader = shader ?? gfx.defShader;\n\n\t// flush on texture / shader change and overflow\n\tif (\n\t\ttex !== gfx.curTex\n\t\t|| shader !== gfx.curShader\n\t\t|| !deepEq(gfx.curUniform, uniform)\n\t\t|| gfx.vqueue.length + verts.length * STRIDE > QUEUE_COUNT\n\t\t|| gfx.iqueue.length + indices.length > QUEUE_COUNT\n\t) {\n\t\tflush();\n\t}\n\n\tfor (const v of verts) {\n\n\t\t// TODO: cache camTransform * gfxTransform?\n\t\tconst transform = fixed ? gfx.transform : game.cam.transform.mult(gfx.transform);\n\n\t\t// normalized world space coordinate [-1.0 ~ 1.0]\n\t\tconst pt = screen2ndc(transform.multVec2(v.pos.xy()));\n\n\t\tgfx.vqueue.push(\n\t\t\tpt.x, pt.y, v.pos.z,\n\t\t\tv.uv.x, v.uv.y,\n\t\t\tv.color.r / 255, v.color.g / 255, v.color.b / 255, v.opacity,\n\t\t);\n\n\t}\n\n\tfor (const i of indices) {\n\t\tgfx.iqueue.push(i + gfx.vqueue.length / STRIDE - verts.length);\n\t}\n\n\tgfx.curTex = tex;\n\tgfx.curShader = shader;\n\tgfx.curUniform = uniform;\n\n}\n\n// draw all batched shapes\nfunction flush() {\n\n\tif (\n\t\t!gfx.curTex\n\t\t|| !gfx.curShader\n\t\t|| gfx.vqueue.length === 0\n\t\t|| gfx.iqueue.length === 0\n\t) {\n\t\treturn;\n\t}\n\n\tconst gl = app.gl;\n\n\tgfx.curShader.send(gfx.curUniform);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, gfx.vbuf);\n\tgl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(gfx.vqueue));\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gfx.ibuf);\n\tgl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, new Uint16Array(gfx.iqueue));\n\tgfx.curShader.bind();\n\tgfx.curTex.bind();\n\tgl.drawElements(gl.TRIANGLES, gfx.iqueue.length, gl.UNSIGNED_SHORT, 0);\n\tgfx.curTex.unbind();\n\tgfx.curShader.unbind();\n\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n\tgfx.iqueue = [];\n\tgfx.vqueue = [];\n\n\tgfx.drawCalls++;\n\n}\n\n// start a rendering frame, reset some states\nfunction frameStart() {\n\n\tapp.gl.clear(app.gl.COLOR_BUFFER_BIT);\n\n\tif (!gopt.background) {\n\t\tdrawUVQuad({\n\t\t\twidth: width(),\n\t\t\theight: height(),\n\t\t\tquad: new Quad(\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\twidth() * app.scale / BG_GRID_SIZE,\n\t\t\t\theight() * app.scale / BG_GRID_SIZE,\n\t\t\t),\n\t\t\ttex: gfx.bgTex,\n\t\t\tfixed: true,\n\t\t})\n\t}\n\n\tgfx.drawCalls = 0;\n\tgfx.transformStack = [];\n\tgfx.transform = new Mat4();\n\n}\n\nfunction frameEnd() {\n\tflush();\n\tgfx.lastDrawCalls = gfx.drawCalls;\n}\n\nfunction drawCalls() {\n\treturn gfx.lastDrawCalls;\n}\n\n// convert a screen space coordinate to webgl normalized device coordinate\nfunction screen2ndc(pt: Vec2): Vec2 {\n\treturn vec2(\n\t\tpt.x / width() * 2 - 1,\n\t\t-pt.y / height() * 2 + 1,\n\t);\n}\n\n// convert a webgl normalied device coordinate to screen space coordinate\nfunction ndc2screen(pt: Vec2): Vec2 {\n\treturn vec2(\n\t\t(pt.x + 1) / 2 * width(),\n\t\t-(pt.y - 1) / 2 * height(),\n\t);\n}\n\nfunction applyMatrix(m: Mat4) {\n\tgfx.transform = m.clone();\n}\n\nfunction pushTranslate(...args) {\n\tif (args[0] === undefined) return;\n\tconst p = vec2(...args);\n\tif (p.x === 0 && p.y === 0) return;\n\tgfx.transform = gfx.transform.translate(p);\n}\n\nfunction pushScale(...args) {\n\tif (args[0] === undefined) return;\n\tconst p = vec2(...args);\n\tif (p.x === 1 && p.y === 1) return;\n\tgfx.transform = gfx.transform.scale(p);\n}\n\nfunction pushRotateX(a: number) {\n\tif (!a) {\n\t\treturn;\n\t}\n\tgfx.transform = gfx.transform.rotateX(a);\n}\n\nfunction pushRotateY(a: number) {\n\tif (!a) {\n\t\treturn;\n\t}\n\tgfx.transform = gfx.transform.rotateY(a);\n}\n\nfunction pushRotateZ(a: number) {\n\tif (!a) {\n\t\treturn;\n\t}\n\tgfx.transform = gfx.transform.rotateZ(a);\n}\n\nfunction pushTransform() {\n\tgfx.transformStack.push(gfx.transform.clone());\n}\n\nfunction popTransform() {\n\tif (gfx.transformStack.length > 0) {\n\t\tgfx.transform = gfx.transformStack.pop();\n\t}\n}\n\n// draw a uv textured quad\nfunction drawUVQuad(opt: DrawUVQuadOpt) {\n\n\tif (opt.width === undefined || opt.height === undefined) {\n\t\tthrow new Error(\"drawUVQuad() requires property \\\"width\\\" and \\\"height\\\".\");\n\t}\n\n\tif (opt.width <= 0 || opt.height <= 0) {\n\t\treturn;\n\t}\n\n\tconst w = opt.width;\n\tconst h = opt.height;\n\tconst origin = originPt(opt.origin || DEF_ORIGIN);\n\tconst offset = origin.scale(vec2(w, h).scale(-0.5));\n\tconst q = opt.quad || new Quad(0, 0, 1, 1);\n\tconst color = opt.color || rgb(255, 255, 255);\n\tconst opacity = opt.opacity ?? 1;\n\n\tpushTransform();\n\tpushTranslate(opt.pos);\n\tpushRotateZ(opt.angle);\n\tpushScale(opt.scale);\n\tpushTranslate(offset);\n\n\tdrawRaw([\n\t\t{\n\t\t\tpos: vec3(-w / 2, h / 2, 0),\n\t\t\tuv: vec2(opt.flipX ? q.x + q.w : q.x, opt.flipY ? q.y : q.y + q.h),\n\t\t\tcolor: color,\n\t\t\topacity: opacity,\n\t\t},\n\t\t{\n\t\t\tpos: vec3(-w / 2, -h / 2, 0),\n\t\t\tuv: vec2(opt.flipX ? q.x + q.w : q.x, opt.flipY ? q.y + q.h : q.y),\n\t\t\tcolor: color,\n\t\t\topacity: opacity,\n\t\t},\n\t\t{\n\t\t\tpos: vec3(w / 2, -h / 2, 0),\n\t\t\tuv: vec2(opt.flipX ? q.x : q.x + q.w, opt.flipY ? q.y + q.h : q.y),\n\t\t\tcolor: color,\n\t\t\topacity: opacity,\n\t\t},\n\t\t{\n\t\t\tpos: vec3(w / 2, h / 2, 0),\n\t\t\tuv: vec2(opt.flipX ? q.x : q.x + q.w, opt.flipY ? q.y : q.y + q.h),\n\t\t\tcolor: color,\n\t\t\topacity: opacity,\n\t\t},\n\t], [0, 1, 3, 1, 2, 3], opt.fixed, opt.tex, opt.shader, opt.uniform);\n\n\tpopTransform();\n\n}\n\n// TODO: clean\nfunction drawTexture(opt: DrawTextureOpt) {\n\n\tif (!opt.tex) {\n\t\tthrow new Error(\"drawTexture() requires property \\\"tex\\\".\");\n\t}\n\n\tconst q = opt.quad ?? new Quad(0, 0, 1, 1);\n\tconst w = opt.tex.width * q.w;\n\tconst h = opt.tex.height * q.h;\n\tconst scale = vec2(1);\n\n\tif (opt.tiled) {\n\n\t\t// TODO: draw fract\n\t\tconst repX = Math.ceil((opt.width || w) / w);\n\t\tconst repY = Math.ceil((opt.height || h) / h);\n\t\tconst origin = originPt(opt.origin || DEF_ORIGIN).add(vec2(1, 1)).scale(0.5);\n\t\tconst offset = origin.scale(repX * w, repY * h);\n\n\t\t// TODO: rotation\n\t\tfor (let i = 0; i < repX; i++) {\n\t\t\tfor (let j = 0; j < repY; j++) {\n\t\t\t\tdrawUVQuad({\n\t\t\t\t\t...opt,\n\t\t\t\t\tpos: (opt.pos || vec2(0)).add(vec2(w * i, h * j)).sub(offset),\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tscale: scale.scale(opt.scale || vec2(1)),\n\t\t\t\t\ttex: opt.tex,\n\t\t\t\t\tquad: q,\n\t\t\t\t\twidth: w,\n\t\t\t\t\theight: h,\n\t\t\t\t\torigin: \"topleft\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} else {\n\n\t\t// TODO: should this ignore scale?\n\t\tif (opt.width && opt.height) {\n\t\t\tscale.x = opt.width / w;\n\t\t\tscale.y = opt.height / h;\n\t\t} else if (opt.width) {\n\t\t\tscale.x = opt.width / w;\n\t\t\tscale.y = scale.x;\n\t\t} else if (opt.height) {\n\t\t\tscale.y = opt.height / h;\n\t\t\tscale.x = scale.y;\n\t\t}\n\n\t\tdrawUVQuad({\n\t\t\t...opt,\n\t\t\t// @ts-ignore\n\t\t\tscale: scale.scale(opt.scale || vec2(1)),\n\t\t\ttex: opt.tex,\n\t\t\tquad: q,\n\t\t\twidth: w,\n\t\t\theight: h,\n\t\t});\n\n\t}\n\n}\n\n// TODO: use native asset loader tracking\nconst loading = new Set();\n\nfunction drawSprite(opt: DrawSpriteOpt) {\n\n\tif (!opt.sprite) {\n\t\tthrow new Error(`drawSprite() requires property \"sprite\"`);\n\t}\n\n\tconst spr = findAsset(opt.sprite, assets.sprites);\n\n\tif (!spr) {\n\n\t\t// if passes a source url, we load it implicitly\n\t\tif (typeof opt.sprite === \"string\") {\n\t\t\tif (!loading.has(opt.sprite)) {\n\t\t\t\tloading.add(opt.sprite);\n\t\t\t\tloadSprite(opt.sprite, opt.sprite)\n\t\t\t\t\t.then((a) => loading.delete(opt.sprite));\n\t\t\t}\n\t\t\treturn;\n\t\t} else {\n\t\t\tthrow new Error(`sprite not found: \"${opt.sprite}\"`);\n\t\t}\n\n\t}\n\n\tconst q = spr.frames[opt.frame ?? 0];\n\n\tif (!q) {\n\t\tthrow new Error(`frame not found: ${opt.frame ?? 0}`);\n\t}\n\n\tdrawTexture({\n\t\t...opt,\n\t\ttex: spr.tex,\n\t\tquad: q.scale(opt.quad || new Quad(0, 0, 1, 1)),\n\t\tuniform: opt.uniform,\n\t});\n\n}\n\n// generate vertices to form an arc\nfunction getArcPts(\n\tpos: Vec2,\n\tradiusX: number,\n\tradiusY: number,\n\tstart: number,\n\tend: number,\n\tres: number = 1,\n): Vec2[] {\n\n\t// normalize and turn start and end angles to radians\n\tstart = deg2rad(start % 360);\n\tend = deg2rad(end % 360);\n\tif (end <= start) end += Math.PI * 2;\n\n\t// TODO: better way to get this?\n\t// the number of vertices is sqrt(r1 + r2) * 3 * res with a minimum of 16\n\tconst nverts = Math.ceil(Math.max(Math.sqrt(radiusX + radiusY) * 3 * (res || 1), 16));\n\tconst step = (end - start) / nverts;\n\tconst pts = [];\n\n\t// calculate vertices\n\tfor (let a = start; a < end; a += step) {\n\t\tpts.push(pos.add(radiusX * Math.cos(a), radiusY * Math.sin(a)));\n\t}\n\n\t// doing this on the side due to possible floating point inaccuracy\n\tpts.push(pos.add(radiusX * Math.cos(end), radiusY * Math.sin(end)));\n\n\treturn pts;\n\n}\n\nfunction drawRect(opt: DrawRectOpt) {\n\n\tif (opt.width === undefined || opt.height === undefined) {\n\t\tthrow new Error(\"drawRect() requires property \\\"width\\\" and \\\"height\\\".\");\n\t}\n\n\tif (opt.width <= 0 || opt.height <= 0) {\n\t\treturn;\n\t}\n\n\tconst w = opt.width;\n\tconst h = opt.height;\n\tconst origin = originPt(opt.origin || DEF_ORIGIN).add(1, 1);\n\tconst offset = origin.scale(vec2(w, h).scale(-0.5));\n\n\tlet pts = [\n\t\tvec2(0, 0),\n\t\tvec2(w, 0),\n\t\tvec2(w, h),\n\t\tvec2(0, h),\n\t];\n\n\t// TODO: drawPolygon should handle generic rounded corners\n\tif (opt.radius) {\n\n\t\t// maxium radius is half the shortest side\n\t\tconst r = Math.min(Math.min(w, h) / 2, opt.radius);\n\n\t\tpts = [\n\t\t\tvec2(r, 0),\n\t\t\tvec2(w - r, 0),\n\t\t\t...getArcPts(vec2(w - r, r), r, r, 270, 360),\n\t\t\tvec2(w, r),\n\t\t\tvec2(w, h - r),\n\t\t\t...getArcPts(vec2(w - r, h - r), r, r, 0, 90),\n\t\t\tvec2(w - r, h),\n\t\t\tvec2(r, h),\n\t\t\t...getArcPts(vec2(r, h - r), r, r, 90, 180),\n\t\t\tvec2(0, h - r),\n\t\t\tvec2(0, r),\n\t\t\t...getArcPts(vec2(r, r), r, r, 180, 270),\n\t\t];\n\n\t}\n\n\tdrawPolygon({ ...opt, offset, pts });\n\n}\n\nfunction drawLine(opt: DrawLineOpt) {\n\n\tconst { p1, p2 } = opt;\n\n\tif (!p1 || !p2) {\n\t\tthrow new Error(\"drawLine() requires properties \\\"p1\\\" and \\\"p2\\\".\");\n\t}\n\n\tconst w = opt.width || 1;\n\n\t// the displacement from the line end point to the corner point\n\tconst dis = p2.sub(p1).unit().normal().scale(w * 0.5);\n\n\t// calculate the 4 corner points of the line polygon\n\tconst verts = [\n\t\tp1.sub(dis),\n\t\tp1.add(dis),\n\t\tp2.add(dis),\n\t\tp2.sub(dis),\n\t].map((p) => ({\n\t\tpos: vec3(p.x, p.y, 0),\n\t\tuv: vec2(0),\n\t\tcolor: opt.color ?? Color.WHITE,\n\t\topacity: opt.opacity ?? 1,\n\t}));\n\n\tdrawRaw(verts, [0, 1, 3, 1, 2, 3], opt.fixed, gfx.defTex, opt.shader, opt.uniform);\n\n}\n\nfunction drawLines(opt: DrawLinesOpt) {\n\n\tconst pts = opt.pts;\n\n\tif (!pts) {\n\t\tthrow new Error(\"drawLines() requires property \\\"pts\\\".\");\n\t}\n\n\tif (pts.length < 2) {\n\t\treturn;\n\t}\n\n\tif (opt.radius && pts.length >= 3) {\n\n\t\t// TODO: rounded vertices for arbitury polygonic shape\n\t\tlet minLen = pts[0].dist(pts[1]);\n\n\t\tfor (let i = 1; i < pts.length - 1; i++) {\n\t\t\tminLen = Math.min(pts[i].dist(pts[i + 1]), minLen);\n\t\t}\n\n\t\tconst radius = Math.min(opt.radius, minLen / 2);\n\n\t\tdrawLine({ ...opt, p1: pts[0], p2: pts[1], });\n\n\t\tfor (let i = 1; i < pts.length - 2; i++) {\n\t\t\tconst p1 = pts[i];\n\t\t\tconst p2 = pts[i + 1];\n\t\t\tdrawLine({\n\t\t\t\t...opt,\n\t\t\t\tp1: p1,\n\t\t\t\tp2: p2,\n\t\t\t});\n\t\t}\n\n\t\tdrawLine({ ...opt, p1: pts[pts.length - 2], p2: pts[pts.length - 1], });\n\n\t} else {\n\n\t\tfor (let i = 0; i < pts.length - 1; i++) {\n\t\t\tdrawLine({\n\t\t\t\t...opt,\n\t\t\t\tp1: pts[i],\n\t\t\t\tp2: pts[i + 1],\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n\nfunction drawTriangle(opt: DrawTriangleOpt) {\n\tif (!opt.p1 || !opt.p2 || !opt.p3) {\n\t\tthrow new Error(\"drawPolygon() requires properties \\\"p1\\\", \\\"p2\\\" and \\\"p3\\\".\");\n\t}\n\treturn drawPolygon({\n\t\t...opt,\n\t\tpts: [opt.p1, opt.p2, opt.p3],\n\t});\n}\n\n// TODO: origin\nfunction drawCircle(opt: DrawCircleOpt) {\n\n\tif (!opt.radius) {\n\t\tthrow new Error(\"drawCircle() requires property \\\"radius\\\".\");\n\t}\n\n\tif (opt.radius === 0) {\n\t\treturn;\n\t}\n\n\tdrawEllipse({\n\t\t...opt,\n\t\tradiusX: opt.radius,\n\t\tradiusY: opt.radius,\n\t\tangle: 0,\n\t});\n\n}\n\n// TODO: use fan-like triangulation\nfunction drawEllipse(opt: DrawEllipseOpt) {\n\n\tif (opt.radiusX === undefined || opt.radiusY === undefined) {\n\t\tthrow new Error(\"drawEllipse() requires properties \\\"radiusX\\\" and \\\"radiusY\\\".\");\n\t}\n\n\tif (opt.radiusX === 0 || opt.radiusY === 0) {\n\t\treturn;\n\t}\n\n\tdrawPolygon({\n\t\t...opt,\n\t\tpts: getArcPts(\n\t\t\tvec2(0),\n\t\t\topt.radiusX,\n\t\t\topt.radiusY,\n\t\t\topt.start ?? 0,\n\t\t\topt.end ?? 360,\n\t\t\topt.resolution\n\t\t),\n\t\tradius: 0,\n\t});\n\n}\n\nfunction drawPolygon(opt: DrawPolygonOpt) {\n\n\tif (!opt.pts) {\n\t\tthrow new Error(\"drawPolygon() requires property \\\"pts\\\".\");\n\t}\n\n\tconst npts = opt.pts.length;\n\n\tif (npts < 3) {\n\t\treturn;\n\t}\n\n\tpushTransform();\n\tpushTranslate(opt.pos);\n\tpushScale(opt.scale);\n\tpushRotateZ(opt.angle);\n\tpushTranslate(opt.offset);\n\n\tif (opt.fill !== false) {\n\n\t\tconst color = opt.color ?? Color.WHITE;\n\n\t\tconst verts = opt.pts.map((pt) => ({\n\t\t\tpos: vec3(pt.x, pt.y, 0),\n\t\t\tuv: vec2(0, 0),\n\t\t\tcolor: color,\n\t\t\topacity: opt.opacity ?? 1,\n\t\t}));\n\n\t\t// TODO: better triangulation\n\t\tconst indices = [...Array(npts - 2).keys()]\n\t\t\t.map((n) => [0, n + 1, n + 2])\n\t\t\t.flat();\n\n\t\tdrawRaw(verts, opt.indices ?? indices, opt.fixed, gfx.defTex, opt.shader, opt.uniform);\n\n\t}\n\n\tif (opt.outline) {\n\t\tdrawLines({\n\t\t\tpts: [ ...opt.pts, opt.pts[0] ],\n\t\t\tradius: opt.radius,\n\t\t\twidth: opt.outline.width,\n\t\t\tcolor: opt.outline.color,\n\t\t\tuniform: opt.uniform,\n\t\t\tfixed: opt.fixed,\n\t\t});\n\t}\n\n\tpopTransform();\n\n}\n\nfunction applyCharTransform(fchar: FormattedChar, tr: CharTransform) {\n\tif (tr.pos) fchar.pos = fchar.pos.add(tr.pos);\n\tif (tr.scale) fchar.scale = fchar.scale.scale(vec2(tr.scale));\n\tif (tr.angle) fchar.angle += tr.angle;\n\tif (tr.color) fchar.color = fchar.color.mult(tr.color);\n\tif (tr.opacity) fchar.opacity *= tr.opacity;\n}\n\n// TODO: escape\nconst TEXT_STYLE_RE = /\\[(?<text>[^\\]]*)\\]\\.(?<style>[\\w\\.]+)+/g;\n\nfunction compileStyledText(text: string): {\n\tcharStyleMap: Record<number, {\n\t\tlocalIdx: number,\n\t\tstyles: string[],\n\t}>,\n\ttext: string,\n} {\n\n\tconst charStyleMap = {};\n\t// get the text without the styling syntax\n\tconst renderText = text.replace(TEXT_STYLE_RE, \"$1\");\n\tlet idxOffset = 0;\n\n\t// put each styled char index into a map for easy access when iterating each char\n\tfor (const match of text.matchAll(TEXT_STYLE_RE)) {\n\t\tconst styles = match.groups.style.split(\".\");\n\t\tconst origIdx = match.index - idxOffset;\n\t\tfor (\n\t\t\tlet i = origIdx;\n\t\t\ti < match.index + match.groups.text.length;\n\t\t\ti++\n\t\t) {\n\t\t\tcharStyleMap[i] = {\n\t\t\t\tlocalIdx: i - origIdx,\n\t\t\t\tstyles: styles,\n\t\t\t};\n\t\t}\n\t\t// omit \"[\", \"]\", \".\" and the style text in the format string when calculating index\n\t\tidxOffset += 3 + match.groups.style.length;\n\t}\n\n\treturn {\n\t\tcharStyleMap: charStyleMap,\n\t\ttext: renderText,\n\t};\n\n}\n\nfunction findAsset<T>(src: string | T, lib: Record<string, T>, def?: string): T | undefined {\n\tif (src) {\n\t\treturn typeof src === \"string\" ? lib[src] : src;\n\t} else if (def) {\n\t\treturn lib[def];\n\t}\n}\n\n// format text and return a list of chars with their calculated position\nfunction formatText(opt: DrawTextOpt): FormattedText {\n\n\tif (opt.text === undefined) {\n\t\tthrow new Error(\"formatText() requires property \\\"text\\\".\");\n\t}\n\n\tconst font = findAsset(opt.font ?? gopt.font, assets.fonts, DEF_FONT);\n\n\tif (!font) {\n\t\tthrow new Error(`Font not found: ${opt.font}`);\n\t}\n\n\tconst { charStyleMap, text } = compileStyledText(opt.text + \"\");\n\tconst chars = text.split(\"\");\n\tconst gw = font.qw * font.tex.width;\n\tconst gh = font.qh * font.tex.height;\n\tconst size = opt.size || gh;\n\tconst scale = vec2(size / gh).scale(vec2(opt.scale || 1));\n\tconst cw = scale.x * gw + (opt.letterSpacing ?? 0);\n\tconst ch = scale.y * gh + (opt.lineSpacing ?? 0);\n\tlet curX = 0;\n\tlet th = ch;\n\tlet tw = 0;\n\tconst flines = [];\n\tlet curLine = [];\n\tlet lastSpace = null;\n\tlet cursor = 0;\n\n\twhile (cursor < chars.length) {\n\n\t\tlet char = chars[cursor];\n\n\t\t// check new line\n\t\tif (char === \"\\n\") {\n\t\t\t// always new line on '\\n'\n\t\t\tth += ch;\n\t\t\tcurX = 0;\n\t\t\tlastSpace = null;\n\t\t\tcurLine.push(char);\n\t\t\tflines.push(curLine);\n\t\t\tcurLine = [];\n\t\t} else if ((opt.width ? (curX + cw > opt.width) : false)) {\n\t\t\t// new line on last word if width exceeds\n\t\t\tth += ch;\n\t\t\tcurX = 0;\n\t\t\tif (lastSpace != null) {\n\t\t\t\tcursor -= curLine.length - lastSpace;\n\t\t\t\tchar = chars[cursor];\n\t\t\t\tcurLine = curLine.slice(0, lastSpace);\n\t\t\t}\n\t\t\tlastSpace = null;\n\t\t\tflines.push(curLine);\n\t\t\tcurLine = [];\n\t\t}\n\n\t\t// push char\n\t\tif (char !== \"\\n\") {\n\t\t\tcurLine.push(char);\n\t\t\tcurX += cw;\n\t\t\tif (char === \" \") {\n\t\t\t\tlastSpace = curLine.length;\n\t\t\t}\n\t\t}\n\n\t\ttw = Math.max(tw, curX);\n\t\tcursor++;\n\n\t}\n\n\tflines.push(curLine);\n\n\tif (opt.width) {\n\t\ttw = opt.width;\n\t}\n\n\t// whole text offset\n\tconst fchars = [];\n\tconst pos = vec2(opt.pos || 0);\n\tconst offset = originPt(opt.origin || DEF_ORIGIN).scale(0.5);\n\t// this math is complicated i forgot how it works instantly\n\tconst ox = -offset.x * cw - (offset.x + 0.5) * (tw - cw);\n\tconst oy = -offset.y * ch - (offset.y + 0.5) * (th - ch);\n\tlet idx = 0;\n\n\tflines.forEach((line, ln) => {\n\n\t\t// line offset\n\t\tconst oxl = (tw - line.length * cw) * (offset.x + 0.5);\n\n\t\tline.forEach((char, cn) => {\n\t\t\tconst qpos = font.map[char];\n\t\t\tconst x = cn * cw;\n\t\t\tconst y = ln * ch;\n\t\t\tif (qpos) {\n\t\t\t\tconst fchar: FormattedChar = {\n\t\t\t\t\ttex: font.tex,\n\t\t\t\t\tquad: new Quad(qpos.x, qpos.y, font.qw, font.qh),\n\t\t\t\t\tch: char,\n\t\t\t\t\tpos: vec2(pos.x + x + ox + oxl, pos.y + y + oy),\n\t\t\t\t\topacity: opt.opacity,\n\t\t\t\t\tcolor: opt.color ?? rgb(255, 255, 255),\n\t\t\t\t\tscale: scale,\n\t\t\t\t\tangle: 0,\n\t\t\t\t\tuniform: opt.uniform,\n\t\t\t\t\tfixed: opt.fixed,\n\t\t\t\t}\n\t\t\t\tif (opt.transform) {\n\t\t\t\t\tconst tr = typeof opt.transform === \"function\"\n\t\t\t\t\t\t? opt.transform(idx, char)\n\t\t\t\t\t\t: opt.transform;\n\t\t\t\t\tif (tr) {\n\t\t\t\t\t\tapplyCharTransform(fchar, tr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (charStyleMap[idx]) {\n\t\t\t\t\tconst { styles, localIdx } = charStyleMap[idx];\n\t\t\t\t\tfor (const name of styles) {\n\t\t\t\t\t\tconst style = opt.styles[name];\n\t\t\t\t\t\tconst tr = typeof style === \"function\"\n\t\t\t\t\t\t\t? style(localIdx, char)\n\t\t\t\t\t\t\t: style;\n\t\t\t\t\t\tif (tr) {\n\t\t\t\t\t\t\tapplyCharTransform(fchar, tr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfchars.push(fchar);\n\t\t\t}\n\t\t\tidx += 1;\n\t\t});\n\t});\n\n\treturn {\n\t\twidth: tw,\n\t\theight: th,\n\t\tchars: fchars,\n\t};\n\n}\n\nfunction drawText(opt: DrawTextOpt) {\n\tdrawFormattedText(formatText(opt));\n}\n\n// TODO: rotation\nfunction drawFormattedText(ftext: FormattedText) {\n\tfor (const ch of ftext.chars) {\n\t\tdrawUVQuad({\n\t\t\ttex: ch.tex,\n\t\t\twidth: ch.tex.width * ch.quad.w,\n\t\t\theight: ch.tex.height * ch.quad.h,\n\t\t\tpos: ch.pos,\n\t\t\tscale: ch.scale,\n\t\t\tangle: ch.angle,\n\t\t\tcolor: ch.color,\n\t\t\topacity: ch.opacity,\n\t\t\tquad: ch.quad,\n\t\t\t// TODO: topleft\n\t\t\torigin: \"center\",\n\t\t\tuniform: ch.uniform,\n\t\t\tfixed: ch.fixed,\n\t\t});\n\t}\n}\n\n/**\n * Update viewport based on user setting and fullscreen state\n */\nfunction updateViewport() {\n\n\tconst gl = app.gl;\n\n\t// canvas size\n\tconst cw = gl.drawingBufferWidth;\n\tconst ch = gl.drawingBufferHeight;\n\n\t// game size\n\tconst gw = width();\n\tconst gh = height();\n\n\tif (isFullscreen()) {\n\t\t// TODO: doesn't work with letterbox\n\t\tconst ww = window.innerWidth;\n\t\tconst wh = window.innerHeight;\n\t\tconst rw = ww / wh;\n\t\tconst rc = cw / ch;\n\t\tif (rw > rc) {\n\t\t\tconst sw = window.innerHeight * rc;\n\t\t\tgfx.viewport = {\n\t\t\t\tx: (ww - sw) / 2,\n\t\t\t\ty: 0,\n\t\t\t\twidth: sw,\n\t\t\t\theight: wh,\n\t\t\t};\n\t\t} else {\n\t\t\tconst sh = window.innerWidth / rc;\n\t\t\tgfx.viewport = {\n\t\t\t\tx: 0,\n\t\t\t\ty: (wh - sh) / 2,\n\t\t\t\twidth: ww,\n\t\t\t\theight: sh,\n\t\t\t};\n\t\t}\n\t\treturn;\n\t}\n\n\tif (gopt.letterbox) {\n\n\t\tif (!gopt.width || !gopt.height) {\n\t\t\tthrow new Error(\"Letterboxing requires width and height defined.\");\n\t\t}\n\n\t\tconst rc = cw / ch;\n\t\tconst rg = gopt.width / gopt.height;\n\n\t\tif (rc > rg) {\n\t\t\tif (!gopt.stretch) {\n\t\t\t\tgfx.width = ch * rg;\n\t\t\t\tgfx.height = ch;\n\t\t\t}\n\t\t\tconst sw = ch * rg;\n\t\t\tconst sh = ch;\n\t\t\tconst x = (cw - sw) / 2;\n\t\t\tgl.scissor(x, 0, sw, sh);\n\t\t\tgl.viewport(x, 0, sw, ch);\n\t\t\tgfx.viewport = {\n\t\t\t\tx: x,\n\t\t\t\ty: 0,\n\t\t\t\twidth: sw,\n\t\t\t\theight: ch,\n\t\t\t};\n\t\t} else {\n\t\t\tif (!gopt.stretch) {\n\t\t\t\tgfx.width = cw;\n\t\t\t\tgfx.height = cw / rg;\n\t\t\t}\n\t\t\tconst sw = cw;\n\t\t\tconst sh = cw / rg;\n\t\t\tconst y = (ch - sh) / 2;\n\t\t\tgl.scissor(0, y, sw, sh);\n\t\t\tgl.viewport(0, y, cw, sh);\n\t\t\tgfx.viewport = {\n\t\t\t\tx: 0,\n\t\t\t\ty: y,\n\t\t\t\twidth: cw,\n\t\t\t\theight: sh,\n\t\t\t};\n\t\t}\n\n\t\treturn;\n\n\t}\n\n\tif (gopt.stretch) {\n\n\t\tif (!gopt.width || !gopt.height) {\n\t\t\tthrow new Error(\"Stretching requires width and height defined.\");\n\t\t}\n\n\t\tgl.viewport(0, 0, cw, ch);\n\n\t\tgfx.viewport = {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\twidth: cw,\n\t\t\theight: ch,\n\t\t};\n\n\t\treturn;\n\t}\n\n\tgfx.width = cw / app.scale;\n\tgfx.height = ch / app.scale;\n\tgl.viewport(0, 0, cw, ch);\n\n\tgfx.viewport = {\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: cw,\n\t\theight: ch,\n\t};\n\n}\n\n// get game width\nfunction width(): number {\n\treturn gfx.width;\n}\n\n// get game height\nfunction height(): number {\n\treturn gfx.height;\n}\n\n// TODO: support remove events\napp.canvas.addEventListener(\"mousemove\", (e) => {\n\tapp.mousePos = vec2(\n\t\t(e.offsetX - gfx.viewport.x) * width() / gfx.viewport.width,\n\t\t(e.offsetY - gfx.viewport.y) * height() / gfx.viewport.height,\n\t);\n\tapp.mouseDeltaPos = vec2(e.movementX, e.movementY).scale(1 / app.scale);\n\tapp.isMouseMoved = true;\n});\n\napp.canvas.addEventListener(\"mousedown\", (e) => {\n\tconst m = MOUSE_BUTTONS[e.button];\n\tif (m) {\n\t\tapp.mouseStates[m] = \"pressed\";\n\t}\n});\n\napp.canvas.addEventListener(\"mouseup\", (e) => {\n\tconst m = MOUSE_BUTTONS[e.button];\n\tif (m) {\n\t\tapp.mouseStates[m] = \"released\";\n\t}\n});\n\napp.canvas.addEventListener(\"keydown\", (e) => {\n\n\tconst k = KEY_ALIAS[e.key] || e.key.toLowerCase();\n\n\tif (PREVENT_DEFAULT_KEYS.includes(k)) {\n\t\te.preventDefault();\n\t}\n\n\tif (k.length === 1) {\n\t\tapp.charInputted.push(e.key);\n\t}\n\n\tif (k === \"space\") {\n\t\tapp.charInputted.push(\" \");\n\t}\n\n\tif (e.repeat) {\n\t\tapp.isKeyPressedRepeat = true;\n\t\tapp.keyStates[k] = \"rpressed\";\n\t} else {\n\t\tapp.isKeyPressed = true;\n\t\tapp.keyStates[k] = \"pressed\";\n\t}\n\n});\n\napp.canvas.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n\tconst k = KEY_ALIAS[e.key] || e.key.toLowerCase();\n\tapp.keyStates[k] = \"released\";\n\tapp.isKeyReleased = true;\n});\n\napp.canvas.addEventListener(\"touchstart\", (e) => {\n\tif (!gopt.touchToMouse) return;\n\t// disable long tap context menu\n\te.preventDefault();\n\tconst t = e.touches[0];\n\tapp.mousePos = vec2(t.clientX, t.clientY).scale(1 / app.scale);\n\tapp.mouseStates[\"left\"] = \"pressed\";\n});\n\napp.canvas.addEventListener(\"touchmove\", (e) => {\n\tif (!gopt.touchToMouse) return;\n\t// disable scrolling\n\te.preventDefault();\n\tconst t = e.touches[0];\n\tapp.mousePos = vec2(t.clientX, t.clientY).scale(1 / app.scale);\n\tapp.isMouseMoved = true;\n});\n\napp.canvas.addEventListener(\"touchend\", (e) => {\n\tif (!gopt.touchToMouse) return;\n\tapp.mouseStates[\"left\"] = \"released\";\n});\n\napp.canvas.addEventListener(\"touchcancel\", (e) => {\n\tif (!gopt.touchToMouse) return;\n\tapp.mouseStates[\"left\"] = \"released\";\n});\n\napp.canvas.addEventListener(\"touchstart\", (e) => {\n\t[...e.changedTouches].forEach((t) => {\n\t\tgame.trigger(\"onTouchStart\", t.identifier, vec2(t.clientX, t.clientY).scale(1 / app.scale));\n\t});\n});\n\napp.canvas.addEventListener(\"touchmove\", (e) => {\n\t[...e.changedTouches].forEach((t) => {\n\t\tgame.trigger(\"onTouchMove\", t.identifier, vec2(t.clientX, t.clientY).scale(1 / app.scale));\n\t});\n});\n\napp.canvas.addEventListener(\"touchend\", (e) => {\n\t[...e.changedTouches].forEach((t) => {\n\t\tgame.trigger(\"onTouchEnd\", t.identifier, vec2(t.clientX, t.clientY).scale(1 / app.scale));\n\t});\n});\n\napp.canvas.addEventListener(\"contextmenu\", function (e) {\n\te.preventDefault();\n});\n\ndocument.addEventListener(\"visibilitychange\", () => {\n\tswitch (document.visibilityState) {\n\t\tcase \"visible\":\n\t\t\t// prevent a surge of dt() when switch back after the tab being hidden for a while\n\t\t\tapp.skipTime = true;\n\t\t\t// TODO: don't resume if debug.paused\n\t\t\taudio.ctx.resume();\n\t\t\tbreak;\n\t\tcase \"hidden\":\n\t\t\taudio.ctx.suspend();\n\t\t\tbreak;\n\t}\n});\n\n// TODO: not quite working\n// window.addEventListener(\"resize\", () => {\n// \tif (!(gopt.width && gopt.height && !gopt.stretch)) {\n// \t\tapp.canvas.width = app.canvas.parentElement.offsetWidth;\n// \t\tapp.canvas.height = app.canvas.parentElement.offsetHeight;\n// \t}\n// });\n\nfunction mousePos(): Vec2 {\n\treturn app.mousePos.clone();\n}\n\nfunction mouseDeltaPos(): Vec2 {\n\treturn app.mouseDeltaPos.clone();\n}\n\nfunction isMousePressed(m = \"left\"): boolean {\n\treturn app.mouseStates[m] === \"pressed\";\n}\n\nfunction isMouseDown(m = \"left\"): boolean {\n\treturn app.mouseStates[m] === \"pressed\" || app.mouseStates[m] === \"down\";\n}\n\nfunction isMouseReleased(m = \"left\"): boolean {\n\treturn app.mouseStates[m] === \"released\";\n}\n\nfunction isMouseMoved(): boolean {\n\treturn app.isMouseMoved;\n}\n\nfunction isKeyPressed(k?: string): boolean {\n\tif (k === undefined) {\n\t\treturn app.isKeyPressed;\n\t} else {\n\t\treturn app.keyStates[k] === \"pressed\";\n\t}\n}\n\nfunction isKeyPressedRepeat(k: string): boolean {\n\tif (k === undefined) {\n\t\treturn app.isKeyPressedRepeat;\n\t} else {\n\t\treturn app.keyStates[k] === \"pressed\" || app.keyStates[k] === \"rpressed\";\n\t}\n}\n\nfunction isKeyDown(k: string): boolean {\n\treturn app.keyStates[k] === \"pressed\"\n\t\t|| app.keyStates[k] === \"rpressed\"\n\t\t|| app.keyStates[k] === \"down\";\n}\n\nfunction isKeyReleased(k?: string): boolean {\n\tif (k === undefined) {\n\t\treturn app.isKeyReleased;\n\t} else {\n\t\treturn app.keyStates[k] === \"released\";\n\t}\n}\n\nfunction charInputted(): string[] {\n\treturn [...app.charInputted];\n}\n\nfunction time(): number {\n\treturn app.time;\n}\n\n// get a base64 png image of canvas\nfunction screenshot(): string {\n\treturn app.canvas.toDataURL();\n}\n\n// TODO: custom cursor\nfunction cursor(c?: Cursor): Cursor {\n\tif (c) {\n\t\tapp.canvas.style.cursor = c;\n\t}\n\treturn app.canvas.style.cursor;\n}\n\nfunction fullscreen(f: boolean = true) {\n\tif (f) {\n\t\tenterFullscreen(app.canvas);\n\t} else {\n\t\texitFullscreen();\n\t}\n}\n\nfunction isFullscreen(): boolean {\n\treturn Boolean(getFullscreenElement());\n}\n\nfunction quit() {\n\tcancelAnimationFrame(app.loopID);\n\tapp.stopped = true;\n}\n\nconst debug: Debug = {\n\tinspect: false,\n\ttimeScale: 1,\n\tshowLog: true,\n\tfps: () => app.fpsCounter.fps,\n\tobjCount(): number {\n\t\t// TODO: recursive count\n\t\treturn game.root.children.length;\n\t},\n\tstepFrame: updateFrame,\n\tdrawCalls: () => gfx.drawCalls,\n\tclearLog: () => game.logs = [],\n\tlog: (msg) => game.logs.unshift(`[${time().toFixed(2)}].time [${msg}].info`),\n\terror: (msg) => game.logs.unshift(`[${time().toFixed(2)}].time [${msg}].error`),\n\tcurRecording: null,\n\tget paused() {\n\t\treturn app.paused;\n\t},\n\tset paused(v) {\n\t\tapp.paused = v;\n\t\tif (v) {\n\t\t\taudio.ctx.suspend();\n\t\t} else {\n\t\t\taudio.ctx.resume();\n\t\t}\n\t}\n};\n\nfunction dt() {\n\treturn app.dt * debug.timeScale;\n}\n\nfunction mouseWorldPos(): Vec2 {\n\tdeprecateMsg(\"mouseWorldPos()\", \"toWorld(mousePos())\");\n\treturn toWorld(mousePos());\n}\n\ntype Camera = {\n\tpos: Vec2,\n\tscale: Vec2,\n\tangle: number,\n\tshake: number,\n};\n\ntype Layer = {\n\torder: number,\n}\n\ntype TaggedEvent = {\n\ttag: string,\n\tcb: (...args) => void,\n};\n\ntype KeyEvent = {\n\tkey: string,\n\tcb(),\n};\n\ntype MouseInputEvent = {\n\tcb(),\n};\n\ntype LoadEvent = () => void;\ntype NextFrameEvent = () => void;\ntype MouseEvent = () => void;\ntype CharEvent = (ch: string) => void;\n\nfunction layers(list: string[], def?: string) {\n\n\tlist.forEach((name, idx) => {\n\t\tgame.layers[name] = idx + 1;\n\t});\n\n\tif (def) {\n\t\tgame.defLayer = def;\n\t}\n\n}\n\nfunction camPos(...pos): Vec2 {\n\tif (pos.length > 0) {\n\t\tgame.cam.pos = vec2(...pos);\n\t}\n\treturn game.cam.pos.clone();\n}\n\nfunction camScale(...scale): Vec2 {\n\tif (scale.length > 0) {\n\t\tgame.cam.scale = vec2(...scale);\n\t}\n\treturn game.cam.scale.clone();\n}\n\nfunction camRot(angle: number): number {\n\tif (angle !== undefined) {\n\t\tgame.cam.angle = angle;\n\t}\n\treturn game.cam.angle;\n}\n\nfunction shake(intensity: number = 12) {\n\tgame.cam.shake = intensity;\n}\n\nfunction toScreen(p: Vec2): Vec2 {\n\treturn game.cam.transform.multVec2(p);\n}\n\nfunction toWorld(p: Vec2): Vec2 {\n\treturn game.cam.transform.invert().multVec2(p);\n}\n\nfunction make<T>(comps: CompList<T>): GameObj<T> {\n\n\tconst compStates = new Map();\n\tconst customState = {};\n\tlet events = {};\n\n\tconst obj = {\n\n\t\t_id: uid(),\n\t\thidden: false,\n\t\tpaused: false,\n\t\tchildren: [],\n\t\tparent: null,\n\n\t\t// TODO: accept gameobj\n\t\tadd<T2>(comps: CompList<T2>): GameObj<T2> {\n\t\t\tif (this !== game.root) {\n\t\t\t\tthrow new Error(\"Children game object not supported yet\");\n\t\t\t}\n\t\t\tconst obj = make(comps);\n\t\t\tobj.parent = this;\n\t\t\tobj.trigger(\"add\");\n\t\t\tonLoad(() => obj.trigger(\"load\"));\n\t\t\tthis.children.push(obj);\n\t\t\treturn obj;\n\t\t},\n\n\t\t// TODO: use add()\n\t\treadd(obj: GameObj): GameObj {\n\t\t\tthis.remove(obj);\n\t\t\tthis.children.push(obj);\n\t\t\treturn obj;\n\t\t},\n\n\t\tremove(obj: GameObj): void {\n\t\t\tconst idx = this.children.indexOf(obj);\n\t\t\tif (idx !== -1) {\n\t\t\t\tobj.parent = null;\n\t\t\t\tobj.trigger(\"destroy\");\n\t\t\t\tthis.children.splice(idx, 1);\n\t\t\t}\n\t\t},\n\n\t\tremoveAll(tag: Tag) {\n\t\t\tthis.every(tag, (obj) => this.remove(obj));\n\t\t},\n\n\t\tupdate() {\n\t\t\tif (this.paused) return;\n\t\t\tthis.revery((child) => child.update());\n\t\t\tthis.trigger(\"update\");\n\t\t},\n\n\t\tdraw() {\n\t\t\tif (this.hidden) return;\n\t\t\tpushTransform();\n\t\t\tpushTranslate(this.pos);\n\t\t\tpushScale(this.scale);\n\t\t\tpushRotateZ(this.angle);\n\t\t\tthis.every((child) => child.draw());\n\t\t\tthis.trigger(\"draw\");\n\t\t\tpopTransform();\n\t\t},\n\n\t\t// use a comp, or tag\n\t\tuse(comp: Comp | Tag) {\n\n\t\t\tif (!comp) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// tag\n\t\t\tif (typeof comp === \"string\") {\n\t\t\t\treturn this.use({\n\t\t\t\t\tid: comp\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// clear if overwrite\n\t\t\tif (comp.id) {\n\t\t\t\tthis.unuse(comp.id);\n\t\t\t\tcompStates.set(comp.id, {});\n\t\t\t}\n\n\t\t\t// state source location\n\t\t\tconst state = comp.id ? compStates.get(comp.id) : customState;\n\n\t\t\tstate.cleanups = [];\n\n\t\t\tfor (const k in comp) {\n\n\t\t\t\tif (COMP_DESC.has(k)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// event / custom method\n\t\t\t\tif (typeof comp[k] === \"function\") {\n\t\t\t\t\tconst func = comp[k].bind(this);\n\t\t\t\t\tif (COMP_EVENTS.has(k)) {\n\t\t\t\t\t\tstate.cleanups.push(this.on(k, func));\n\t\t\t\t\t\tstate[k] = func;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate[k] = func;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tstate[k] = comp[k];\n\t\t\t\t}\n\n\t\t\t\tif (this[k] === undefined) {\n\t\t\t\t\t// assign comp fields to game obj\n\t\t\t\t\tObject.defineProperty(this, k, {\n\t\t\t\t\t\tget: () => state[k],\n\t\t\t\t\t\tset: (val) => state[k] = val,\n\t\t\t\t\t\tconfigurable: true,\n\t\t\t\t\t\tenumerable: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst checkDeps = () => {\n\t\t\t\tif (!comp.require) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const dep of comp.require) {\n\t\t\t\t\tif (!this.c(dep)) {\n\t\t\t\t\t\tthrow new Error(`comp '${comp.id}' requires comp '${dep}'`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// check deps or run add event\n\t\t\tif (this.exists()) {\n\t\t\t\tif (comp.add) {\n\t\t\t\t\tcomp.add.call(this);\n\t\t\t\t}\n\t\t\t\tif (comp.load) {\n\t\t\t\t\tonLoad(() => comp.load.call(this));\n\t\t\t\t}\n\t\t\t\tcheckDeps();\n\t\t\t} else {\n\t\t\t\tif (comp.require) {\n\t\t\t\t\tstate.cleanups.push(this.on(\"add\", checkDeps));\n\t\t\t\t}\n\t\t\t}\n\n\t\t},\n\n\t\tunuse(id: Tag) {\n\t\t\tif (compStates.has(id)) {\n\t\t\t\tconst comp = compStates.get(id);\n\t\t\t\tcomp.cleanups.forEach((f) => f());\n\t\t\t\tfor (const k in comp) {\n\t\t\t\t\tdelete comp[k];\n\t\t\t\t}\n\t\t\t}\n\t\t\tcompStates.delete(id);\n\t\t},\n\n\t\tc(id: Tag): Comp {\n\t\t\treturn compStates.get(id);\n\t\t},\n\n\t\t// TODO: a recursive variant\n\t\tget(t?: Tag | Tag[]): GameObj[] {\n\t\t\treturn this.children\n\t\t\t\t.filter((child) => t ? child.is(t) : true)\n\t\t\t\t.sort((o1, o2) => {\n\t\t\t\t\t// TODO: layers are deprecated\n\t\t\t\t\tconst l1 = game.layers[o1.layer ?? game.defLayer] ?? 0;\n\t\t\t\t\tconst l2 = game.layers[o2.layer ?? game.defLayer] ?? 0;\n\t\t\t\t\t// if on same layer, use \"z\" comp to decide which is on top, if given\n\t\t\t\t\tif (l1 == l2) {\n\t\t\t\t\t\treturn (o1.z ?? 0) - (o2.z ?? 0);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn l1 - l2;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t},\n\n\t\tevery<T>(t: Tag | Tag[] | ((obj: GameObj) => T), f?: (obj: GameObj) => T) {\n\t\t\tif (typeof t === \"function\" && f === undefined) {\n\t\t\t\treturn this.get().forEach((obj) => t(obj));\n\t\t\t} else if (typeof t === \"string\" || Array.isArray(t)) {\n\t\t\t\treturn this.get(t).forEach((obj) => f(obj));\n\t\t\t}\n\t\t},\n\n\t\trevery<T>(t: Tag | Tag[] | ((obj: GameObj) => T), f?: (obj: GameObj) => T) {\n\t\t\tif (typeof t === \"function\" && f === undefined) {\n\t\t\t\treturn this.get().reverse().forEach((obj) => t(obj));\n\t\t\t} else if (typeof t === \"string\" || Array.isArray(t)) {\n\t\t\t\treturn this.get(t).reverse().forEach((obj) => f(obj));\n\t\t\t}\n\t\t},\n\n\t\texists(): boolean {\n\t\t\tif (this.parent === game.root) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn this.parent?.exists();\n\t\t\t}\n\t\t},\n\n\t\tis(tag: Tag | Tag[]): boolean {\n\t\t\tif (tag === \"*\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (Array.isArray(tag)) {\n\t\t\t\tfor (const t of tag) {\n\t\t\t\t\tif (!this.c(t)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn this.c(tag) != null;\n\t\t\t}\n\t\t},\n\n\t\ton(ev: string, cb): EventCanceller {\n\t\t\tif (!events[ev]) {\n\t\t\t\tevents[ev] = new IDList();\n\t\t\t}\n\t\t\treturn events[ev].pushd(cb);\n\t\t},\n\n\t\taction(...args): EventCanceller {\n\t\t\tconsole.warn(\"action() is deprecated. Use onUpdate() instead\")\n\t\t\treturn this.onUpdate(...args);\n\t\t},\n\n\t\ttrigger(ev: string, ...args): void {\n\n\t\t\tif (events[ev]) {\n\t\t\t\tevents[ev].forEach((cb) => cb.call(this, ...args));\n\t\t\t}\n\n\t\t\tconst gEvents = game.objEvents[ev];\n\n\t\t\tif (gEvents) {\n\t\t\t\tgEvents.forEach((e) => {\n\t\t\t\t\tif (this.is(e.tag)) {\n\t\t\t\t\t\te.cb(this, ...args);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t},\n\n\t\tdestroy() {\n\t\t\tthis.parent?.remove(this);\n\t\t},\n\n\t\tinspect() {\n\t\t\tconst info = {};\n\t\t\tfor (const [tag, comp] of compStates) {\n\t\t\t\tinfo[tag] = comp.inspect ? comp.inspect() : null;\n\t\t\t}\n\t\t\treturn info;\n\t\t},\n\n\t\tonUpdate(cb: () => void): EventCanceller {\n\t\t\treturn this.on(\"update\", cb);\n\t\t},\n\n\t\tonDraw(cb: () => void): EventCanceller {\n\t\t\treturn this.on(\"draw\", cb);\n\t\t},\n\n\t\tonDestroy(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"destroy\", action);\n\t\t},\n\n\t\tclearEvents() {\n\t\t\tevents = {}\n\t\t},\n\n\t};\n\n\tfor (const comp of comps) {\n\t\tobj.use(comp);\n\t}\n\n\treturn obj as unknown as GameObj<T>;\n\n}\n\n// add an event to a tag\nfunction on(event: string, tag: Tag, cb: (obj: GameObj, ...args) => void): EventCanceller {\n\tif (!game.objEvents[event]) {\n\t\tgame.objEvents[event] = new IDList();\n\t}\n\treturn game.objEvents[event].pushd({\n\t\ttag: tag,\n\t\tcb: cb,\n\t});\n}\n\n// add update event to a tag or global update\nfunction onUpdate(tag: Tag | (() => void), cb?: (obj: GameObj) => void): EventCanceller {\n\tif (typeof tag === \"function\" && cb === undefined) {\n\t\treturn game.root.onUpdate(tag);\n\t} else if (typeof tag === \"string\") {\n\t\treturn on(\"update\", tag, cb);\n\t}\n}\n\n// add draw event to a tag or global draw\nfunction onDraw(tag: Tag | (() => void), cb?: (obj: GameObj) => void) {\n\tif (typeof tag === \"function\" && cb === undefined) {\n\t\treturn game.root.onDraw(tag);\n\t} else if (typeof tag === \"string\") {\n\t\treturn on(\"draw\", tag, cb);\n\t}\n}\n\n// add an event that runs with objs with t1 collides with objs with t2\nfunction onCollide(\n\tt1: Tag,\n\tt2: Tag,\n\tf: (a: GameObj, b: GameObj, col?: Collision) => void,\n): EventCanceller {\n\tconst e1 = on(\"collide\", t1, (a, b, col) => b.is(t2) && f(a, b, col));\n\tconst e2 = on(\"collide\", t2, (a, b, col) => b.is(t1) && f(b, a, col));\n\tconst e3 = onUpdate(t1, (o1: GameObj) => {\n\t\tif (!o1.area) {\n\t\t\tthrow new Error(\"onCollide() requires the object to have area() component\");\n\t\t}\n\t\to1._checkCollisions(t2, (o2) => {\n\t\t\tf(o1, o2);\n\t\t});\n\t});\n\treturn () => [e1, e2, e3].forEach((f) => f());\n}\n\n// add an event that runs when objs with tag t is clicked\nfunction onClick(tag: Tag | (() => void), cb?: (obj: GameObj) => void): EventCanceller {\n\tif (typeof tag === \"function\") {\n\t\treturn onMousePress(tag);\n\t} else {\n\t\treturn onUpdate(tag, (o: GameObj) => {\n\t\t\tif (!o.area) throw new Error(\"onClick() requires the object to have area() component\");\n\t\t\tif (o.isClicked()) {\n\t\t\t\tcb(o);\n\t\t\t}\n\t\t});\n\t}\n}\n\n// add an event that runs when objs with tag t is hovered\nfunction onHover(t: string, onHover: (obj: GameObj) => void, onNotHover?: (obj: GameObj) => void): EventCanceller {\n\treturn onUpdate(t, (o: GameObj) => {\n\t\tif (!o.area) throw new Error(\"onHover() requires the object to have area() component\");\n\t\tif (o.isHovering()) {\n\t\t\tonHover(o);\n\t\t} else {\n\t\t\tif (onNotHover) {\n\t\t\t\tonNotHover(o);\n\t\t\t}\n\t\t}\n\t});\n}\n\n// add an event that'd be run after t\nfunction wait(t: number, f?: () => void): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tgame.timers.push(new Timer(t, () => {\n\t\t\tif (f) f();\n\t\t\tresolve();\n\t\t}))\n\t});\n}\n\n// add an event that's run every t seconds\nfunction loop(t: number, f: () => void): EventCanceller {\n\n\tlet stopped = false;\n\n\tconst newF = () => {\n\t\tif (stopped) {\n\t\t\treturn;\n\t\t}\n\t\tf();\n\t\twait(t, newF);\n\t};\n\n\tnewF();\n\n\treturn () => stopped = true;\n\n}\n\n// input callbacks\nfunction onKeyDown(k: Key | Key[], f: () => void): EventCanceller {\n\tif (Array.isArray(k)) {\n\t\tconst cancellers = k.map((key) => onKeyDown(key, f));\n\t\treturn () => cancellers.forEach((cb) => cb());\n\t} {\n\t\treturn game.on(\"input\", () => isKeyDown(k) && f());\n\t}\n}\n\nfunction onKeyPress(k: Key | Key[] | (() => void), f?: () => void): EventCanceller {\n\tif (Array.isArray(k)) {\n\t\tconst cancellers = k.map((key) => onKeyPress(key, f));\n\t\treturn () => cancellers.forEach((cb) => cb());\n\t} else if (typeof k === \"function\") {\n\t\treturn game.on(\"input\", () => isKeyPressed() && k());\n\t} else {\n\t\treturn game.on(\"input\", () => isKeyPressed(k) && f());\n\t}\n}\n\nfunction onKeyPressRepeat(k: Key | Key[] | (() => void), f?: () => void): EventCanceller {\n\tif (Array.isArray(k)) {\n\t\tconst cancellers = k.map((key) => onKeyPressRepeat(key, f));\n\t\treturn () => cancellers.forEach((cb) => cb());\n\t} else if (typeof k === \"function\") {\n\t\treturn game.on(\"input\", () => isKeyPressed() && k());\n\t} else {\n\t\treturn game.on(\"input\", () => isKeyPressedRepeat(k) && f());\n\t}\n}\n\nfunction onKeyRelease(k: Key | Key[] | (() => void), f?: () => void): EventCanceller {\n\tif (Array.isArray(k)) {\n\t\tconst cancellers = k.map((key) => onKeyRelease(key, f));\n\t\treturn () => cancellers.forEach((cb) => cb());\n\t} else if (typeof k === \"function\") {\n\t\treturn game.on(\"input\", () => isKeyReleased() && k());\n\t} else {\n\t\treturn game.on(\"input\", () => isKeyReleased(k) && f());\n\t}\n}\n\nfunction onMouseDown(\n\tm: MouseButton | ((pos?: Vec2) => void),\n\taction?: (pos?: Vec2) => void\n): EventCanceller {\n\tif (typeof m === \"function\") {\n\t\treturn game.on(\"input\", () => isMouseDown() && m(mousePos()));\n\t} else {\n\t\treturn game.on(\"input\", () => isMouseDown(m) && action(mousePos()));\n\t}\n}\n\nfunction onMousePress(\n\tm: MouseButton | ((pos?: Vec2) => void),\n\taction?: (pos?: Vec2) => void\n): EventCanceller {\n\tif (typeof m === \"function\") {\n\t\treturn game.on(\"input\", () => isMousePressed() && m(mousePos()));\n\t} else {\n\t\treturn game.on(\"input\", () => isMousePressed(m) && action(mousePos()));\n\t}\n}\n\nfunction onMouseRelease(\n\tm: MouseButton | ((pos?: Vec2) => void),\n\taction?: (pos?: Vec2) => void\n): EventCanceller {\n\tif (typeof m === \"function\") {\n\t\treturn game.on(\"input\", () => isMouseReleased() && m(mousePos()));\n\t} else {\n\t\treturn game.on(\"input\", () => isMouseReleased(m) && action(mousePos()));\n\t}\n}\n\nfunction onMouseMove(f: (pos: Vec2, dpos: Vec2) => void): EventCanceller {\n\treturn game.on(\"input\", () => isMouseMoved() && f(mousePos(), mouseDeltaPos()));\n}\n\nfunction onCharInput(f: (ch: string) => void): EventCanceller {\n\treturn game.on(\"input\", () => charInputted().forEach((ch) => f(ch)));\n}\n\nfunction onTouchStart(f: (id: TouchID, pos: Vec2) => void): EventCanceller {\n\treturn game.on(\"onTouchStart\", f);\n}\n\nfunction onTouchMove(f: (id: TouchID, pos: Vec2) => void): EventCanceller {\n\treturn game.on(\"onTouchMove\", f);\n}\n\nfunction onTouchEnd(f: (id: TouchID, pos: Vec2) => void): EventCanceller {\n\treturn game.on(\"onTouchEnd\", f);\n}\n\nfunction enterDebugMode() {\n\n\tonKeyPress(\"f1\", () => {\n\t\tdebug.inspect = !debug.inspect;\n\t});\n\n\tonKeyPress(\"f2\", () => {\n\t\tdebug.clearLog();\n\t});\n\n\tonKeyPress(\"f8\", () => {\n\t\tdebug.paused = !debug.paused;\n\t});\n\n\tonKeyPress(\"f7\", () => {\n\t\tdebug.timeScale = toFixed(clamp(debug.timeScale - 0.2, 0, 2), 1);\n\t});\n\n\tonKeyPress(\"f9\", () => {\n\t\tdebug.timeScale = toFixed(clamp(debug.timeScale + 0.2, 0, 2), 1);\n\t});\n\n\tonKeyPress(\"f10\", () => {\n\t\tdebug.stepFrame();\n\t});\n\n\tonKeyPress(\"f5\", () => {\n\t\tdownloadURL(screenshot(), \"kaboom.png\");\n\t});\n\n\tonKeyPress(\"f6\", () => {\n\t\tif (debug.curRecording) {\n\t\t\tdebug.curRecording.download();\n\t\t\tdebug.curRecording = null;\n\t\t} else {\n\t\t\tdebug.curRecording = record();\n\t\t}\n\t});\n\n}\n\nfunction enterBurpMode() {\n\tonKeyPress(\"b\", burp);\n}\n\n// get / set gravity\nfunction gravity(g?: number): number {\n\tif (g !== undefined) {\n\t\tgame.gravity = g;\n\t}\n\treturn game.gravity;\n}\n\nfunction regCursor(c: Cursor, draw: string | ((mpos: Vec2) => void)) {\n\t// TODO\n}\n\nfunction makeCollision(target: GameObj<any>, dis: Vec2): Collision {\n\treturn {\n\t\ttarget: target,\n\t\tdisplacement: dis,\n\t\tisTop: () => dis.y > 0,\n\t\tisBottom: () => dis.y < 0,\n\t\tisLeft: () => dis.x > 0,\n\t\tisRight: () => dis.x < 0,\n\t};\n}\n\n// TODO: manage global velocity here?\nfunction pos(...args): PosComp {\n\n\treturn {\n\n\t\tid: \"pos\",\n\t\tpos: vec2(...args),\n\n\t\t// TODO: clean\n\t\tmoveBy(...args): Collision | null {\n\n\t\t\tconst p = vec2(...args);\n\t\t\tlet dx = p.x;\n\t\t\tlet dy = p.y;\n\t\t\tlet col = null;\n\n\t\t\tif (this.solid && this.area?.shape === \"rect\") {\n\n\t\t\t\tlet a1 = this.worldArea();\n\n\t\t\t\t// TODO: definitely shouln't iterate through all solid objs\n\t\t\t\tgame.root.every((other) => {\n\n\t\t\t\t\t// make sure we still exist, don't check with self, and only\n\t\t\t\t\t// check with other solid objects\n\t\t\t\t\tif (\n\t\t\t\t\t\t!this.exists()\n\t\t\t\t\t\t|| other === this\n\t\t\t\t\t\t|| !other.solid\n\t\t\t\t\t\t|| other.area?.shape !== \"rect\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst a2 = other.worldArea();\n\t\t\t\t\tlet md = minkDiff(a2, a1);\n\n\t\t\t\t\t// if they're already overlapping, push them away first\n\t\t\t\t\tif (testRectPoint(md, vec2(0))) {\n\n\t\t\t\t\t\tlet dist = Math.min(\n\t\t\t\t\t\t\tMath.abs(md.p1.x),\n\t\t\t\t\t\t\tMath.abs(md.p2.x),\n\t\t\t\t\t\t\tMath.abs(md.p1.y),\n\t\t\t\t\t\t\tMath.abs(md.p2.y),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst res = (() => {\n\t\t\t\t\t\t\tswitch (dist) {\n\t\t\t\t\t\t\t\tcase Math.abs(md.p1.x): return vec2(dist, 0);\n\t\t\t\t\t\t\t\tcase Math.abs(md.p2.x): return vec2(-dist, 0);\n\t\t\t\t\t\t\t\tcase Math.abs(md.p1.y): return vec2(0, dist);\n\t\t\t\t\t\t\t\tcase Math.abs(md.p2.y): return vec2(0, -dist);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})();\n\n\t\t\t\t\t\tthis.pos = this.pos.sub(res);\n\n\t\t\t\t\t\t// calculate new mink diff\n\t\t\t\t\t\ta1 = this.worldArea();\n\t\t\t\t\t\tmd = minkDiff(a2, a1);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst ray = { p1: vec2(0), p2: vec2(dx, dy) };\n\t\t\t\t\tlet minT = 1;\n\t\t\t\t\tconst p1 = md.p1;\n\t\t\t\t\tconst p2 = vec2(md.p1.x, md.p2.y);\n\t\t\t\t\tconst p3 = md.p2;\n\t\t\t\t\tconst p4 = vec2(md.p2.x, md.p1.y);\n\t\t\t\t\tlet numCols = 0;\n\t\t\t\t\tconst lines = {\n\t\t\t\t\t\t\"right\": { p1: p1, p2: p2, },\n\t\t\t\t\t\t\"top\": { p1: p2, p2: p3, },\n\t\t\t\t\t\t\"left\": { p1: p3, p2: p4, },\n\t\t\t\t\t\t\"bottom\": { p1: p4, p2: p1, },\n\t\t\t\t\t};\n\n\t\t\t\t\tfor (const s in lines) {\n\t\t\t\t\t\tconst line = lines[s];\n\t\t\t\t\t\t// if moving along a side, we forgive\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(dx === 0 && line.p1.x === 0 && line.p2.x === 0)\n\t\t\t\t\t\t\t||\n\t\t\t\t\t\t\t(dy === 0 && line.p1.y === 0 && line.p2.y === 0)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tminT = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst t = testLineLineT(ray, line);\n\t\t\t\t\t\tif (t != null) {\n\t\t\t\t\t\t\tnumCols++;\n\t\t\t\t\t\t\tif (t < minT) {\n\t\t\t\t\t\t\t\tminT = t;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// if moving away, we forgive\n\t\t\t\t\tif (\n\t\t\t\t\t\tminT < 1\n\t\t\t\t\t\t&& !(minT === 0 && numCols == 1 && !testRectPoint(md, vec2(dx, dy)))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst dis = vec2(-dx * (1 - minT), -dy * (1 - minT));\n\t\t\t\t\t\tdx *= minT;\n\t\t\t\t\t\tdy *= minT;\n\t\t\t\t\t\tcol = makeCollision(other, dis);\n\t\t\t\t\t}\n\n\t\t\t\t});\n\n\t\t\t}\n\n\t\t\tthis.pos.x += dx;\n\t\t\tthis.pos.y += dy;\n\n\t\t\tif (col) {\n\t\t\t\tthis.trigger(\"collide\", col.target, col);\n\t\t\t\tcol.target.trigger(\"collide\", this, makeCollision(this, col.displacement.scale(-1)));\n\t\t\t}\n\n\t\t\treturn col;\n\n\t\t},\n\n\t\t// move with velocity (pixels per second)\n\t\tmove(...args): Collision | null {\n\t\t\treturn this.moveBy(vec2(...args).scale(dt()));\n\t\t},\n\n\t\t// move to a destination, with optional speed\n\t\tmoveTo(...args) {\n\t\t\tif (typeof args[0] === \"number\" && typeof args[1] === \"number\") {\n\t\t\t\treturn this.moveTo(vec2(args[0], args[1]), args[2]);\n\t\t\t}\n\t\t\tconst dest = args[0];\n\t\t\tconst speed = args[1];\n\t\t\tif (speed === undefined) {\n\t\t\t\tthis.pos = vec2(dest);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst diff = dest.sub(this.pos);\n\t\t\tif (diff.len() <= speed * dt()) {\n\t\t\t\tthis.pos = vec2(dest);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.move(diff.unit().scale(speed));\n\t\t},\n\n\t\t// TODO\n\t\t// get the screen position (transformed by camera)\n\t\tscreenPos(): Vec2 {\n\t\t\tif (this.fixed) {\n\t\t\t\treturn this.pos;\n\t\t\t} else {\n\t\t\t\treturn toScreen(this.pos);\n\t\t\t}\n\t\t},\n\n\t\tinspect() {\n\t\t\treturn `(${Math.round(this.pos.x)}, ${Math.round(this.pos.y)})`;\n\t\t},\n\n\t};\n\n};\n\n// TODO: allow single number assignment\nfunction scale(...args): ScaleComp {\n\tif (args.length === 0) {\n\t\treturn scale(1);\n\t}\n\treturn {\n\t\tid: \"scale\",\n\t\tscale: vec2(...args),\n\t\tscaleTo(...args) {\n\t\t\tthis.scale = vec2(...args);\n\t\t},\n\t\tinspect() {\n\t\t\tif (typeof this.scale === \"number\") {\n\t\t\t\treturn `${toFixed(this.scale, 2)}`;\n\t\t\t} else {\n\t\t\t\treturn `(${toFixed(this.scale.x, 2)}, ${toFixed(this.scale.y, 2)})`;\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction rotate(r: number): RotateComp {\n\treturn {\n\t\tid: \"rotate\",\n\t\tangle: r ?? 0,\n\t\tinspect() {\n\t\t\treturn `${Math.round(this.angle)}`;\n\t\t},\n\t};\n}\n\nfunction color(...args): ColorComp {\n\treturn {\n\t\tid: \"color\",\n\t\tcolor: rgb(...args),\n\t\tinspect() {\n\t\t\treturn this.color.str();\n\t\t},\n\t};\n}\n\nfunction toFixed(n: number, f: number) {\n\treturn Number(n.toFixed(f));\n}\n\nfunction opacity(a: number): OpacityComp {\n\treturn {\n\t\tid: \"opacity\",\n\t\topacity: a ?? 1,\n\t\tinspect() {\n\t\t\treturn `${toFixed(this.opacity, 2)}`;\n\t\t},\n\t};\n}\n\nfunction origin(o: Origin | Vec2): OriginComp {\n\tif (!o) {\n\t\tthrow new Error(\"please define an origin\");\n\t}\n\treturn {\n\t\tid: \"origin\",\n\t\torigin: o,\n\t\tinspect() {\n\t\t\tif (typeof this.origin === \"string\") {\n\t\t\t\treturn this.origin;\n\t\t\t} else {\n\t\t\t\treturn this.origin.str();\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction layer(l: string): LayerComp {\n\treturn {\n\t\tid: \"layer\",\n\t\tlayer: l,\n\t\tinspect() {\n\t\t\treturn this.layer ?? game.defLayer;\n\t\t},\n\t};\n}\n\nfunction z(z: number): ZComp {\n\treturn {\n\t\tid: \"z\",\n\t\tz: z,\n\t\tinspect() {\n\t\t\treturn `${this.z}`;\n\t\t},\n\t};\n}\n\nfunction follow(obj: GameObj, offset?: Vec2): FollowComp {\n\treturn {\n\t\tid: \"follow\",\n\t\trequire: [ \"pos\", ],\n\t\tfollow: {\n\t\t\tobj: obj,\n\t\t\toffset: offset ?? vec2(0),\n\t\t},\n\t\tadd() {\n\t\t\tif (obj.exists()) {\n\t\t\t\tthis.pos = this.follow.obj.pos.add(this.follow.offset);\n\t\t\t}\n\t\t},\n\t\tupdate() {\n\t\t\tif (obj.exists()) {\n\t\t\t\tthis.pos = this.follow.obj.pos.add(this.follow.offset);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction move(dir: number | Vec2, speed: number): MoveComp {\n\tconst d = typeof dir === \"number\" ? Vec2.fromAngle(dir) : dir.unit();\n\treturn {\n\t\tid: \"move\",\n\t\trequire: [ \"pos\", ],\n\t\tupdate() {\n\t\t\tthis.move(d.scale(speed));\n\t\t},\n\t};\n}\n\nfunction outview(opt: OutviewCompOpt = {}): OutviewComp {\n\tlet timer = 0;\n\tlet isOut = false;\n\treturn {\n\t\tid: \"outview\",\n\t\trequire: [ \"pos\", \"area\", ],\n\t\tisOutOfView(): boolean {\n\t\t\tconst offset = vec2(opt.offset ?? 0);\n\t\t\tconst screenRect = new Rect(\n\t\t\t\tvec2(0, 0).sub(offset),\n\t\t\t\tvec2(width(), height()).add(offset),\n\t\t\t);\n\t\t\treturn !testAreaRect(this.screenArea(), screenRect);\n\t\t},\n\t\tonExitView(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"exitView\", action);\n\t\t},\n\t\tonEnterView(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"enterView\", action);\n\t\t},\n\t\tupdate() {\n\t\t\tif (this.isOutOfView()) {\n\t\t\t\tif (!isOut) {\n\t\t\t\t\tthis.trigger(\"exitView\");\n\t\t\t\t\tisOut = true;\n\t\t\t\t}\n\t\t\t\tif (opt.delay) {\n\t\t\t\t\ttimer += dt();\n\t\t\t\t\tif (timer < opt.delay) return\n\t\t\t\t}\n\t\t\t\tif (opt.hide) this.hidden = true;\n\t\t\t\tif (opt.pause) this.paused = true;\n\t\t\t\tif (opt.destroy) this.destroy();\n\t\t\t} else {\n\t\t\t\tif (isOut) {\n\t\t\t\t\tthis.trigger(\"enterView\");\n\t\t\t\t\tisOut = false;\n\t\t\t\t}\n\t\t\t\ttimer = 0;\n\t\t\t\tif (opt.hide) this.hidden = false;\n\t\t\t\tif (opt.pause) this.paused = false;\n\t\t\t}\n\t\t},\n\t\tinspect() {\n\t\t\treturn this.isOutOfView();\n\t\t},\n\t};\n}\n\nfunction cleanup(opt: (number | undefined) | CleanupCompOpt = {}): CleanupComp {\n\tif (typeof opt === \"number\") {\n\t\tdeprecateMsg(\"clean(time)\", \"cleanup({ delay: time })\");\n\t\treturn {\n\t\t\t...outview({\n\t\t\t\tdestroy: true,\n\t\t\t\tdelay: opt,\n\t\t\t}),\n\t\t\tid: \"cleanup\",\n\t\t};\n\t}\n\treturn {\n\t\t...outview({\n\t\t\tdestroy: true,\n\t\t\tonExitView: opt.onCleanup,\n\t\t\toffset: opt.offset,\n\t\t\tdelay: opt.delay,\n\t\t}),\n\t\tid: \"cleanup\",\n\t};\n}\n\nfunction area(opt: AreaCompOpt = {}): AreaComp {\n\n\tconst colliding = {};\n\n\treturn {\n\n\t\tid: \"area\",\n\n\t\tadd() {\n\t\t\tif (this.area.cursor) {\n\t\t\t\t// TODO: collect\n\t\t\t\tthis.onHover(() => cursor(this.area.cursor));\n\t\t\t}\n\t\t},\n\n\t\tarea: {\n\t\t\tshape: \"rect\",\n\t\t\toffset: opt.offset ?? vec2(0),\n\t\t\twidth: opt.width,\n\t\t\theight: opt.height,\n\t\t\tscale: opt.scale ?? vec2(1),\n\t\t\tcursor: opt.cursor,\n\t\t},\n\n\t\tisClicked(): boolean {\n\t\t\treturn isMousePressed() && this.isHovering();\n\t\t},\n\n\t\tisHovering() {\n\t\t\tconst mpos = this.fixed ? mousePos() : toWorld(mousePos());\n\t\t\treturn this.hasPoint(mpos);\n\t\t},\n\n\t\tisColliding(other) {\n\t\t\tif (!other.area || !other.exists()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst a1 = this.worldArea();\n\t\t\tconst a2 = other.worldArea();\n\t\t\treturn testAreaArea(a1, a2);\n\t\t},\n\n\t\tisTouching(other) {\n\t\t\tif (!other.area || !other.exists()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// TODO: support other shapes\n\t\t\tconst a1 = this.worldArea();\n\t\t\tconst a2 = other.worldArea();\n\t\t\treturn testRectRect2(a1, a2);\n\t\t},\n\n\t\tonClick(f: () => void): EventCanceller {\n\t\t\treturn this.onUpdate(() => {\n\t\t\t\tif (this.isClicked()) {\n\t\t\t\t\tf();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tonHover(onHover: () => void, onNotHover: () => void): EventCanceller {\n\t\t\treturn this.onUpdate(() => {\n\t\t\t\tif (this.isHovering()) {\n\t\t\t\t\tonHover();\n\t\t\t\t} else {\n\t\t\t\t\tif (onNotHover) {\n\t\t\t\t\t\tonNotHover();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tonCollide(tag: Tag, f: (o: GameObj, col?: Collision) => void): EventCanceller {\n\t\t\tconst e1 = this.onUpdate(() => this._checkCollisions(tag, f));\n\t\t\tconst e2 = this.on(\"collide\", (obj, col) => obj.is(tag) && f(obj, col));\n\t\t\treturn () => [e1, e2].forEach((f) => f());\n\t\t},\n\n\t\tclicks(...args) {\n\t\t\tdeprecateMsg(\"clicks()\", \"onClick()\");\n\t\t\treturn this.onClick(...args);\n\t\t},\n\n\t\thovers(...args) {\n\t\t\tdeprecateMsg(\"hovers()\", \"onHover()\");\n\t\t\treturn this.onHover(...args);\n\t\t},\n\n\t\tcollides(...args) {\n\t\t\tdeprecateMsg(\"collides()\", \"onCollide()\");\n\t\t\treturn this.onCollide(...args);\n\t\t},\n\n\t\thasPoint(pt: Vec2): boolean {\n\t\t\treturn testAreaPoint(this.worldArea(), pt);\n\t\t},\n\n\t\t// push an obj out of another if they're overlapped\n\t\tpushOut(obj: GameObj): Vec2 | null {\n\n\t\t\tif (obj === this) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// TODO: support other shapes\n\t\t\tif (obj.area?.shape !== \"rect\") {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst a1 = this.worldArea();\n\t\t\tconst a2 = obj.worldArea();\n\t\t\tconst md = minkDiff(a1, a2);\n\n\t\t\tif (!testRectPoint(md, vec2(0))) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet dist = Math.min(\n\t\t\t\tMath.abs(md.p1.x),\n\t\t\t\tMath.abs(md.p2.x),\n\t\t\t\tMath.abs(md.p1.y),\n\t\t\t\tMath.abs(md.p2.y),\n\t\t\t);\n\n\t\t\tconst res = (() => {\n\t\t\t\tswitch (dist) {\n\t\t\t\t\tcase Math.abs(md.p1.x): return vec2(dist, 0);\n\t\t\t\t\tcase Math.abs(md.p2.x): return vec2(-dist, 0);\n\t\t\t\t\tcase Math.abs(md.p1.y): return vec2(0, dist);\n\t\t\t\t\tcase Math.abs(md.p2.y): return vec2(0, -dist);\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tthis.pos = this.pos.add(res);\n\n\t\t},\n\n\t\t// push object out of other solid objects\n\t\tpushOutAll() {\n\t\t\tgame.root.every(this.pushOut);\n\t\t},\n\n\t\t// @ts-ignore\n\t\t_checkCollisions(tag: Tag) {\n\n\t\t\tgame.root.every(tag, (obj) => {\n\n\t\t\t\tif (this === obj || !this.exists() || colliding[obj._id]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (this.isColliding(obj)) {\n\t\t\t\t\tthis.trigger(\"collide\", obj, null);\n\t\t\t\t\tcolliding[obj._id] = obj;\n\t\t\t\t}\n\n\t\t\t});\n\n\t\t\tfor (const id in colliding) {\n\t\t\t\tconst obj = colliding[id];\n\t\t\t\tif (!this.isColliding(obj)) {\n\t\t\t\t\tdelete colliding[id];\n\t\t\t\t}\n\t\t\t}\n\n\t\t},\n\n\t\t// TODO: doesn't work with nested parent transforms\n\t\t// TODO: cache\n\t\t// TODO: use matrix mult for more accuracy and rotation?\n\t\tworldArea(): Area {\n\n\t\t\tlet w = this.area.width ?? this.width;\n\t\t\tlet h = this.area.height ?? this.height;\n\n\t\t\tif (w == null || h == null) {\n\t\t\t\tthrow new Error(\"failed to get area dimension\");\n\t\t\t}\n\n\t\t\tconst scale = vec2(this.scale ?? 1).scale(this.area.scale);\n\n\t\t\tw *= scale.x;\n\t\t\th *= scale.y;\n\n\t\t\tconst orig = originPt(this.origin || DEF_ORIGIN);\n\t\t\tconst pos = (this.pos ?? vec2(0))\n\t\t\t\t.add(this.area.offset)\n\t\t\t\t.sub(orig.add(1, 1).scale(0.5).scale(w, h));\n\n\t\t\treturn {\n\t\t\t\tshape: \"rect\",\n\t\t\t\tp1: pos,\n\t\t\t\tp2: vec2(pos.x + w, pos.y + h),\n\t\t\t};\n\n\t\t},\n\n\t\tscreenArea(): Area {\n\t\t\tconst area = this.worldArea();\n\t\t\tif (this.fixed) {\n\t\t\t\treturn area;\n\t\t\t} else {\n\t\t\t\treturn {\n\t\t\t\t\tshape: \"rect\",\n\t\t\t\t\tp1: toScreen(area.p1),\n\t\t\t\t\tp2: toScreen(area.p2),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t};\n\n}\n\n// make the list of common render properties from the \"pos\", \"scale\", \"color\", \"opacity\", \"rotate\", \"origin\", \"outline\", and \"shader\" components of a character\nfunction getRenderProps(obj: GameObj<any>) {\n\treturn {\n\t\tcolor: obj.color,\n\t\topacity: obj.opacity,\n\t\torigin: obj.origin,\n\t\toutline: obj.outline,\n\t\tfixed: obj.fixed,\n\t\tshader: assets.shaders[obj.shader],\n\t\tuniform: obj.uniform,\n\t};\n}\n\ninterface SpriteCurAnim {\n\tname: string,\n\ttimer: number,\n\tloop: boolean,\n\tspeed: number,\n\tpingpong: boolean,\n\tonEnd: () => void,\n}\n\n// TODO: clean\nfunction sprite(id: string | SpriteData, opt: SpriteCompOpt = {}): SpriteComp {\n\n\tlet spr = null;\n\tlet curAnim: SpriteCurAnim | null = null;\n\n\tfunction calcTexScale(tex: GfxTexture, q: Quad, w?: number, h?: number): Vec2 {\n\t\tconst scale = vec2(1, 1);\n\t\tif (w && h) {\n\t\t\tscale.x = w / (tex.width * q.w);\n\t\t\tscale.y = h / (tex.height * q.h);\n\t\t} else if (w) {\n\t\t\tscale.x = w / (tex.width * q.w);\n\t\t\tscale.y = scale.x;\n\t\t} else if (h) {\n\t\t\tscale.y = h / (tex.height * q.h);\n\t\t\tscale.x = scale.y;\n\t\t}\n\t\treturn scale;\n\t}\n\n\treturn {\n\n\t\tid: \"sprite\",\n\t\t// TODO: allow update\n\t\twidth: 0,\n\t\theight: 0,\n\t\tframe: opt.frame || 0,\n\t\tquad: opt.quad || new Quad(0, 0, 1, 1),\n\t\tanimSpeed: opt.animSpeed ?? 1,\n\n\t\tload() {\n\n\t\t\tif (typeof id === \"string\") {\n\t\t\t\tspr = assets.sprites[id];\n\t\t\t} else {\n\t\t\t\tspr = id;\n\t\t\t}\n\n\t\t\tif (!spr) {\n\t\t\t\tthrow new Error(`sprite not found: \"${id}\"`);\n\t\t\t}\n\n\t\t\tlet q = spr.frames[0].clone();\n\n\t\t\tif (opt.quad) {\n\t\t\t\tq = q.scale(opt.quad);\n\t\t\t}\n\n\t\t\tconst scale = calcTexScale(spr.tex, q, opt.width, opt.height);\n\n\t\t\tthis.width = spr.tex.width * q.w * scale.x;\n\t\t\tthis.height = spr.tex.height * q.h * scale.y;\n\n\t\t\tif (opt.anim) {\n\t\t\t\tthis.play(opt.anim);\n\t\t\t}\n\n\t\t},\n\n\t\tdraw() {\n\t\t\tdrawSprite({\n\t\t\t\t...getRenderProps(this),\n\t\t\t\tsprite: spr,\n\t\t\t\tframe: this.frame,\n\t\t\t\tquad: this.quad,\n\t\t\t\tflipX: opt.flipX,\n\t\t\t\tflipY: opt.flipY,\n\t\t\t\ttiled: opt.tiled,\n\t\t\t\twidth: opt.width,\n\t\t\t\theight: opt.height,\n\t\t\t});\n\t\t},\n\n\t\tupdate() {\n\n\t\t\tif (!curAnim) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst anim = spr.anims[curAnim.name];\n\n\t\t\tif (typeof anim === \"number\") {\n\t\t\t\tthis.frame = anim;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (anim.speed === 0) {\n\t\t\t\tthrow new Error(\"sprite anim speed cannot be 0\");\n\t\t\t}\n\n\t\t\tcurAnim.timer += dt() * this.animSpeed;\n\n\t\t\tif (curAnim.timer >= (1 / curAnim.speed)) {\n\t\t\t\tcurAnim.timer = 0;\n\t\t\t\t// TODO: clean up\n\t\t\t\tif (anim.from > anim.to) {\n\t\t\t\t\tthis.frame--;\n\t\t\t\t\tif (this.frame < anim.to) {\n\t\t\t\t\t\tif (curAnim.loop) {\n\t\t\t\t\t\t\tthis.frame = anim.from;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.frame++;\n\t\t\t\t\t\t\tcurAnim.onEnd();\n\t\t\t\t\t\t\tthis.stop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.frame++;\n\t\t\t\t\tif (this.frame > anim.to) {\n\t\t\t\t\t\tif (curAnim.loop) {\n\t\t\t\t\t\t\tthis.frame = anim.from;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.frame--;\n\t\t\t\t\t\t\tcurAnim.onEnd();\n\t\t\t\t\t\t\tthis.stop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t},\n\n\t\t// TODO: this opt should be used instead of the sprite data opt, if given\n\t\tplay(name: string, opt: SpriteAnimPlayOpt = {}) {\n\n\t\t\tif (!spr) {\n\t\t\t\tonLoad(() => {\n\t\t\t\t\tthis.play(name);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst anim = spr.anims[name];\n\n\t\t\tif (anim == null) {\n\t\t\t\tthrow new Error(`anim not found: ${name}`);\n\t\t\t}\n\n\t\t\tif (curAnim) {\n\t\t\t\tthis.stop();\n\t\t\t}\n\n\t\t\tcurAnim = {\n\t\t\t\tname: name,\n\t\t\t\ttimer: 0,\n\t\t\t\tloop: opt.loop ?? anim.loop ?? false,\n\t\t\t\tpingpong: opt.pingpong ?? anim.pingpong ?? false,\n\t\t\t\tspeed: opt.speed ?? anim.speed ?? 10,\n\t\t\t\tonEnd: opt.onEnd ?? (() => {}),\n\t\t\t};\n\n\t\t\tif (typeof anim === \"number\") {\n\t\t\t\tthis.frame = anim;\n\t\t\t} else {\n\t\t\t\tthis.frame = anim.from;\n\t\t\t}\n\n\t\t\t// TODO: \"animPlay\" is deprecated\n\t\t\tthis.trigger(\"animPlay\", name);\n\t\t\tthis.trigger(\"animStart\", name);\n\n\t\t},\n\n\t\tstop() {\n\t\t\tif (!curAnim) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prevAnim = curAnim.name;\n\t\t\tcurAnim = null;\n\t\t\tthis.trigger(\"animEnd\", prevAnim);\n\t\t},\n\n\t\tnumFrames() {\n\t\t\tif (!spr) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn spr.frames.length;\n\t\t},\n\n\t\tcurAnim() {\n\t\t\treturn curAnim?.name;\n\t\t},\n\n\t\tflipX(b: boolean) {\n\t\t\topt.flipX = b;\n\t\t},\n\n\t\tflipY(b: boolean) {\n\t\t\topt.flipY = b;\n\t\t},\n\n\t\tonAnimEnd(name: string, action: () => void): EventCanceller {\n\t\t\treturn this.on(\"animEnd\", (anim) => {\n\t\t\t\tif (anim === name) {\n\t\t\t\t\taction();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tonAnimStart(name: string, action: () => void): EventCanceller {\n\t\t\treturn this.on(\"animStart\", (anim) => {\n\t\t\t\tif (anim === name) {\n\t\t\t\t\taction();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tinspect() {\n\t\t\tlet msg = \"\";\n\t\t\tif (typeof id === \"string\") {\n\t\t\t\tmsg += JSON.stringify(id);\n\t\t\t} else {\n\t\t\t\tmsg += \"[blob]\";\n\t\t\t}\n\t\t\treturn msg;\n\t\t},\n\n\t};\n\n}\n\nfunction text(t: string, opt: TextCompOpt = {}): TextComp {\n\n\tfunction update(obj: GameObj<TextComp | any>) {\n\n\t\tconst ftext = formatText({\n\t\t\t...getRenderProps(obj),\n\t\t\ttext: obj.text + \"\",\n\t\t\tsize: obj.textSize,\n\t\t\tfont: obj.font,\n\t\t\twidth: opt.width && obj.width,\n\t\t\tletterSpacing: obj.letterSpacing,\n\t\t\tlineSpacing: obj.lineSpacing,\n\t\t\ttransform: obj.transform,\n\t\t\tstyles: obj.styles,\n\t\t});\n\n\t\tobj.width = ftext.width / (obj.scale?.x || 1);\n\t\tobj.height = ftext.height / (obj.scale?.y || 1);\n\n\t\treturn ftext;\n\n\t};\n\n\treturn {\n\n\t\tid: \"text\",\n\t\ttext: t,\n\t\ttextSize: opt.size,\n\t\tfont: opt.font,\n\t\twidth: opt.width,\n\t\theight: 0,\n\t\tlineSpacing: opt.lineSpacing,\n\t\tletterSpacing: opt.letterSpacing,\n\t\ttransform: opt.transform,\n\t\tstyles: opt.styles,\n\n\t\tload() {\n\t\t\tupdate(this);\n\t\t},\n\n\t\tdraw() {\n\t\t\tdrawFormattedText(update(this));\n\t\t},\n\n\t};\n\n}\n\nfunction rect(w: number, h: number, opt: RectCompOpt = {}): RectComp {\n\treturn {\n\t\tid: \"rect\",\n\t\twidth: w,\n\t\theight: h,\n\t\tradius: opt.radius || 0,\n\t\tdraw() {\n\t\t\tdrawRect({\n\t\t\t\t...getRenderProps(this),\n\t\t\t\twidth: this.width,\n\t\t\t\theight: this.height,\n\t\t\t\tradius: this.radius,\n\t\t\t});\n\t\t},\n\t\tinspect() {\n\t\t\treturn `${Math.ceil(this.width)}, ${Math.ceil(this.height)}`;\n\t\t},\n\t};\n}\n\nfunction uvquad(w: number, h: number): UVQuadComp {\n\treturn {\n\t\tid: \"rect\",\n\t\twidth: w,\n\t\theight: h,\n\t\tdraw() {\n\t\t\tdrawUVQuad({\n\t\t\t\t...getRenderProps(this),\n\t\t\t\twidth: this.width,\n\t\t\t\theight: this.height,\n\t\t\t});\n\t\t},\n\t\tinspect() {\n\t\t\treturn `${Math.ceil(this.width)}, ${Math.ceil(this.height)}`;\n\t\t},\n\t};\n}\n\nfunction circle(radius: number): CircleComp {\n\treturn {\n\t\tid: \"circle\",\n\t\tradius: radius,\n\t\tdraw() {\n\t\t\tdrawCircle({\n\t\t\t\t...getRenderProps(this),\n\t\t\t\tradius: this.radius,\n\t\t\t});\n\t\t},\n\t\tinspect() {\n\t\t\treturn `${Math.ceil(this.radius)}`;\n\t\t},\n\t};\n}\n\nfunction outline(width: number = 1, color: Color = rgb(0, 0, 0)): OutlineComp {\n\treturn {\n\t\tid: \"outline\",\n\t\toutline: {\n\t\t\twidth,\n\t\t\tcolor,\n\t\t},\n\t};\n}\n\nfunction timer(time?: number, action?: () => void): TimerComp {\n\tconst timers: IDList<Timer> = new IDList();\n\tif (time && action) {\n\t\ttimers.pushd(new Timer(time, action));\n\t}\n\treturn {\n\t\tid: \"timer\",\n\t\twait(time: number, action: () => void): EventCanceller {\n\t\t\treturn timers.pushd(new Timer(time, action));\n\t\t},\n\t\tupdate() {\n\t\t\ttimers.forEach((timer, id) => {\n\t\t\t\tif (timer.tick(dt())) {\n\t\t\t\t\ttimers.delete(id);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n}\n\n// maximum y velocity with body()\nconst DEF_JUMP_FORCE = 640;\nconst MAX_VEL = 65536;\n\n// TODO: land on wall\nfunction body(opt: BodyCompOpt = {}): BodyComp {\n\n\tlet velY = 0;\n\tlet curPlatform: GameObj | null = null;\n\tlet lastPlatformPos = null;\n\tlet canDouble = true;\n\n\treturn {\n\n\t\tid: \"body\",\n\t\trequire: [ \"pos\", \"area\", ],\n\t\tjumpForce: opt.jumpForce ?? DEF_JUMP_FORCE,\n\t\tweight: opt.weight ?? 1,\n\t\tsolid: opt.solid ?? true,\n\n\t\tupdate() {\n\n\t\t\tlet justFall = false;\n\n\t\t\t// check if loses current platform\n\t\t\tif (curPlatform) {\n\n\t\t\t\tconst a1 = this.worldArea();\n\t\t\t\tconst a2 = curPlatform.worldArea();\n\t\t\t\tconst y1 = a1.p2.y;\n\t\t\t\tconst y2 = a2.p1.y;\n\t\t\t\tconst x1 = a1.p1.x;\n\t\t\t\tconst x2 = a1.p2.x;\n\t\t\t\tconst x3 = a2.p1.x;\n\t\t\t\tconst x4 = a2.p2.x;\n\n\t\t\t\tif (\n\t\t\t\t\t!curPlatform.exists()\n\t\t\t\t\t|| y1 !== y2\n\t\t\t\t\t|| x2 < x3\n\t\t\t\t\t|| x1 > x4\n\t\t\t\t) {\n\t\t\t\t\tthis.trigger(\"fall\", curPlatform);\n\t\t\t\t\tcurPlatform = null;\n\t\t\t\t\tlastPlatformPos = null;\n\t\t\t\t\tjustFall = true;\n\t\t\t\t} else {\n\t\t\t\t\tif (lastPlatformPos && curPlatform.pos) {\n\t\t\t\t\t\t// TODO: moveBy?\n\t\t\t\t\t\t// sticky platform\n\t\t\t\t\t\tthis.pos = this.pos.add(curPlatform.pos.sub(lastPlatformPos));\n\t\t\t\t\t\tlastPlatformPos = curPlatform.pos.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!curPlatform) {\n\n\t\t\t\tconst col = this.move(0, velY);\n\n\t\t\t\t// check if grounded to a new platform\n\t\t\t\tif (col) {\n\t\t\t\t\tif (col.isBottom()) {\n\t\t\t\t\t\tcurPlatform = col.target;\n\t\t\t\t\t\tconst oy = velY;\n\t\t\t\t\t\tvelY = 0;\n\t\t\t\t\t\tif (curPlatform.pos) {\n\t\t\t\t\t\t\tlastPlatformPos = curPlatform.pos.clone();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!justFall) {\n\t\t\t\t\t\t\tthis.trigger(\"ground\", curPlatform);\n\t\t\t\t\t\t\tcanDouble = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (col.isTop()) {\n\t\t\t\t\t\tvelY = 0;\n\t\t\t\t\t\tthis.trigger(\"headbutt\", col.target);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvelY += gravity() * this.weight * dt();\n\t\t\t\tvelY = Math.min(velY, opt.maxVel ?? MAX_VEL);\n\n\t\t\t}\n\n\t\t},\n\n\t\tcurPlatform(): GameObj | null {\n\t\t\treturn curPlatform;\n\t\t},\n\n\t\tisGrounded() {\n\t\t\treturn curPlatform !== null;\n\t\t},\n\n\t\tgrounded(): boolean {\n\t\t\tdeprecateMsg(\"grounded()\", \"isGrounded()\");\n\t\t\treturn this.isGrounded();\n\t\t},\n\n\t\tisFalling(): boolean {\n\t\t\treturn velY > 0;\n\t\t},\n\n\t\tfalling(): boolean {\n\t\t\tdeprecateMsg(\"falling()\", \"isFalling()\");\n\t\t\treturn this.isFalling();\n\t\t},\n\n\t\tjump(force: number) {\n\t\t\tcurPlatform = null;\n\t\t\tlastPlatformPos = null;\n\t\t\tvelY = -force || -this.jumpForce;\n\t\t},\n\n\t\tdoubleJump(force: number) {\n\t\t\tif (this.isGrounded()) {\n\t\t\t\tthis.jump(force);\n\t\t\t} else if (canDouble) {\n\t\t\t\tcanDouble = false;\n\t\t\t\tthis.jump(force);\n\t\t\t\tthis.trigger(\"doubleJump\");\n\t\t\t}\n\t\t},\n\n\t\tonGround(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"ground\", action);\n\t\t},\n\n\t\tonFall(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"fall\", action);\n\t\t},\n\n\t\tonHeadbutt(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"headbutt\", action);\n\t\t},\n\n\t\tonDoubleJump(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"doubleJump\", action);\n\t\t},\n\n\t};\n\n}\n\nfunction shader(id: string, uniform: Uniform = {}): ShaderComp {\n\tconst shader = assets.shaders[id];\n\treturn {\n\t\tid: \"shader\",\n\t\tshader: id,\n\t\tuniform: uniform,\n\t};\n}\n\nfunction solid(): SolidComp {\n\treturn {\n\t\tid: \"solid\",\n\t\trequire: [ \"area\", ],\n\t\tsolid: true,\n\t};\n}\n\nfunction fixed(): FixedComp {\n\treturn {\n\t\tid: \"fixed\",\n\t\tfixed: true,\n\t};\n}\n\nfunction stay(): StayComp {\n\treturn {\n\t\tid: \"stay\",\n\t\tstay: true,\n\t};\n}\n\nfunction health(hp: number): HealthComp {\n\tif (hp == null) {\n\t\tthrow new Error(\"health() requires the initial amount of hp\");\n\t}\n\treturn {\n\t\tid: \"health\",\n\t\thurt(n: number = 1) {\n\t\t\tthis.setHP(hp - n);\n\t\t\tthis.trigger(\"hurt\");\n\t\t},\n\t\theal(n: number = 1) {\n\t\t\tthis.setHP(hp + n);\n\t\t\tthis.trigger(\"heal\");\n\t\t},\n\t\thp(): number {\n\t\t\treturn hp;\n\t\t},\n\t\tsetHP(n: number) {\n\t\t\thp = n;\n\t\t\tif (hp <= 0) {\n\t\t\t\tthis.trigger(\"death\");\n\t\t\t}\n\t\t},\n\t\tonHurt(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"hurt\", action);\n\t\t},\n\t\tonHeal(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"heal\", action);\n\t\t},\n\t\tonDeath(action: () => void): EventCanceller {\n\t\t\treturn this.on(\"death\", action);\n\t\t},\n\t\tinspect() {\n\t\t\treturn `${hp}`;\n\t\t},\n\t};\n}\n\nfunction lifespan(time: number, opt: LifespanCompOpt = {}): LifespanComp {\n\tif (time == null) {\n\t\tthrow new Error(\"lifespan() requires time\");\n\t}\n\tlet timer = 0;\n\tconst fade = opt.fade ?? 0;\n\tconst startFade = Math.max((time - fade), 0);\n\treturn {\n\t\tid: \"lifespan\",\n\t\tupdate() {\n\t\t\ttimer += dt();\n\t\t\t// TODO: don't assume 1 as start opacity\n\t\t\tif (timer >= startFade) {\n\t\t\t\tthis.opacity = map(timer, startFade, time, 1, 0);\n\t\t\t}\n\t\t\tif (timer >= time) {\n\t\t\t\tthis.destroy();\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction state(\n\tinitState: string,\n\tstateList?: string[],\n\ttransitions?: Record<string, string | string[]>,\n): StateComp {\n\n\tif (!initState) {\n\t\tthrow new Error(\"state() requires an initial state\");\n\t}\n\n\tconst events = {};\n\n\tfunction initStateHook(state: string) {\n\t\tif (!events[state]) {\n\t\t\tevents[state] = {\n\t\t\t\tenter: [],\n\t\t\t\tleave: [],\n\t\t\t\tupdate: [],\n\t\t\t\tdraw: [],\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction on(event, state, action) {\n\t\tinitStateHook(state);\n\t\tevents[state][event].push(action);\n\t}\n\n\tfunction trigger(event, state, ...args) {\n\t\tinitStateHook(state);\n\t\tevents[state][event].forEach((action) => action(...args));\n\t}\n\n\treturn {\n\n\t\tid: \"state\",\n\t\tstate: initState,\n\n\t\tenterState(state: string, ...args) {\n\n\t\t\tif (stateList && !stateList.includes(state)) {\n\t\t\t\tthrow new Error(`State not found: ${state}`);\n\t\t\t}\n\n\t\t\tconst oldState = this.state;\n\n\t\t\tif (transitions) {\n\n\t\t\t\t// check if the transition is legal, if transition graph is defined\n\t\t\t\tif (!transitions?.[oldState]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst available = typeof transitions[oldState] === \"string\"\n\t\t\t\t\t? [transitions[oldState]]\n\t\t\t\t\t: transitions[oldState] as string[];\n\n\t\t\t\tif (!available.includes(state)) {\n\t\t\t\t\tthrow new Error(`Cannot transition state from \"${oldState}\" to \"${state}\". Available transitions: ${available.map((s) => `\"${s}\"`).join(\", \")}`);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\ttrigger(\"leave\", oldState, ...args);\n\t\t\tthis.state = state;\n\t\t\ttrigger(\"enter\", state, ...args);\n\t\t\ttrigger(\"enter\", `${oldState} -> ${state}`, ...args);\n\n\t\t},\n\n\t\tonStateTransition(from: string, to: string, action: () => void) {\n\t\t\ton(\"enter\", `${from} -> ${to}`, action);\n\t\t},\n\n\t\tonStateEnter(state: string, action: () => void) {\n\t\t\ton(\"enter\", state, action);\n\t\t},\n\n\t\tonStateUpdate(state: string, action: () => void) {\n\t\t\ton(\"update\", state, action);\n\t\t},\n\n\t\tonStateDraw(state: string, action: () => void) {\n\t\t\ton(\"draw\", state, action);\n\t\t},\n\n\t\tonStateLeave(state: string, action: () => void) {\n\t\t\ton(\"leave\", state, action);\n\t\t},\n\n\t\tupdate() {\n\t\t\ttrigger(\"update\", this.state);\n\t\t},\n\n\t\tdraw() {\n\t\t\ttrigger(\"draw\", this.state);\n\t\t},\n\n\t\tinspect() {\n\t\t\treturn this.state;\n\t\t},\n\n\t};\n\n}\n\nfunction onLoad(cb: () => void): void {\n\tif (app.loaded) {\n\t\tcb();\n\t} else {\n\t\tgame.on(\"load\", cb);\n\t}\n}\n\nfunction scene(id: SceneID, def: SceneDef) {\n\tgame.scenes[id] = def;\n}\n\nfunction go(id: SceneID, ...args) {\n\n\tif (!game.scenes[id]) {\n\t\tthrow new Error(`scene not found: ${id}`);\n\t}\n\n\tconst cancel = game.on(\"updateStart\", () => {\n\n\t\tgame.events = {};\n\n\t\tgame.objEvents = {\n\t\t\tadd: new IDList(),\n\t\t\tupdate: new IDList(),\n\t\t\tdraw: new IDList(),\n\t\t\tdestroy: new IDList(),\n\t\t};\n\n\t\tgame.root.every((obj) => {\n\t\t\tif (!obj.is(\"stay\")) {\n\t\t\t\tgame.root.remove(obj);\n\t\t\t}\n\t\t})\n\n\t\tgame.root.clearEvents();\n\t\tgame.timers = new IDList();\n\n\t\t// cam\n\t\tgame.cam = {\n\t\t\tpos: center(),\n\t\t\tscale: vec2(1),\n\t\t\tangle: 0,\n\t\t\tshake: 0,\n\t\t\ttransform: new Mat4(),\n\t\t};\n\n\t\tgame.layers = {};\n\t\tgame.defLayer = null;\n\t\tgame.gravity = DEF_GRAVITY;\n\n\t\tgame.scenes[id](...args);\n\n\t\tif (gopt.debug !== false) {\n\t\t\tenterDebugMode();\n\t\t}\n\n\t\tif (gopt.burp) {\n\t\t\tenterBurpMode();\n\t\t}\n\n\t\tcancel();\n\n\t});\n\n}\n\nfunction getData<T>(key: string, def?: T): T {\n\ttry {\n\t\treturn JSON.parse(window.localStorage[key]);\n\t} catch {\n\t\tif (def) {\n\t\t\tsetData(key, def);\n\t\t\treturn def;\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n\nfunction setData(key: string, data: any) {\n\twindow.localStorage[key] = JSON.stringify(data);\n}\n\nfunction plug<T>(plugin: KaboomPlugin<T>): MergeObj<T> & KaboomCtx {\n\tconst funcs = plugin(ctx);\n\tfor (const k in funcs) {\n\t\t// @ts-ignore\n\t\tctx[k] = funcs[k];\n\t\tif (gopt.global !== false) {\n\t\t\t// @ts-ignore\n\t\t\twindow[k] = funcs[k];\n\t\t}\n\t}\n\treturn ctx as unknown as MergeObj<T> & KaboomCtx;\n}\n\nfunction center(): Vec2 {\n\treturn vec2(width() / 2, height() / 2);\n}\n\nfunction grid(level: Level, p: Vec2) {\n\n\treturn {\n\n\t\tid: \"grid\",\n\t\tgridPos: p.clone(),\n\n\t\tsetGridPos(...args) {\n\t\t\tconst p = vec2(...args);\n\t\t\tthis.gridPos = p.clone();\n\t\t\tthis.pos = vec2(\n\t\t\t\tlevel.offset().x + this.gridPos.x * level.gridWidth(),\n\t\t\t\tlevel.offset().y + this.gridPos.y * level.gridHeight()\n\t\t\t);\n\t\t},\n\n\t\tmoveLeft() {\n\t\t\tthis.setGridPos(this.gridPos.add(vec2(-1, 0)));\n\t\t},\n\n\t\tmoveRight() {\n\t\t\tthis.setGridPos(this.gridPos.add(vec2(1, 0)));\n\t\t},\n\n\t\tmoveUp() {\n\t\t\tthis.setGridPos(this.gridPos.add(vec2(0, -1)));\n\t\t},\n\n\t\tmoveDown() {\n\t\t\tthis.setGridPos(this.gridPos.add(vec2(0, 1)));\n\t\t},\n\n\t};\n\n}\n\nfunction addLevel(map: string[], opt: LevelOpt): Level {\n\n\tif (!opt.width || !opt.height) {\n\t\tthrow new Error(\"Must provide level grid width & height.\");\n\t}\n\n\tconst objs: GameObj[] = [];\n\tconst offset = vec2(opt.pos || vec2(0));\n\tlet longRow = 0;\n\n\tconst level = {\n\n\t\toffset() {\n\t\t\treturn offset.clone();\n\t\t},\n\n\t\tgridWidth() {\n\t\t\treturn opt.width;\n\t\t},\n\n\t\tgridHeight() {\n\t\t\treturn opt.height;\n\t\t},\n\n\t\tgetPos(...args): Vec2 {\n\t\t\tconst p = vec2(...args);\n\t\t\treturn vec2(\n\t\t\t\toffset.x + p.x * opt.width,\n\t\t\t\toffset.y + p.y * opt.height\n\t\t\t);\n\t\t},\n\n\t\tspawn(sym: string, ...args): GameObj {\n\n\t\t\tconst p = vec2(...args);\n\n\t\t\tconst comps = (() => {\n\t\t\t\tif (opt[sym]) {\n\t\t\t\t\tif (typeof opt[sym] !== \"function\") {\n\t\t\t\t\t\tthrow new Error(\"level symbol def must be a function returning a component list\");\n\t\t\t\t\t}\n\t\t\t\t\treturn opt[sym](p);\n\t\t\t\t} else if (opt.any) {\n\t\t\t\t\treturn opt.any(sym, p);\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tif (!comps) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst posComp = vec2(\n\t\t\t\toffset.x + p.x * opt.width,\n\t\t\t\toffset.y + p.y * opt.height\n\t\t\t);\n\n\t\t\tfor (const comp of comps) {\n\t\t\t\tif (comp.id === \"pos\") {\n\t\t\t\t\tposComp.x += comp.pos.x;\n\t\t\t\t\tposComp.y += comp.pos.y;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcomps.push(pos(posComp));\n\t\t\tcomps.push(grid(this, p));\n\n\t\t\tconst obj = game.root.add(comps);\n\n\t\t\tobjs.push(obj);\n\n\t\t\treturn obj;\n\n\t\t},\n\n\t\twidth() {\n\t\t\treturn longRow * opt.width;\n\t\t},\n\n\t\theight() {\n\t\t\treturn map.length * opt.height;\n\t\t},\n\n\t\tdestroy() {\n\t\t\tfor (const obj of objs) {\n\t\t\t\tobj.destroy();\n\t\t\t}\n\t\t},\n\n\t};\n\n\tmap.forEach((row, i) => {\n\n\t\tconst syms = row.split(\"\");\n\n\t\tlongRow = Math.max(syms.length, longRow);\n\n\t\tsyms.forEach((sym, j) => {\n\t\t\tlevel.spawn(sym, vec2(j, i));\n\t\t});\n\n\t});\n\n\treturn level;\n\n}\n\nfunction record(frameRate?): Recording {\n\n\tconst stream = app.canvas.captureStream(frameRate);\n\tconst audioDest = audio.ctx.createMediaStreamDestination();\n\n\taudio.masterNode.connect(audioDest)\n\n\tconst audioStream = audioDest.stream;\n\tconst [firstAudioTrack] = audioStream.getAudioTracks();\n\n\t// TODO: Enabling audio results in empty video if no audio received\n\t// stream.addTrack(firstAudioTrack);\n\n\tconst recorder = new MediaRecorder(stream);\n\tconst chunks = [];\n\n\trecorder.ondataavailable = (e) => {\n\t\tif (e.data.size > 0) {\n\t\t\tchunks.push(e.data);\n\t\t}\n\t};\n\n\trecorder.onerror = (e) => {\n\t\taudio.masterNode.disconnect(audioDest)\n\t\tstream.getTracks().forEach(t => t.stop());\n\t};\n\n\trecorder.start();\n\n\treturn {\n\n\t\tresume() {\n\t\t\trecorder.resume();\n\t\t},\n\n\t\tpause() {\n\t\t\trecorder.pause();\n\t\t},\n\n\t\tdownload(filename = \"kaboom.mp4\") {\n\n\t\t\trecorder.onstop = () => {\n\t\t\t\tdownloadBlob(new Blob(chunks, {\n\t\t\t\t\ttype: \"video/mp4\",\n\t\t\t\t}), filename);\n\t\t\t}\n\n\t\t\trecorder.stop();\n\t\t\t// cleanup\n\t\t\taudio.masterNode.disconnect(audioDest)\n\t\t\tstream.getTracks().forEach(t => t.stop());\n\n\t\t},\n\n\t};\n\n}\n\nfunction focus() {\n\tdeprecateMsg(\"focus()\", \"canvas.focus()\");\n\tapp.canvas.focus();\n}\n\nfunction isFocused(): boolean {\n\treturn document.activeElement === app.canvas;\n}\n\ninterface BoomOpt {\n\t/**\n\t * Animation speed.\n\t */\n\tspeed?: number,\n\t/**\n\t * Scale.\n\t */\n\tscale?: number,\n\t/**\n\t * Additional ka components.\n\t */\n\tkaComps?: () => CompList<any>,\n\t/**\n\t * Additional boom components.\n\t */\n\tboomComps?: () => CompList<any>,\n}\n\n// aliases for root game obj operations\nfunction add<T>(comps: CompList<T>): GameObj<T> {\n\treturn game.root.add(comps);\n}\n\nfunction readd<T>(obj: GameObj<T>): GameObj<T> {\n\treturn game.root.readd(obj);\n}\n\nfunction destroy(obj: GameObj) {\n\treturn game.root.remove(obj);\n}\n\nfunction destroyAll(tag: Tag) {\n\treturn game.root.removeAll(tag);\n}\n\nfunction get(...args) {\n\treturn game.root.get(...args);\n}\n\nfunction every(...args) {\n\t// @ts-ignore\n\treturn game.root.every(...args);\n}\n\nfunction revery(...args) {\n\t// @ts-ignore\n\treturn game.root.revery(...args);\n}\n\ninterface ExplodeComp extends Comp {\n}\n\nfunction explode(speed: number = 2, size: number = 1): ExplodeComp {\n\tlet time = 0;\n\treturn {\n\t\tid: \"explode\",\n\t\trequire: [ \"scale\", ],\n\t\tupdate() {\n\t\t\tconst s = Math.sin(time * speed) * size;\n\t\t\tif (s < 0) {\n\t\t\t\tdestroy(this);\n\t\t\t}\n\t\t\tthis.scale = vec2(s);\n\t\t\ttime += dt();\n\t\t},\n\t};\n}\n\nlet kaSprite = null;\nlet boomSprite = null;\n\nloadSprite(null, kaSrc).then((spr) => kaSprite = spr);\nloadSprite(null, boomSrc).then((spr) => boomSprite = spr);\n\n// TODO: use children obj\nfunction addKaboom(p: Vec2, opt: BoomOpt = {}): Kaboom {\n\n\tconst speed = (opt.speed || 1) * 5;\n\tconst s = opt.scale || 1;\n\n\tconst boom = add([\n\t\tpos(p),\n\t\tsprite(boomSprite),\n\t\tscale(0),\n\t\tstay(),\n\t\torigin(\"center\"),\n\t\texplode(speed, s),\n\t\t...(opt.boomComps ?? (() => []))(),\n\t]);\n\n\tconst ka = add([\n\t\tpos(p),\n\t\tsprite(kaSprite),\n\t\tscale(0),\n\t\tstay(),\n\t\torigin(\"center\"),\n\t\ttimer(0.4 / speed, () => ka.use(explode(speed, s))),\n\t\t...(opt.kaComps ?? (() => []))(),\n\t]);\n\n\treturn {\n\t\tdestroy() {\n\t\t\tdestroy(ka);\n\t\t\tdestroy(boom);\n\t\t},\n\t};\n\n}\n\nfunction frames() {\n\treturn app.numFrames;\n}\n\nfunction updateFrame() {\n\n\tgame.trigger(\"updateStart\");\n\n\t// update timers\n\tgame.timers.forEach((t, id) => {\n\t\tt.time -= dt();\n\t\tif (t.time <= 0) {\n\t\t\t// TODO: some timer action causes crash on FF when dt is really high, not sure why\n\t\t\tt.action();\n\t\t\tgame.timers.delete(id);\n\t\t}\n\t});\n\n\t// update every obj\n\tgame.root.update();\n\n}\n\nfunction drawFrame() {\n\n\t// calculate camera matrix\n\tconst cam = game.cam;\n\tconst shake = Vec2.fromAngle(rand(0, 360)).scale(cam.shake);\n\n\tcam.shake = lerp(cam.shake, 0, 5 * dt());\n\tcam.transform = new Mat4()\n\t\t.translate(center())\n\t\t.scale(cam.scale)\n\t\t.rotateZ(cam.angle)\n\t\t.translate(cam.pos.scale(-1).add(shake))\n\t\t;\n\n\tgame.root.draw();\n\n}\n\nfunction drawLoadScreen() {\n\n\t// if assets are not fully loaded, draw a progress bar\n\tconst progress = loadProgress();\n\n\tif (progress === 1) {\n\t\tapp.loaded = true;\n\t\tgame.trigger(\"load\");\n\t} else {\n\n\t\tconst w = width() / 2;\n\t\tconst h = 24 / app.scale;\n\t\tconst pos = vec2(width() / 2, height() / 2).sub(vec2(w / 2, h / 2));\n\n\t\tdrawRect({\n\t\t\tpos: vec2(0),\n\t\t\twidth: width(),\n\t\t\theight: height(),\n\t\t\tcolor: rgb(0, 0, 0),\n\t\t});\n\n\t\tdrawRect({\n\t\t\tpos: pos,\n\t\t\twidth: w,\n\t\t\theight: h,\n\t\t\tfill: false,\n\t\t\toutline: {\n\t\t\t\twidth: 4 / app.scale,\n\t\t\t},\n\t\t});\n\n\t\tdrawRect({\n\t\t\tpos: pos,\n\t\t\twidth: w * progress,\n\t\t\theight: h,\n\t\t});\n\n\t}\n\n}\n\nfunction drawInspectText(pos, txt) {\n\n\tconst pad = vec2(8);\n\n\tpushTransform();\n\tpushTranslate(pos);\n\tpushScale(1 / app.scale);\n\n\tconst ftxt = formatText({\n\t\ttext: txt,\n\t\tfont: assets.fonts[DBG_FONT],\n\t\tsize: 16,\n\t\tpos: pad,\n\t\tcolor: rgb(255, 255, 255),\n\t\tfixed: true,\n\t});\n\n\tconst bw = ftxt.width + pad.x * 2;\n\tconst bh = ftxt.height + pad.x * 2;\n\n\tif (pos.x + bw / app.scale >= width()) {\n\t\tpushTranslate(vec2(-bw, 0));\n\t}\n\n\tif (pos.y + bh / app.scale >= height()) {\n\t\tpushTranslate(vec2(0, -bh));\n\t}\n\n\tdrawRect({\n\t\twidth: bw,\n\t\theight: bh,\n\t\tcolor: rgb(0, 0, 0),\n\t\tradius: 4,\n\t\topacity: 0.8,\n\t\tfixed: true,\n\t});\n\n\tdrawFormattedText(ftxt);\n\tpopTransform();\n\n}\n\nfunction drawDebug() {\n\n\tif (debug.inspect) {\n\n\t\tlet inspecting = null;\n\t\tconst lcolor = Color.fromArray(gopt.inspectColor ?? [0, 0, 255]);\n\n\t\t// draw area outline\n\t\tgame.root.every((obj) => {\n\n\t\t\tif (!obj.area) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!inspecting) {\n\t\t\t\tif (obj.isHovering()) {\n\t\t\t\t\tinspecting = obj;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst lwidth = (inspecting === obj ? 8 : 4);\n\t\t\tconst a = obj.worldArea();\n\t\t\tconst w = a.p2.x - a.p1.x;\n\t\t\tconst h = a.p2.y - a.p1.y;\n\n\t\t\tdrawRect({\n\t\t\t\tpos: a.p1,\n\t\t\t\twidth: w,\n\t\t\t\theight: h,\n\t\t\t\toutline: {\n\t\t\t\t\twidth: lwidth,\n\t\t\t\t\tcolor: lcolor,\n\t\t\t\t},\n\t\t\t\tfill: false,\n\t\t\t\tfixed: obj.fixed,\n\t\t\t});\n\n\t\t});\n\n\t\tif (inspecting) {\n\n\t\t\tconst lines = [];\n\t\t\tconst data = inspecting.inspect();\n\n\t\t\tfor (const tag in data) {\n\t\t\t\tif (data[tag]) {\n\t\t\t\t\tlines.push(`${tag}: ${data[tag]}`);\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(`${tag}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdrawInspectText(mousePos(), lines.join(\"\\n\"));\n\n\t\t}\n\n\t\tdrawInspectText(vec2(8 / app.scale), `FPS: ${debug.fps()}`);\n\n\t}\n\n\tif (debug.paused) {\n\n\t\t// top right corner\n\t\tpushTransform();\n\t\tpushTranslate(width(), 0);\n\t\tpushScale(1 / app.scale);\n\t\tpushTranslate(-8, 8);\n\n\t\tconst size = 32;\n\n\t\t// bg\n\t\tdrawRect({\n\t\t\twidth: size,\n\t\t\theight: size,\n\t\t\torigin: \"topright\",\n\t\t\tcolor: rgb(0, 0, 0),\n\t\t\topacity: 0.8,\n\t\t\tradius: 4,\n\t\t\tfixed: true,\n\t\t});\n\n\t\t// pause icon\n\t\tfor (let i = 1; i <= 2; i++) {\n\t\t\tdrawRect({\n\t\t\t\twidth: 4,\n\t\t\t\theight: size * 0.6,\n\t\t\t\torigin: \"center\",\n\t\t\t\tpos: vec2(-size / 3 * i, size * 0.5),\n\t\t\t\tcolor: rgb(255, 255, 255),\n\t\t\t\tradius: 2,\n\t\t\t\tfixed: true,\n\t\t\t});\n\t\t}\n\n\t\tpopTransform();\n\n\t}\n\n\tif (debug.timeScale !== 1) {\n\n\t\t// bottom right corner\n\t\tpushTransform();\n\t\tpushTranslate(width(), height());\n\t\tpushScale(1 / app.scale);\n\t\tpushTranslate(-8, -8);\n\n\t\tconst pad = 8;\n\n\t\t// format text first to get text size\n\t\tconst ftxt = formatText({\n\t\t\ttext: debug.timeScale.toFixed(1),\n\t\t\tfont: assets.fonts[DBG_FONT],\n\t\t\tsize: 16,\n\t\t\tcolor: rgb(255, 255, 255),\n\t\t\tpos: vec2(-pad),\n\t\t\torigin: \"botright\",\n\t\t\tfixed: true,\n\t\t});\n\n\t\t// bg\n\t\tdrawRect({\n\t\t\twidth: ftxt.width + pad * 2 + pad * 4,\n\t\t\theight: ftxt.height + pad * 2,\n\t\t\torigin: \"botright\",\n\t\t\tcolor: rgb(0, 0, 0),\n\t\t\topacity: 0.8,\n\t\t\tradius: 4,\n\t\t\tfixed: true,\n\t\t});\n\n\t\t// fast forward / slow down icon\n\t\tfor (let i = 0; i < 2; i++) {\n\t\t\tconst flipped = debug.timeScale < 1;\n\t\t\tdrawTriangle({\n\t\t\t\tp1: vec2(-ftxt.width - pad * (flipped ? 2 : 3.5), -pad),\n\t\t\t\tp2: vec2(-ftxt.width - pad * (flipped ? 2 : 3.5), -pad - ftxt.height),\n\t\t\t\tp3: vec2(-ftxt.width - pad * (flipped ? 3.5 : 2), -pad - ftxt.height / 2),\n\t\t\t\tpos: vec2(-i * pad * 1 + (flipped ? -pad * 0.5 : 0), 0),\n\t\t\t\tcolor: rgb(255, 255, 255),\n\t\t\t\tfixed: true,\n\t\t\t});\n\t\t}\n\n\t\t// text\n\t\tdrawFormattedText(ftxt);\n\n\t\tpopTransform();\n\n\t}\n\n\tif (debug.curRecording) {\n\n\t\tpushTransform();\n\t\tpushTranslate(0, height());\n\t\tpushScale(1 / app.scale);\n\t\tpushTranslate(24, -24);\n\n\t\tdrawCircle({\n\t\t\tradius: 12,\n\t\t\tcolor: rgb(255, 0, 0),\n\t\t\topacity: wave(0, 1, time() * 4),\n\t\t\tfixed: true,\n\t\t});\n\n\t\tpopTransform();\n\n\t}\n\n\tif (debug.showLog && game.logs.length > 0) {\n\n\t\tpushTransform();\n\t\tpushTranslate(0, height());\n\t\tpushScale(1 / app.scale);\n\t\tpushTranslate(8, -8);\n\n\t\tconst pad = 8;\n\t\tconst max = gopt.logMax ?? 1;\n\n\t\tif (game.logs.length > max) {\n\t\t\tgame.logs = game.logs.slice(0, max);\n\t\t}\n\n\t\tconst ftext = formatText({\n\t\t\ttext: game.logs.join(\"\\n\"),\n\t\t\tfont: assets.fonts[DBG_FONT],\n\t\t\tpos: vec2(pad, -pad),\n\t\t\torigin: \"botleft\",\n\t\t\tsize: 16,\n\t\t\twidth: width() * app.scale * 0.6,\n\t\t\tlineSpacing: pad / 2,\n\t\t\tfixed: true,\n\t\t\tstyles: {\n\t\t\t\t\"time\": { color: rgb(127, 127, 127) },\n\t\t\t\t\"info\": { color: rgb(255, 255, 255) },\n\t\t\t\t\"error\": { color: rgb(255, 0, 127) },\n\t\t\t},\n\t\t});\n\n\t\tdrawRect({\n\t\t\twidth: ftext.width + pad * 2,\n\t\t\theight: ftext.height + pad * 2,\n\t\t\torigin: \"botleft\",\n\t\t\tcolor: rgb(0, 0, 0),\n\t\t\tradius: 4,\n\t\t\topacity: 0.8,\n\t\t\tfixed: true,\n\t\t});\n\n\t\tdrawFormattedText(ftext);\n\t\tpopTransform();\n\n\t}\n\n}\n\nif (gopt.debug !== false) {\n\tenterDebugMode();\n}\n\nif (gopt.burp) {\n\tenterBurpMode();\n}\n\nwindow.addEventListener(\"error\", (e) => {\n\tdebug.error(`Error: ${e.error.message}`);\n\tquit();\n\trun(() => {\n\t\tif (loadProgress() === 1) {\n\t\t\tframeStart();\n\t\t\tdrawDebug();\n\t\t\tframeEnd();\n\t\t}\n\t});\n});\n\nfunction run(f: () => void) {\n\n\tconst frame = (t: number) => {\n\n\t\tif (document.visibilityState !== \"visible\") {\n\t\t\tapp.loopID = requestAnimationFrame(frame);\n\t\t\treturn;\n\t\t}\n\n\t\tconst realTime = t / 1000;\n\t\tconst realDt = realTime - app.realTime;\n\n\t\tapp.realTime = realTime;\n\n\t\tif (!app.skipTime) {\n\t\t\tapp.dt = realDt;\n\t\t\tapp.time += app.dt;\n\t\t\tapp.fpsCounter.tick(app.dt);\n\t\t}\n\n\t\tapp.skipTime = false;\n\t\tapp.numFrames++;\n\n\t\tf();\n\n\t\tfor (const k in app.keyStates) {\n\t\t\tapp.keyStates[k] = processButtonState(app.keyStates[k]);\n\t\t}\n\n\t\tfor (const m in app.mouseStates) {\n\t\t\tapp.mouseStates[m] = processButtonState(app.mouseStates[m]);\n\t\t}\n\n\t\tapp.charInputted = [];\n\t\tapp.isMouseMoved = false;\n\t\tapp.isKeyPressed = false;\n\t\tapp.isKeyPressedRepeat = false;\n\t\tapp.isKeyReleased = false;\n\t\tapp.loopID = requestAnimationFrame(frame);\n\n\t};\n\n\tapp.stopped = false;\n\tapp.loopID = requestAnimationFrame(frame);\n\n}\n\n// main game loop\nrun(() => {\n\n\t// running this every frame now mainly because isFullscreen() is not updated real time when requested fullscreen\n\tupdateViewport();\n\n\tif (!app.loaded) {\n\t\tframeStart();\n\t\tdrawLoadScreen();\n\t\tframeEnd();\n\t} else {\n\n\t\t// TODO: this gives the latest mousePos in input handlers but uses cam matrix from last frame\n\t\tgame.trigger(\"input\");\n\n\t\tif (!debug.paused) {\n\t\t\tupdateFrame();\n\t\t}\n\n\t\tframeStart();\n\t\tdrawFrame();\n\n\t\tif (gopt.debug !== false) {\n\t\t\tdrawDebug();\n\t\t}\n\n\t\tframeEnd();\n\n\t}\n\n});\n\nloadFont(\n\t\"apl386\",\n\tapl386Src,\n\t45,\n\t74,\n);\n\nloadFont(\n\t\"apl386o\",\n\tapl386oSrc,\n\t45,\n\t74,\n);\n\nloadFont(\n\t\"sink\",\n\tsinkSrc,\n\t6,\n\t8,\n\t{\n\t\tchars: `\u2588\u263A\u263B\u2665\u2666\u2663\u2660\u25CF\u25CB\u25AA\u25A1\u25A0\u25D8\u266A\u266B\u2261\u25BA\u25C4\u2302\u00DE\u00C0\u00DF\u00D7\u00A5\u2191\u2193\u2192\u2190\u25CC\u25CF\u25BC\u25B2 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~\u03A7\u2591\u2592\u2593\u1E00\u1E01\u1E02\u2502\u252C\u2524\u250C\u2510\u1E03\u1E04\u253C\u1E05\u1E06\u1E07\u1E08\u1E09\u1E0A\u1E0B\u1E0C\u2500\u251C\u2534\u2514\u2518\u1E0D\u1E0E\u205E\u1E0F\u1E10\u1E11\u1E12\u1E13\u1E14\u1E15\u1E16\u1E17\u1E18\u2584\u1E19\u1E1A\u1E1B\u1E1C\u2026\u1E1D\u1E1E\u1E1F\u1E20\u1E21\u1E22\u1E23\u1E24\u1E25\u1E26\u258C\u2590\u1E27\u1E28\u1E29\u1E2A\u1E2B\u1E2C\u1E2D\u1E2E\u1E2F\u1E30\u1E31\u1E32\u1E33\u1E34\u1E35\u1E36\u1E37\u1E38\u1E39\u1E3A\u1E3B\u1E3C\u1E3D\u1E3E\u1E3F\u1E40\u1E41\u1E42\u1E43\u1E44\u1E45\u1E46\u1E47\u1E48\u1E49\u1E4A\u1E4B\u1E4C\u1E4D\u1E4E\u1E4F\u1E50\u1E51\u1E52\u1E53\u1E54\u1E55\u1E56\u1E57\u1E58\u1E59\u1E5A\u1E5B\u1E5C\u1E5D\u1E5E\u1E5F\u1E60\u1E61\u1E62\u1E63\u1E64\u1E65\u1E66\u1E67\u1E68\u1E69\u1E6A\u1E6B\u1E6C\u1E6D\u1E6E\u1E6F\u1E70\u1E71\u1E72\u1E73\u1E74\u1E75\u1E76\u1E77\u1E78\u1E79\u1E7A\u1E7B\u1E7C`,\n\t}\n);\n\nloadFont(\n\t\"sinko\",\n\tsinkoSrc,\n\t8,\n\t10,\n);\n\nframeStart();\nframeEnd();\n\n// the exported ctx handle\nconst ctx: KaboomCtx = {\n\t// asset load\n\tloadRoot,\n\tloadSprite,\n\tloadSpriteAtlas,\n\tloadSound,\n\tloadFont,\n\tloadShader,\n\tloadAseprite,\n\tloadPedit,\n\tloadBean,\n\tload,\n\t// query\n\twidth,\n\theight,\n\tcenter,\n\tdt,\n\ttime,\n\tscreenshot,\n\trecord,\n\tisFocused,\n\tfocus,\n\tcursor,\n\tregCursor,\n\tfullscreen,\n\tisFullscreen,\n\tonLoad,\n\tisTouch: () => app.isTouch,\n\t// misc\n\tlayers,\n\tcamPos,\n\tcamScale,\n\tcamRot,\n\tshake,\n\ttoScreen,\n\ttoWorld,\n\tgravity,\n\t// obj\n\tadd,\n\treadd,\n\tdestroy,\n\tdestroyAll,\n\tget,\n\tevery,\n\trevery,\n\t// comps\n\tpos,\n\tscale,\n\trotate,\n\tcolor,\n\topacity,\n\torigin,\n\tlayer,\n\tarea,\n\tsprite,\n\ttext,\n\trect,\n\tcircle,\n\tuvquad,\n\toutline,\n\tbody,\n\tshader,\n\ttimer,\n\tsolid,\n\tfixed,\n\tstay,\n\thealth,\n\tlifespan,\n\tz,\n\tmove,\n\toutview,\n\tcleanup,\n\tfollow,\n\tstate,\n\t// group events\n\ton,\n\tonUpdate,\n\tonDraw,\n\tonCollide,\n\tonClick,\n\tonHover,\n\t// input\n\tonKeyDown,\n\tonKeyPress,\n\tonKeyPressRepeat,\n\tonKeyRelease,\n\tonMouseDown,\n\tonMousePress,\n\tonMouseRelease,\n\tonMouseMove,\n\tonCharInput,\n\tonTouchStart,\n\tonTouchMove,\n\tonTouchEnd,\n\tmousePos,\n\tmouseWorldPos,\n\tmouseDeltaPos,\n\tisKeyDown,\n\tisKeyPressed,\n\tisKeyPressedRepeat,\n\tisKeyReleased,\n\tisMouseDown,\n\tisMousePressed,\n\tisMouseReleased,\n\tisMouseMoved,\n\t// timer\n\tloop,\n\twait,\n\t// audio\n\tplay,\n\tvolume,\n\tburp,\n\taudioCtx: audio.ctx,\n\t// math\n\tTimer,\n\tLine,\n\tRect,\n\tCircle,\n\tVec2,\n\tColor,\n\tMat4,\n\tQuad,\n\tRNG,\n\trng,\n\trand,\n\trandi,\n\trandSeed,\n\tvec2,\n\trgb,\n\thsl2rgb,\n\tquad,\n\tchoose,\n\tchance,\n\tlerp,\n\tmap,\n\tmapc,\n\twave,\n\tdeg2rad,\n\trad2deg,\n\ttestAreaRect,\n\ttestAreaLine,\n\ttestAreaCircle,\n\ttestAreaPolygon,\n\ttestAreaPoint,\n\ttestAreaArea,\n\ttestLineLine,\n\ttestRectRect,\n\ttestRectLine,\n\ttestRectPoint,\n\ttestPolygonPoint,\n\ttestLinePolygon,\n\ttestPolygonPolygon,\n\ttestCircleCircle,\n\ttestCirclePoint,\n\ttestRectPolygon,\n\t// raw draw\n\tdrawSprite,\n\tdrawText,\n\tformatText,\n\tdrawRect,\n\tdrawLine,\n\tdrawLines,\n\tdrawTriangle,\n\tdrawCircle,\n\tdrawEllipse,\n\tdrawUVQuad,\n\tdrawPolygon,\n\tdrawFormattedText,\n\tpushTransform,\n\tpopTransform,\n\tpushTranslate,\n\tpushRotate: pushRotateZ,\n\tpushScale,\n\t// debug\n\tdebug,\n\t// scene\n\tscene,\n\tgo,\n\t// level\n\taddLevel,\n\t// storage\n\tgetData,\n\tsetData,\n\t// plugin\n\tplug,\n\t// char sets\n\tASCII_CHARS,\n\tCP437_CHARS,\n\t// dom\n\tcanvas: app.canvas,\n\t// misc\n\taddKaboom,\n\t// dirs\n\tLEFT: Vec2.LEFT,\n\tRIGHT: Vec2.RIGHT,\n\tUP: Vec2.UP,\n\tDOWN: Vec2.DOWN,\n\t// colors\n\tRED: Color.RED,\n\tGREEN: Color.GREEN,\n\tBLUE: Color.BLUE,\n\tYELLOW: Color.YELLOW,\n\tMAGENTA: Color.MAGENTA,\n\tCYAN: Color.CYAN,\n\tWHITE: Color.WHITE,\n\tBLACK: Color.BLACK,\n\t// deprecated\n\tkeyIsDown: deprecate(\"keyIsDown()\", \"isKeyDown()\", isKeyDown),\n\tkeyIsPressed: deprecate(\"keyIsPressed()\", \"isKeyPressed()\", isKeyPressed),\n\tkeyIsPressedRep: deprecate(\"keyIsPressedRep()\", \"isKeyPressedRepeat()\", isKeyPressedRepeat),\n\tkeyIsReleased: deprecate(\"keyIsReleased()\", \"isKeyReleased()\", isKeyReleased),\n\tmouseIsDown: deprecate(\"mouseIsDown()\", \"isMouseDown()\", isMouseDown),\n\tmouseIsClicked: deprecate(\"mouseIsClicked()\", \"isMousePressed()\", isMousePressed),\n\tmouseIsReleased: deprecate(\"mouseIsReleased()\", \"isMouseReleased()\", isMouseReleased),\n\tmouseIsMoved: deprecate(\"mouseIsMoved()\", \"isMouseMoved()\", isMouseMoved),\n\tdir: deprecate(\"dir()\", \"Vec2.fromAngle()\", Vec2.fromAngle),\n\taction: deprecate(\"action()\", \"onUpdate()\", onUpdate),\n\trender: deprecate(\"render()\", \"onDraw()\", onDraw),\n\tcollides: deprecate(\"collides()\", \"onCollide()\", onCollide),\n\tclicks: deprecate(\"clicks()\", \"onClick()\", onClick),\n\thovers: deprecate(\"hovers()\", \"onHover()\", onHover),\n\tkeyDown: deprecate(\"keyDown()\", \"onKeyDown()\", onKeyDown),\n\tkeyPress: deprecate(\"keyPress()\", \"onKeyPress()\", onKeyPress),\n\tkeyPressRep: deprecate(\"keyPressRep()\", \"onKeyPressRepeat()\", onKeyPressRepeat),\n\tkeyRelease: deprecate(\"keyRelease()\", \"onKeyRelease()\", onKeyRelease),\n\tmouseDown: deprecate(\"mouseDown()\", \"onMouseDown()\", onMouseDown),\n\tmouseClick: deprecate(\"mouseClick()\", \"onMousePress()\", onMousePress),\n\tmouseRelease: deprecate(\"mouseRelease()\", \"onMouseRelease()\", onMouseRelease),\n\tmouseMove: deprecate(\"mouseMove()\", \"onMouseMove()\", onMouseMove),\n\tcharInput: deprecate(\"charInput()\", \"onCharInput()\", onCharInput),\n\ttouchStart: deprecate(\"touchStart()\", \"onTouchStart()\", onTouchStart),\n\ttouchMove: deprecate(\"touchMove()\", \"onTouchMove()\", onTouchMove),\n\ttouchEnd: deprecate(\"touchEnd()\", \"onTouchEnd()\", onTouchEnd),\n\tfocused: deprecate(\"focused()\", \"isFocused()\", isFocused),\n\tready: deprecate(\"ready()\", \"onLoad()\", onLoad),\n};\n\nif (gopt.plugins) {\n\tgopt.plugins.forEach(plug);\n}\n\n// export everything to window if global is set\nif (gopt.global !== false) {\n\tfor (const k in ctx) {\n\t\twindow[k] = ctx[k];\n\t}\n}\n\nreturn ctx;\n\n};\n", "export class IDList<T> extends Map<number, T> {\n\t_lastID: number;\n\tconstructor(...args) {\n\t\tsuper(...args);\n\t\tthis._lastID = 0;\n\t}\n\tpush(v: T): number {\n\t\tconst id = this._lastID;\n\t\tthis.set(id, v);\n\t\tthis._lastID++;\n\t\treturn id;\n\t}\n\tpushd(v: T): () => void {\n\t\tconst id = this.push(v);\n\t\treturn () => this.delete(id);\n\t}\n}\n\nexport function deepEq(o1: any, o2: any): boolean {\n\tconst t1 = typeof o1;\n\tconst t2 = typeof o2;\n\tif (t1 !== t2) {\n\t\treturn false;\n\t}\n\tif (t1 === \"object\" && t2 === \"object\") {\n\t\tconst k1 = Object.keys(o1);\n\t\tconst k2 = Object.keys(o2);\n\t\tif (k1.length !== k2.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (const k of k1) {\n\t\t\tconst v1 = o1[k];\n\t\t\tconst v2 = o2[k];\n\t\t\tif (!(typeof v1 === \"function\" && typeof v2 === \"function\")) {\n\t\t\t\tif (!deepEq(v1, v2)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\treturn o1 === o2;\n}\n\nexport function downloadURL(url: string, filename: string) {\n\tconst a = document.createElement(\"a\");\n\tdocument.body.appendChild(a);\n\ta.setAttribute(\"style\", \"display: none\");\n\ta.href = url;\n\ta.download = filename;\n\ta.click();\n\tdocument.body.removeChild(a);\n}\n\nexport function downloadBlob(blob: Blob, filename: string) {\n\tconst url = URL.createObjectURL(blob);\n\tdownloadURL(url, filename);\n\tURL.revokeObjectURL(url);\n}\n\nexport function isDataURL(str: string) {\n\treturn str.match(/^data:\\w+\\/\\w+;base64,.+/);\n}\n\nexport const uid = (() => {\n\tlet id = 0;\n\treturn () => id++;\n})();\n\nconst warned = new Set();\n\nexport function deprecateMsg(oldName: string, newName: string) {\n\tif (!warned.has(oldName)) {\n\t\twarned.add(oldName);\n\t\tconsole.warn(`${oldName} is deprecated. Use ${newName} instead.`);\n\t}\n}\n\nexport const deprecate = (oldName: string, newName: string, newFunc: (...args) => any) => (...args) => {\n\tdeprecateMsg(oldName, newName);\n\treturn newFunc(...args);\n};\n", "import {\n\tVec4,\n\tPoint,\n\tPolygon,\n\tArea,\n} from \"./types\";\n\nimport {\n\tdeprecateMsg,\n} from \"./utils\";\n\nexport function deg2rad(deg: number): number {\n\treturn deg * Math.PI / 180;\n}\n\nexport function rad2deg(rad: number): number {\n\treturn rad * 180 / Math.PI;\n}\n\nexport function clamp(\n\tval: number,\n\tmin: number,\n\tmax: number,\n): number {\n\tif (min > max) {\n\t\treturn clamp(val, max, min);\n\t}\n\treturn Math.min(Math.max(val, min), max);\n}\n\nexport function lerp(\n\ta: number,\n\tb: number,\n\tt: number,\n): number {\n\treturn a + (b - a) * t;\n}\n\nexport function map(\n\tv: number,\n\tl1: number,\n\th1: number,\n\tl2: number,\n\th2: number,\n): number {\n\treturn l2 + (v - l1) / (h1 - l1) * (h2 - l2);\n}\n\nexport function mapc(\n\tv: number,\n\tl1: number,\n\th1: number,\n\tl2: number,\n\th2: number,\n): number {\n\treturn clamp(map(v, l1, h1, l2, h2), l2, h2);\n}\n\nexport class Vec2 {\n\tx: number = 0;\n\ty: number = 0;\n\tconstructor(x: number = 0, y: number = x) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t}\n\tstatic fromAngle(deg: number) {\n\t\tconst angle = deg2rad(deg);\n\t\treturn new Vec2(Math.cos(angle), Math.sin(angle));\n\t}\n\tstatic LEFT = new Vec2(-1, 0);\n\tstatic RIGHT = new Vec2(1, 0);\n\tstatic UP = new Vec2(0, -1);\n\tstatic DOWN = new Vec2(0, 1);\n\tclone(): Vec2 {\n\t\treturn new Vec2(this.x, this.y);\n\t}\n\tadd(...args): Vec2 {\n\t\tconst p2 = vec2(...args);\n\t\treturn new Vec2(this.x + p2.x, this.y + p2.y);\n\t}\n\tsub(...args): Vec2 {\n\t\tconst p2 = vec2(...args);\n\t\treturn new Vec2(this.x - p2.x, this.y - p2.y);\n\t}\n\tscale(...args): Vec2 {\n\t\tconst s = vec2(...args);\n\t\treturn new Vec2(this.x * s.x, this.y * s.y);\n\t}\n\tdist(...args): number {\n\t\tconst p2 = vec2(...args);\n\t\treturn Math.sqrt(\n\t\t\t(this.x - p2.x) * (this.x - p2.x)\n\t\t\t+ (this.y - p2.y) * (this.y - p2.y)\n\t\t);\n\t}\n\tlen(): number {\n\t\treturn this.dist(new Vec2(0, 0));\n\t}\n\tunit(): Vec2 {\n\t\treturn this.scale(1 / this.len());\n\t}\n\tnormal(): Vec2 {\n\t\treturn new Vec2(this.y, -this.x);\n\t}\n\tdot(p2: Vec2): number {\n\t\treturn this.x * p2.x + this.y * p2.y;\n\t}\n\tangle(...args): number {\n\t\tconst p2 = vec2(...args);\n\t\treturn rad2deg(Math.atan2(this.y - p2.y, this.x - p2.x));\n\t}\n\tlerp(p2: Vec2, t: number): Vec2 {\n\t\treturn new Vec2(lerp(this.x, p2.x, t), lerp(this.y, p2.y, t));\n\t}\n\ttoFixed(n: number): Vec2 {\n\t\treturn new Vec2(Number(this.x.toFixed(n)), Number(this.y.toFixed(n)));\n\t}\n\teq(other: Vec2): boolean {\n\t\treturn this.x === other.x && this.y === other.y;\n\t}\n\ttoString(): string {\n\t\treturn `(${this.x.toFixed(2)}, ${this.y.toFixed(2)})`;\n\t}\n\tstr(): string {\n\t\treturn this.toString();\n\t}\n}\n\nexport function vec2(...args): Vec2 {\n\tif (args.length === 1) {\n\t\tif (args[0] instanceof Vec2) {\n\t\t\treturn vec2(args[0].x, args[0].y);\n\t\t} else if (Array.isArray(args[0]) && args[0].length === 2) {\n\t\t\treturn vec2.apply(null, args[0]);\n\t\t}\n\t}\n\treturn new Vec2(...args);\n}\n\nexport class Vec3 {\n\tx: number = 0;\n\ty: number = 0;\n\tz: number = 0;\n\tconstructor(x: number, y: number, z: number) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t}\n\txy() {\n\t\treturn vec2(this.x, this.y);\n\t}\n}\n\nexport const vec3 = (x, y, z) => new Vec3(x, y, z);\n\nexport class Color {\n\n\tr: number = 255;\n\tg: number = 255;\n\tb: number = 255;\n\n\tconstructor(r: number, g: number, b: number) {\n\t\tthis.r = clamp(r, 0, 255);\n\t\tthis.g = clamp(g, 0, 255);\n\t\tthis.b = clamp(b, 0, 255);\n\t}\n\n\tstatic fromArray(arr: number[]) {\n\t\treturn new Color(arr[0], arr[1], arr[2])\n\t}\n\n\tstatic RED = rgb(255, 0, 0);\n\tstatic GREEN = rgb(0, 255, 0);\n\tstatic BLUE = rgb(0, 0, 255);\n\tstatic YELLOW = rgb(255, 255, 0);\n\tstatic MAGENTA = rgb(255, 0, 255);\n\tstatic CYAN = rgb(0, 255, 255);\n\tstatic WHITE = rgb(255, 255, 255);\n\tstatic BLACK = rgb(0, 0, 0);\n\n\tclone(): Color {\n\t\treturn new Color(this.r, this.g, this.b);\n\t}\n\n\tlighten(a: number): Color {\n\t\treturn new Color(this.r + a, this.g + a, this.b + a);\n\t}\n\n\tdarken(a: number): Color {\n\t\treturn this.lighten(-a);\n\t}\n\n\tinvert(): Color {\n\t\treturn new Color(255 - this.r, 255 - this.g, 255 - this.b);\n\t}\n\n\tmult(other: Color): Color {\n\t\treturn new Color(\n\t\t\tthis.r * other.r / 255,\n\t\t\tthis.g * other.g / 255,\n\t\t\tthis.b * other.b / 255,\n\t\t);\n\t}\n\n\teq(other: Color): boolean {\n\t\treturn this.r === other.r\n\t\t\t&& this.g === other.g\n\t\t\t&& this.b === other.b\n\t\t\t;\n\t}\n\n\tstr(): string {\n\t\tdeprecateMsg(\"str()\", \"toString()\");\n\t\treturn `(${this.r}, ${this.g}, ${this.b})`;\n\t}\n\n\ttoString(): string {\n\t\treturn `(${this.r}, ${this.g}, ${this.b})`;\n\t}\n\n\tstatic fromHSL(h: number, s: number, l: number) {\n\n\t\tif (s == 0){\n\t\t\treturn rgb(255 * l, 255 * l, 255 * l);\n\t\t}\n\n\t\tconst hue2rgb = (p, q, t) => {\n\t\t\tif (t < 0) t += 1;\n\t\t\tif (t > 1) t -= 1;\n\t\t\tif (t < 1 / 6) return p + (q - p) * 6 * t;\n\t\t\tif (t < 1 / 2) return q;\n\t\t\tif (t < 2 / 3) return p + (q - p) * (2/3 - t) * 6;\n\t\t\treturn p;\n\t\t}\n\n\t\tconst q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n\t\tconst p = 2 * l - q;\n\t\tconst r = hue2rgb(p, q, h + 1 / 3);\n\t\tconst g = hue2rgb(p, q, h);\n\t\tconst b = hue2rgb(p, q, h - 1 / 3);\n\n\t\treturn new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255));\n\n\t}\n\n}\n\nexport function rgb(...args): Color {\n\tif (args.length === 0) {\n\t\treturn new Color(255, 255, 255);\n\t} else if (args.length === 1) {\n\t\tif (args[0] instanceof Color) {\n\t\t\treturn args[0].clone();\n\t\t} else if (Array.isArray(args[0]) && args[0].length === 3) {\n\t\t\treturn Color.fromArray(args[0]);\n\t\t}\n\t}\n\t// @ts-ignore\n\treturn new Color(...args);\n}\n\nexport const hsl2rgb = (h, s, l) => Color.fromHSL(h, s, l);\n\nexport class Quad {\n\tx: number = 0;\n\ty: number = 0;\n\tw: number = 1;\n\th: number = 1;\n\tconstructor(x: number, y: number, w: number, h: number) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.w = w;\n\t\tthis.h = h;\n\t}\n\tscale(other: Quad): Quad {\n\t\treturn new Quad(\n\t\t\tthis.x + this.w * other.x,\n\t\t\tthis.y + this.h * other.y,\n\t\t\tthis.w * other.w,\n\t\t\tthis.h * other.h\n\t\t);\n\t}\n\tclone(): Quad {\n\t\treturn new Quad(this.x, this.y, this.w, this.h);\n\t}\n\teq(other: Quad): boolean {\n\t\treturn this.x === other.x\n\t\t\t&& this.y === other.y\n\t\t\t&& this.w === other.w\n\t\t\t&& this.h === other.h;\n\t}\n\ttoString(): string {\n\t\treturn `quad(${this.x}, ${this.y}, ${this.w}, ${this.h})`;\n\t}\n}\n\nexport function quad(x: number, y: number, w: number, h: number): Quad {\n\treturn new Quad(x, y, w, h);\n}\n\nexport class Mat4 {\n\n\tm: number[] = [\n\t\t1, 0, 0, 0,\n\t\t0, 1, 0, 0,\n\t\t0, 0, 1, 0,\n\t\t0, 0, 0, 1,\n\t];\n\n\tconstructor(m?: number[]) {\n\t\tif (m) {\n\t\t\tthis.m = m;\n\t\t}\n\t}\n\n\tclone(): Mat4 {\n\t\treturn new Mat4(this.m);\n\t};\n\n\tmult(other: Mat4): Mat4 {\n\n\t\tconst out = [];\n\n\t\tfor (let i = 0; i < 4; i++) {\n\t\t\tfor (let j = 0; j < 4; j++) {\n\t\t\t\tout[i * 4 + j] =\n\t\t\t\t\tthis.m[0 * 4 + j] * other.m[i * 4 + 0] +\n\t\t\t\t\tthis.m[1 * 4 + j] * other.m[i * 4 + 1] +\n\t\t\t\t\tthis.m[2 * 4 + j] * other.m[i * 4 + 2] +\n\t\t\t\t\tthis.m[3 * 4 + j] * other.m[i * 4 + 3];\n\t\t\t}\n\t\t}\n\n\t\treturn new Mat4(out);\n\n\t}\n\n\tmultVec4(p: Vec4): Vec4 {\n\t\treturn {\n\t\t\tx: p.x * this.m[0] + p.y * this.m[4] + p.z * this.m[8] + p.w * this.m[12],\n\t\t\ty: p.x * this.m[1] + p.y * this.m[5] + p.z * this.m[9] + p.w * this.m[13],\n\t\t\tz: p.x * this.m[2] + p.y * this.m[6] + p.z * this.m[10] + p.w * this.m[14],\n\t\t\tw: p.x * this.m[3] + p.y * this.m[7] + p.z * this.m[11] + p.w * this.m[15]\n\t\t};\n\t}\n\n\tmultVec3(p: Vec3): Vec3 {\n\t\tconst p4 = this.multVec4({\n\t\t\tx: p.x,\n\t\t\ty: p.y,\n\t\t\tz: p.z,\n\t\t\tw: 1.0,\n\t\t});\n\t\treturn vec3(p4.x, p4.y, p4.z);\n\t}\n\n\tmultVec2(p: Vec2): Vec2 {\n\t\treturn vec2(\n\t\t\tp.x * this.m[0] + p.y * this.m[4] + 0 * this.m[8] + 1 * this.m[12],\n\t\t\tp.x * this.m[1] + p.y * this.m[5] + 0 * this.m[9] + 1 * this.m[13],\n\t\t);\n\t}\n\n\tstatic translate(p: Vec2): Mat4 {\n\t\treturn new Mat4([\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\tp.x, p.y, 0, 1,\n\t\t]);\n\t}\n\n\tstatic scale(s: Vec2): Mat4 {\n\t\treturn new Mat4([\n\t\t\ts.x, 0, 0, 0,\n\t\t\t0, s.y, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1,\n\t\t]);\n\t}\n\n\tstatic rotateX(a: number): Mat4 {\n\t\ta = deg2rad(-a);\n\t\treturn new Mat4([\n\t\t\t1, 0, 0, 0,\n\t\t\t0, Math.cos(a), -Math.sin(a), 0,\n\t\t\t0, Math.sin(a), Math.cos(a), 0,\n\t\t\t0, 0, 0, 1,\n\t\t]);\n\t}\n\n\tstatic rotateY(a: number): Mat4 {\n\t\ta = deg2rad(-a);\n\t\treturn new Mat4([\n\t\t\tMath.cos(a), 0, Math.sin(a), 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t-Math.sin(a), 0, Math.cos(a), 0,\n\t\t\t0, 0, 0, 1,\n\t\t]);\n\t}\n\n\tstatic rotateZ(a: number): Mat4 {\n\t\ta = deg2rad(-a);\n\t\treturn new Mat4([\n\t\t\tMath.cos(a), -Math.sin(a), 0, 0,\n\t\t\tMath.sin(a), Math.cos(a), 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1,\n\t\t]);\n\t}\n\n\ttranslate(p: Vec2): Mat4 {\n\t\treturn this.mult(Mat4.translate(p));\n\t}\n\n\tscale(s: Vec2): Mat4 {\n\t\treturn this.mult(Mat4.scale(s));\n\t}\n\n\trotateX(a: number): Mat4 {\n\t\treturn this.mult(Mat4.rotateX(a));\n\t}\n\n\trotateY(a: number): Mat4 {\n\t\treturn this.mult(Mat4.rotateY(a));\n\t}\n\n\trotateZ(a: number): Mat4 {\n\t\treturn this.mult(Mat4.rotateZ(a));\n\t}\n\n\tinvert(): Mat4 {\n\n\t\tconst out = [];\n\n\t\tconst f00 = this.m[10] * this.m[15] - this.m[14] * this.m[11];\n\t\tconst f01 = this.m[9] * this.m[15] - this.m[13] * this.m[11];\n\t\tconst f02 = this.m[9] * this.m[14] - this.m[13] * this.m[10];\n\t\tconst f03 = this.m[8] * this.m[15] - this.m[12] * this.m[11];\n\t\tconst f04 = this.m[8] * this.m[14] - this.m[12] * this.m[10];\n\t\tconst f05 = this.m[8] * this.m[13] - this.m[12] * this.m[9];\n\t\tconst f06 = this.m[6] * this.m[15] - this.m[14] * this.m[7];\n\t\tconst f07 = this.m[5] * this.m[15] - this.m[13] * this.m[7];\n\t\tconst f08 = this.m[5] * this.m[14] - this.m[13] * this.m[6];\n\t\tconst f09 = this.m[4] * this.m[15] - this.m[12] * this.m[7];\n\t\tconst f10 = this.m[4] * this.m[14] - this.m[12] * this.m[6];\n\t\tconst f11 = this.m[5] * this.m[15] - this.m[13] * this.m[7];\n\t\tconst f12 = this.m[4] * this.m[13] - this.m[12] * this.m[5];\n\t\tconst f13 = this.m[6] * this.m[11] - this.m[10] * this.m[7];\n\t\tconst f14 = this.m[5] * this.m[11] - this.m[9] * this.m[7];\n\t\tconst f15 = this.m[5] * this.m[10] - this.m[9] * this.m[6];\n\t\tconst f16 = this.m[4] * this.m[11] - this.m[8] * this.m[7];\n\t\tconst f17 = this.m[4] * this.m[10] - this.m[8] * this.m[6];\n\t\tconst f18 = this.m[4] * this.m[9] - this.m[8] * this.m[5];\n\n\t\tout[0] = this.m[5] * f00 - this.m[6] * f01 + this.m[7] * f02;\n\t\tout[4] = -(this.m[4] * f00 - this.m[6] * f03 + this.m[7] * f04);\n\t\tout[8] = this.m[4] * f01 - this.m[5] * f03 + this.m[7] * f05;\n\t\tout[12] = -(this.m[4] * f02 - this.m[5] * f04 + this.m[6] * f05);\n\n\t\tout[1] = -(this.m[1] * f00 - this.m[2] * f01 + this.m[3] * f02);\n\t\tout[5] = this.m[0] * f00 - this.m[2] * f03 + this.m[3] * f04;\n\t\tout[9] = -(this.m[0] * f01 - this.m[1] * f03 + this.m[3] * f05);\n\t\tout[13] = this.m[0] * f02 - this.m[1] * f04 + this.m[2] * f05;\n\n\t\tout[2] = this.m[1] * f06 - this.m[2] * f07 + this.m[3] * f08;\n\t\tout[6] = -(this.m[0] * f06 - this.m[2] * f09 + this.m[3] * f10);\n\t\tout[10] = this.m[0] * f11 - this.m[1] * f09 + this.m[3] * f12;\n\t\tout[14] = -(this.m[0] * f08 - this.m[1] * f10 + this.m[2] * f12);\n\n\t\tout[3] = -(this.m[1] * f13 - this.m[2] * f14 + this.m[3] * f15);\n\t\tout[7] = this.m[0] * f13 - this.m[2] * f16 + this.m[3] * f17;\n\t\tout[11] = -(this.m[0] * f14 - this.m[1] * f16 + this.m[3] * f18);\n\t\tout[15] = this.m[0] * f15 - this.m[1] * f17 + this.m[2] * f18;\n\n\t\tconst det =\n\t\t\tthis.m[0] * out[0] +\n\t\t\tthis.m[1] * out[4] +\n\t\t\tthis.m[2] * out[8] +\n\t\t\tthis.m[3] * out[12];\n\n\t\tfor (let i = 0; i < 4; i++) {\n\t\t\tfor (let j = 0; j < 4; j++) {\n\t\t\t\tout[i * 4 + j] *= (1.0 / det);\n\t\t\t}\n\t\t}\n\n\t\treturn new Mat4(out);\n\n\t}\n\n\ttoString(): string {\n\t\treturn this.m.toString();\n\t}\n\n}\n\nexport function wave(lo: number, hi: number, t: number, f = Math.sin): number {\n\treturn lo + (f(t) + 1) / 2 * (hi - lo);\n}\n\n// basic ANSI C LCG\nconst A = 1103515245;\nconst C = 12345;\nconst M = 2147483648;\n\nexport class RNG {\n\tseed: number;\n\tconstructor(seed: number) {\n\t\tthis.seed = seed;\n\t}\n\tgen(...args) {\n\t\tif (args.length === 0) {\n\t\t\tthis.seed = (A * this.seed + C) % M;\n\t\t\treturn this.seed / M;\n\t\t} else if (args.length === 1) {\n\t\t\tif (typeof args[0] === \"number\") {\n\t\t\t\treturn this.gen(0, args[0]);\n\t\t\t} else if (args[0] instanceof Vec2) {\n\t\t\t\treturn this.gen(vec2(0, 0), args[0]);\n\t\t\t} else if (args[0] instanceof Color) {\n\t\t\t\treturn this.gen(rgb(0, 0, 0), args[0]);\n\t\t\t}\n\t\t} else if (args.length === 2) {\n\t\t\tif (typeof args[0] === \"number\" && typeof args[1] === \"number\") {\n\t\t\t\treturn (this.gen() * (args[1] - args[0])) + args[0];\n\t\t\t} else if (args[0] instanceof Vec2 && args[1] instanceof Vec2) {\n\t\t\t\treturn vec2(\n\t\t\t\t\tthis.gen(args[0].x, args[1].x),\n\t\t\t\t\tthis.gen(args[0].y, args[1].y),\n\t\t\t\t);\n\t\t\t} else if (args[0] instanceof Color && args[1] instanceof Color) {\n\t\t\t\treturn rgb(\n\t\t\t\t\tthis.gen(args[0].r, args[1].r),\n\t\t\t\t\tthis.gen(args[0].g, args[1].g),\n\t\t\t\t\tthis.gen(args[0].b, args[1].b),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TODO: let user pass seed\nconst defRNG = new RNG(Date.now());\n\nexport function rng(seed: number): RNG {\n\tdeprecateMsg(\"rng()\", \"new RNG()\");\n\treturn new RNG(seed);\n}\n\nexport function randSeed(seed?: number): number {\n\tif (seed != null) {\n\t\tdefRNG.seed = seed;\n\t}\n\treturn defRNG.seed;\n}\n\nexport function rand(...args) {\n\t// @ts-ignore\n\treturn defRNG.gen(...args);\n}\n\n// TODO: randi() to return 0 / 1?\nexport function randi(...args) {\n\treturn Math.floor(rand(...args));\n}\n\nexport function chance(p: number): boolean {\n\treturn rand() <= p;\n}\n\nexport function choose<T>(list: T[]): T {\n\treturn list[randi(list.length)];\n}\n\n// TODO: better name\nexport function testRectRect2(r1: Rect, r2: Rect): boolean {\n\treturn r1.p2.x >= r2.p1.x\n\t\t&& r1.p1.x <= r2.p2.x\n\t\t&& r1.p2.y >= r2.p1.y\n\t\t&& r1.p1.y <= r2.p2.y;\n}\n\nexport function testRectRect(r1: Rect, r2: Rect): boolean {\n\treturn r1.p2.x > r2.p1.x\n\t\t&& r1.p1.x < r2.p2.x\n\t\t&& r1.p2.y > r2.p1.y\n\t\t&& r1.p1.y < r2.p2.y;\n}\n\n// TODO: better name\nexport function testLineLineT(l1: Line, l2: Line): number | null {\n\n\tif ((l1.p1.x === l1.p2.x && l1.p1.y === l1.p2.y) || (l2.p1.x === l2.p2.x && l2.p1.y === l2.p2.y)) {\n\t\treturn null;\n\t}\n\n\tconst denom = ((l2.p2.y - l2.p1.y) * (l1.p2.x - l1.p1.x) - (l2.p2.x - l2.p1.x) * (l1.p2.y - l1.p1.y));\n\n\t// parallel\n\tif (denom === 0) {\n\t\treturn null;\n\t}\n\n\tconst ua = ((l2.p2.x - l2.p1.x) * (l1.p1.y - l2.p1.y) - (l2.p2.y - l2.p1.y) * (l1.p1.x - l2.p1.x)) / denom;\n\tconst ub = ((l1.p2.x - l1.p1.x) * (l1.p1.y - l2.p1.y) - (l1.p2.y - l1.p1.y) * (l1.p1.x - l2.p1.x)) / denom;\n\n\t// is the intersection on the segments\n\tif (ua < 0 || ua > 1 || ub < 0 || ub > 1) {\n\t\treturn null;\n\t}\n\n\treturn ua;\n\n}\n\nexport function testLineLine(l1: Line, l2: Line): Vec2 | null {\n\tconst t = testLineLineT(l1, l2);\n\tif (!t) return null;\n\treturn vec2(\n\t\tl1.p1.x + t * (l1.p2.x - l1.p1.x),\n\t\tl1.p1.y + t * (l1.p2.y - l1.p1.y),\n\t);\n}\n\nexport function testRectLine(r: Rect, l: Line): boolean {\n\tif (testRectPoint(r, l.p1) || testRectPoint(r, l.p2)) {\n\t\treturn true;\n\t}\n\treturn !!testLineLine(l, new Line(r.p1, vec2(r.p2.x, r.p1.y)))\n\t\t|| !!testLineLine(l, new Line(vec2(r.p2.x, r.p1.y), r.p2))\n\t\t|| !!testLineLine(l, new Line(r.p2, vec2(r.p1.x, r.p2.y)))\n\t\t|| !!testLineLine(l, new Line(vec2(r.p1.x, r.p2.y), r.p1));\n}\n\nexport function testRectPoint2(r: Rect, pt: Point): boolean {\n\treturn pt.x >= r.p1.x && pt.x <= r.p2.x && pt.y >= r.p1.y && pt.y <= r.p2.y;\n}\n\nexport function testRectPoint(r: Rect, pt: Point): boolean {\n\treturn pt.x > r.p1.x && pt.x < r.p2.x && pt.y > r.p1.y && pt.y < r.p2.y;\n}\n\nexport function testRectCircle(r: Rect, c: Circle): boolean {\n\tconst nx = Math.max(r.p1.x, Math.min(c.center.x, r.p2.x));\n\tconst ny = Math.max(r.p1.y, Math.min(c.center.y, r.p2.y));\n\tconst nearestPoint = vec2(nx, ny);\n\treturn nearestPoint.dist(c.center) <= c.radius;\n}\n\nexport function testRectPolygon(r: Rect, p: Polygon): boolean {\n\treturn testPolygonPolygon(p, [\n\t\tr.p1,\n\t\tvec2(r.p2.x, r.p1.y),\n\t\tr.p2,\n\t\tvec2(r.p1.x, r.p2.y),\n\t]);\n}\n\n// TODO\nexport function testLinePoint(l: Line, pt: Vec2): boolean {\n\treturn false;\n}\n\n// TODO\nexport function testLineCircle(l: Line, c: Circle): boolean {\n\treturn false;\n}\n\nexport function testLinePolygon(l: Line, p: Polygon): boolean {\n\n\t// test if line is inside\n\tif (testPolygonPoint(p, l.p1) || testPolygonPoint(p, l.p2)) {\n\t\treturn true;\n\t}\n\n\t// test each line\n\tfor (let i = 0; i < p.length; i++) {\n\t\tconst p1 = p[i];\n\t\tconst p2 = p[(i + 1) % p.length];\n\t\tif (testLineLine(l, { p1, p2 })) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n\n}\n\nexport function testCirclePoint(c: Circle, p: Point): boolean {\n\treturn c.center.dist(p) < c.radius;\n}\n\nexport function testCircleCircle(c1: Circle, c2: Circle): boolean {\n\treturn c1.center.dist(c2.center) < c1.radius + c2.radius;\n}\n\n// TODO\nexport function testCirclePolygon(c: Circle, p: Polygon): boolean {\n\treturn false;\n}\n\nexport function testPolygonPolygon(p1: Polygon, p2: Polygon): boolean {\n\tfor (let i = 0; i < p1.length; i++) {\n\t\tconst l = {\n\t\t\tp1: p1[i],\n\t\t\tp2: p1[(i + 1) % p1.length],\n\t\t};\n\t\tif (testLinePolygon(l, p2)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html\nexport function testPolygonPoint(p: Polygon, pt: Point): boolean {\n\n\tlet c = false;\n\n\tfor (let i = 0, j = p.length - 1; i < p.length; j = i++) {\n\t\tif (\n\t\t\t((p[i].y > pt.y) != (p[j].y > pt.y))\n\t\t\t&& (pt.x < (p[j].x - p[i].x) * (pt.y - p[i].y) / (p[j].y - p[i].y) + p[i].x)\n\t\t) {\n\t\t\tc = !c;\n\t\t}\n\t}\n\n\treturn c;\n\n}\n\nexport function testPointPoint(p1: Point, p2: Point): boolean {\n\treturn p1.eq(p2);\n}\n\nexport function testAreaRect(a: Area, r: Rect): boolean {\n\tswitch (a.shape) {\n\t\tcase \"rect\": return testRectRect(r, a);\n\t\tcase \"line\": return testRectLine(r, a);\n\t\tcase \"circle\": return testRectCircle(r, a);\n\t\tcase \"polygon\": return testRectPolygon(r, a.pts);\n\t\tcase \"point\": return testRectPoint(r, a.pt);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a as Area).shape}`);\n}\n\nexport function testAreaLine(a: Area, l: Line): boolean {\n\tswitch (a.shape) {\n\t\tcase \"rect\": return testRectLine(a, l);\n\t\tcase \"line\": return Boolean(testLineLine(a, l));\n\t\tcase \"circle\": return testLineCircle(l, a);\n\t\tcase \"polygon\": return testLinePolygon(l, a.pts);\n\t\tcase \"point\": return testLinePoint(l, a.pt);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a as Area).shape}`);\n}\n\nexport function testAreaCircle(a: Area, c: Circle): boolean {\n\tswitch (a.shape) {\n\t\tcase \"rect\": return testRectCircle(a, c);\n\t\tcase \"line\": return testLineCircle(a, c);\n\t\tcase \"circle\": return testCircleCircle(a, c);\n\t\tcase \"polygon\": return testCirclePolygon(c, a.pts);\n\t\tcase \"point\": return testCirclePoint(c, a.pt);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a as Area).shape}`);\n}\n\nexport function testAreaPolygon(a: Area, p: Polygon): boolean {\n\tswitch (a.shape) {\n\t\tcase \"rect\": return testRectPolygon(a, p);\n\t\tcase \"line\": return testLinePolygon(a, p);\n\t\tcase \"circle\": return testCirclePolygon(a, p);\n\t\tcase \"polygon\": return testPolygonPolygon(p, a.pts);\n\t\tcase \"point\": return testPolygonPoint(p, a.pt);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a as Area).shape}`);\n}\n\nexport function testAreaPoint(a: Area, p: Point): boolean {\n\tswitch (a.shape) {\n\t\tcase \"rect\": return testRectPoint(a, p);\n\t\tcase \"line\": return testLinePoint(a, p);\n\t\tcase \"circle\": return testCirclePoint(a, p);\n\t\tcase \"polygon\": return testPolygonPoint(a.pts, p);\n\t\tcase \"point\": return testPointPoint(a.pt, p);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a as Area).shape}`);\n}\n\nexport function testAreaArea(a1: Area, a2: Area): boolean {\n\tswitch (a2.shape) {\n\t\tcase \"rect\": return testAreaRect(a1, a2);\n\t\tcase \"line\": return testAreaLine(a1, a2);\n\t\tcase \"circle\": return testAreaCircle(a1, a2);\n\t\tcase \"polygon\": return testAreaPolygon(a1, a2.pts);\n\t\tcase \"point\": return testAreaPoint(a1, a2.pt);\n\t}\n\tthrow new Error(`Unknown area shape: ${(a2 as Area).shape}`);\n}\n\nexport function minkDiff(r1: Rect, r2: Rect): Rect {\n\treturn {\n\t\tp1: vec2(r1.p1.x - r2.p2.x, r1.p1.y - r2.p2.y),\n\t\tp2: vec2(r1.p2.x - r2.p1.x, r1.p2.y - r2.p1.y),\n\t};\n}\n\nexport class Line {\n\tp1: Vec2;\n\tp2: Vec2;\n\tconstructor(p1: Vec2, p2: Vec2) {\n\t\tthis.p1 = p1;\n\t\tthis.p2 = p2;\n\t}\n}\n\nexport class Rect {\n\tp1: Vec2;\n\tp2: Vec2;\n\tconstructor(p1: Vec2, p2: Vec2) {\n\t\tthis.p1 = p1;\n\t\tthis.p2 = p2;\n\t}\n}\n\nexport class Circle {\n\tcenter: Vec2;\n\tradius: number;\n\tconstructor(center: Vec2, radius: number) {\n\t\tthis.center = center;\n\t\tthis.radius = radius;\n\t}\n}\n", "export default class FPSCounter {\n\n\tprivate buf: number[] = [];\n\tprivate timer: number = 0;\n\tfps: number = 0;\n\n\ttick(dt: number) {\n\n\t\tthis.buf.push(1 / dt);\n\t\tthis.timer += dt;\n\n\t\tif (this.timer >= 1) {\n\t\t\tthis.timer = 0;\n\t\t\tthis.fps = Math.round(this.buf.reduce((a, b) => a + b) / this.buf.length);\n\t\t\tthis.buf = [];\n\t\t}\n\n\t}\n\n}\n", "export default class Timer {\n\n\ttime: number\n\taction: () => void\n\tfinished: boolean = false\n\tpaused: boolean = false\n\n\tconstructor(time: number, action: () => void) {\n\t\tthis.time = time;\n\t\tthis.action = action;\n\t}\n\n\ttick(dt: number): boolean {\n\t\tif (this.finished || this.paused) return false;\n\t\tthis.time -= dt;\n\t\tif (this.time <= 0) {\n\t\t\tthis.action();\n\t\t\tthis.finished = true;\n\t\t\tthis.time = 0;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\treset(time) {\n\t\tthis.time = time;\n\t\tthis.finished = false;\n\t}\n\n}\n"],
|
|
"mappings": "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W,KAAK,GAAI,YACnB,EAAI,YAAY,GAAK,GAAmB,EAAI,YAAY,IAGzD,EAAI,aAAe,GACnB,EAAI,aAAe,GACnB,EAAI,aAAe,GACnB,EAAI,mBAAqB,GACzB,EAAI,cAAgB,GACpB,EAAI,OAAS,sBAAsB,IApCtB,SAwCd,EAAI,QAAU,GACd,EAAI,OAAS,sBAAsB,GA3C3B,YAgDT,GAAI,IAAM,CAGT,KAEA,AAAK,EAAI,OAOR,GAAK,QAAQ,SAER,EAAM,QACV,KAGD,KACA,KAEI,EAAK,QAAU,IAClB,KAGD,MAnBA,MACA,KACA,QAuBF,EACC,SACA,GACA,GACA,IAGD,EACC,UACA,GACA,GACA,IAGD,EACC,OACA,GACA,EACA,EACA,CACC,MAAO,koCAIT,EACC,QACA,GACA,EACA,IAGD,KACA,KAGA,GAAM,IAAiB,CAEtB,WACA,aACA,mBACA,aACA,WACA,cACA,gBACA,aACA,YACA,OAEA,QACA,SACA,UACA,KACA,QACA,cACA,UACA,aACA,SACA,UACA,aACA,cACA,gBACA,UACA,QAAS,IAAM,EAAI,QAEnB,UACA,UACA,YACA,UACA,SACA,YACA,WACA,WAEA,OACA,SACA,WACA,cACA,OACA,SACA,UAEA,OACA,SACA,UACA,SACA,WACA,UACA,SACA,QACA,UACA,QACA,QACA,UACA,UACA,WACA,QACA,UACA,SACA,SACA,SACA,QACA,UACA,YACA,KACA,QACA,WACA,WACA,UACA,SAEA,MACA,YACA,UACA,aACA,WACA,WAEA,aACA,aACA,oBACA,gBACA,eACA,gBACA,kBACA,eACA,eACA,gBACA,eACA,cACA,WACA,iBACA,iBACA,aACA,gBACA,sBACA,iBACA,eACA,kBACA,mBACA,gBAEA,QACA,QAEA,QACA,UACA,QACA,SAAU,EAAM,IAEhB,SACA,QACA,QACA,UACA,OACA,QACA,OACA,OACA,OACA,OACA,QACA,SACA,YACA,OACA,MACA,WACA,QACA,UACA,UACA,QACA,OACA,QACA,QACA,WACA,WACA,gBACA,gBACA,kBACA,mBACA,iBACA,gBACA,gBACA,gBACA,gBACA,iBACA,oBACA,mBACA,sBACA,oBACA,mBACA,mBAEA,cACA,YACA,cACA,WACA,YACA,aACA,gBACA,cACA,eACA,cACA,eACA,qBACA,iBACA,gBACA,gBACA,WAAY,GACZ,aAEA,QAEA,SACA,MAEA,YAEA,WACA,WAEA,QAEA,eACA,eAEA,OAAQ,EAAI,OAEZ,aAEA,KAAM,EAAK,KACX,MAAO,EAAK,MACZ,GAAI,EAAK,GACT,KAAM,EAAK,KAEX,IAAK,EAAM,IACX,MAAO,EAAM,MACb,KAAM,EAAM,KACZ,OAAQ,EAAM,OACd,QAAS,EAAM,QACf,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,MAAO,EAAM,MAEb,UAAW,EAAU,cAAe,cAAe,IACnD,aAAc,EAAU,iBAAkB,iBAAkB,IAC5D,gBAAiB,EAAU,oBAAqB,uBAAwB,IACxE,cAAe,EAAU,kBAAmB,kBAAmB,IAC/D,YAAa,EAAU,gBAAiB,gBAAiB,IACzD,eAAgB,EAAU,mBAAoB,mBAAoB,IAClE,gBAAiB,EAAU,oBAAqB,oBAAqB,IACrE,aAAc,EAAU,iBAAkB,iBAAkB,IAC5D,IAAK,EAAU,QAAS,mBAAoB,EAAK,WACjD,OAAQ,EAAU,WAAY,aAAc,IAC5C,OAAQ,EAAU,WAAY,WAAY,IAC1C,SAAU,EAAU,aAAc,cAAe,IACjD,OAAQ,EAAU,WAAY,YAAa,IAC3C,OAAQ,EAAU,WAAY,YAAa,IAC3C,QAAS,EAAU,YAAa,cAAe,IAC/C,SAAU,EAAU,aAAc,eAAgB,GAClD,YAAa,EAAU,gBAAiB,qBAAsB,IAC9D,WAAY,EAAU,eAAgB,iBAAkB,IACxD,UAAW,EAAU,cAAe,gBAAiB,IACrD,WAAY,EAAU,eAAgB,iBAAkB,IACxD,aAAc,EAAU,iBAAkB,mBAAoB,IAC9D,UAAW,EAAU,cAAe,gBAAiB,IACrD,UAAW,EAAU,cAAe,gBAAiB,IACrD,WAAY,EAAU,eAAgB,iBAAkB,IACxD,UAAW,EAAU,cAAe,gBAAiB,IACrD,SAAU,EAAU,aAAc,eAAgB,IAClD,QAAS,EAAU,YAAa,cAAe,IAC/C,MAAO,EAAU,UAAW,WAAY,KAQzC,GALI,EAAK,SACR,EAAK,QAAQ,QAAQ,IAIlB,EAAK,SAAW,GACnB,OAAW,KAAK,IACf,OAAO,GAAK,GAAI,GAIlB,MAAO,KA9rKQ",
|
|
"names": []
|
|
}
|