@oidoid/void 0.1.0-7 → 0.1.0-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +7 -8
- package/dist/public/index.js +1 -1
- package/dist/public/index.js.map +1 -1
- package/dist/public/{void-v0.1.0-6+20251020.7cdf98d.html → void-v0.1.0-8+20251022.b364155.html} +2 -2
- package/package.json +7 -8
- package/dist/meta.json +0 -1
- package/dist/public/favicon/favicon16.png +0 -0
- package/dist/public/favicon/favicon192.png +0 -0
- package/dist/public/favicon/favicon32.png +0 -0
- package/dist/public/favicon/favicon48.png +0 -0
- package/dist/public/favicon/favicon64.png +0 -0
- package/dist/public/preload-atlas.png +0 -0
- package/dist/public/void-v0.1.0-6+20251020.e4e9eef.html +0 -111
- package/dist/public/void-v0.1.0-7+20251021.7cdf98d.html +0 -111
- package/schema/config-file.test.ts +0 -55
- package/schema/config-file.ts +0 -69
- package/schema/config-file.v0.json +0 -68
- package/tools/atlas-pack/aseprite.ts +0 -60
- package/tools/atlas-pack/atlas-json-parser.test.ts +0 -780
- package/tools/atlas-pack/atlas-json-parser.ts +0 -159
- package/tools/atlas-pack/atlas-pack.ts +0 -51
- package/tools/bundle/bundle.ts +0 -64
- package/tools/bundle/html-plugin.ts +0 -135
- package/tools/types/config.ts +0 -65
- package/tools/types/package-json.ts +0 -4
- package/tools/utils/argv.test.ts +0 -41
- package/tools/utils/argv.ts +0 -29
- package/tools/utils/exec.ts +0 -22
- package/tools/utils/file-util.ts +0 -11
- package/tools/utils/html-parser.ts +0 -9
- package/tools/void.ts +0 -55
package/dist/public/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["<define:globalThis.voidVersion>", "../../src/types/void-version.ts", "../../node_modules/mem-font/dist/mem-prop-5x6.json", "../../node_modules/mem-font/src/index.ts", "../../src/graphics/layer.ts", "../../src/types/geo.ts", "../../src/ents/nine-patch-ent.ts", "../../src/text/font.ts", "../../src/text/text-layout.ts", "../../src/ents/text-ent.ts", "../../src/ents/button-ent.ts", "../../src/ents/cursor-ent.ts", "../../src/ents/follow-cam-ent.ts", "../../src/utils/debug.ts", "../../src/ents/zoo.ts", "../../src/graphics/atlas-parser.ts", "../../src/graphics/cam.ts", "../../src/utils/math.ts", "../../src/graphics/sprite.ts", "../../src/input/context-menu.ts", "../../src/input/gamepad.ts", "../../src/input/keyboard.ts", "../../src/input/pointer.ts", "../../src/input/wheel.ts", "../../src/input/input.ts", "../../src/mem/pool.ts", "../../src/utils/color-util.ts", "../../src/utils/dom-util.ts", "../../src/utils/canvas-util.ts", "../../src/utils/fetch-util.ts", "../../src/graphics/gl.ts", "../../src/graphics/sprite-frag.glsl.ts", "../../src/graphics/sprite-vert.glsl.ts", "../../src/graphics/renderer.ts", "../../src/looper.ts", "../../src/utils/delay-interval.ts", "../../src/void.ts", "../../src/index.ts", "../../src/demo/assets/preload-atlas.json", "../../src/demo/ents/clock-ent.ts", "../../src/demo/ents/render-toggle-ent.ts", "../../src/demo/ents/work-counter-ent.ts", "../../src/demo/game.ts", "../../src/demo/index.ts"],
|
|
4
|
-
"sourcesContent": ["{\"published\":\"20251021\",\"version\":\"0.1.0-7\"}", "export type VoidVersion = {\n /** package.json `published` YYYYMMDD. */\n published: string\n /** package.json semantic `version`. */\n version: string\n}\n\ndeclare namespace globalThis {\n var voidVersion: VoidVersion // set by esbuild.\n}\n\nexport const voidVersion: VoidVersion = globalThis.voidVersion\n", "{\n \"id\": \"mem-prop-5x6\",\n \"name\": \"mem 5x6\",\n \"cellWidth\": 5,\n \"cellHeight\": 6,\n \"leading\": 1,\n \"lineHeight\": 7,\n \"baseline\": 1,\n \"kerning\": {\n \" 0\": 0,\n \" 1\": 0,\n \" 2\": 0,\n \" 3\": 0,\n \" 4\": 0,\n \" 5\": 0,\n \" 6\": 0,\n \" 7\": 0,\n \" 8\": 0,\n \" 9\": 0,\n \"##\": -1,\n \"#_\": 0,\n \"',\": 0,\n \"'.\": 0,\n \"'/\": 0,\n \"'J\": 0,\n \"'S\": 0,\n \"'_\": 0,\n \"'j\": 0,\n \"'s\": 0,\n \"(+\": 0,\n \"(-\": 0,\n \"(<\": 0,\n \"(f\": 0,\n \"({\": 0,\n \"(~\": 0,\n \")_\": 0,\n \"*,\": 0,\n \"*.\": 0,\n \"*/\": 0,\n \"*S\": 0,\n \"*_\": 0,\n \"*j\": 0,\n \"*s\": 0,\n \"+)\": 0,\n \"+,\": 0,\n \"+.\": 0,\n \"+/\": 0,\n \"+>\": 0,\n \"+?\": 0,\n \"+I\": 0,\n \"+S\": 0,\n \"+T\": 0,\n \"+Z\": 0,\n \"+]\": 0,\n \"+_\": 0,\n \"+`\": 0,\n \"+j\": 0,\n \"+s\": 0,\n \"+}\": 0,\n \",'\": 0,\n \",*\": 0,\n \",+\": 0,\n \",-\": 0,\n \",<\": 0,\n \",?\": 0,\n \",T\": 0,\n \",Y\": 0,\n \",Z\": 0,\n \",\\\"\": 0,\n \",\\\\\": 0,\n \",^\": 0,\n \",`\": 0,\n \",f\": 0,\n \",t\": 0,\n \",z\": 0,\n \",{\": 0,\n \",~\": 0,\n \"-)\": 0,\n \"-,\": 0,\n \"--\": 0,\n \"-.\": 0,\n \"-/\": 0,\n \"->\": 0,\n \"-?\": 0,\n \"-I\": 0,\n \"-S\": 0,\n \"-T\": 0,\n \"-Z\": 0,\n \"-]\": 0,\n \"-_\": 0,\n \"-`\": 0,\n \"-j\": 0,\n \"-s\": 0,\n \"-}\": 0,\n \".'\": 0,\n \".*\": 0,\n \".+\": 0,\n \".-\": 0,\n \".<\": 0,\n \".?\": 0,\n \".T\": 0,\n \".Y\": 0,\n \".Z\": 0,\n \".\\\"\": 0,\n \".\\\\\": 0,\n \".^\": 0,\n \".`\": 0,\n \".f\": 0,\n \".t\": 0,\n \".z\": 0,\n \".{\": 0,\n \".~\": 0,\n \"/,\": 0,\n \"/.\": 0,\n \"//\": 0,\n \"/J\": 0,\n \"/S\": 0,\n \"/_\": 0,\n \"/j\": 0,\n \"/s\": 0,\n \"0 \": 0,\n \"1 \": 0,\n \"1T\": 0,\n \"1Y\": 0,\n \"1Z\": 0,\n \"1f\": 0,\n \"1t\": 0,\n \"1z\": 0,\n \"2 \": 0,\n \"3 \": 0,\n \"4 \": 0,\n \"5 \": 0,\n \"6 \": 0,\n \"7 \": 0,\n \"8 \": 0,\n \"9 \": 0,\n \":?\": 0,\n \":T\": 0,\n \":Z\": 0,\n \":`\": 0,\n \";?\": 0,\n \";T\": 0,\n \";Z\": 0,\n \"<+\": 0,\n \"<-\": 0,\n \"<<\": 0,\n \"<f\": 0,\n \"<{\": 0,\n \"<~\": 0,\n \"==\": 0,\n \"=_\": 0,\n \">)\": 0,\n \">,\": 0,\n \">.\": 0,\n \">/\": 0,\n \">>\": 0,\n \">?\": 0,\n \">I\": 0,\n \">S\": 0,\n \">T\": 0,\n \">Z\": 0,\n \">]\": 0,\n \">_\": 0,\n \">`\": 0,\n \">j\": 0,\n \">s\": 0,\n \">}\": 0,\n \"?,\": 0,\n \"?.\": 0,\n \"?/\": 0,\n \"?S\": 0,\n \"?_\": 0,\n \"?j\": 0,\n \"?s\": 0,\n \"@_\": 0,\n \"C+\": 0,\n \"C-\": 0,\n \"C<\": 0,\n \"Cf\": 0,\n \"C{\": 0,\n \"C~\": 0,\n \"D_\": 0,\n \"E+\": 0,\n \"E-\": 0,\n \"E<\": 0,\n \"Ef\": 0,\n \"E{\": 0,\n \"E~\": 0,\n \"F&\": 0,\n \"F+\": 0,\n \"F,\": 0,\n \"F-\": 0,\n \"F.\": 0,\n \"F/\": 0,\n \"F:\": 0,\n \"F;\": 0,\n \"F<\": 0,\n \"FJ\": 0,\n \"FS\": 0,\n \"F_\": 0,\n \"Fa\": 0,\n \"Fe\": 0,\n \"Ff\": 0,\n \"Fg\": 0,\n \"Fj\": 0,\n \"Fq\": 0,\n \"Fs\": 0,\n \"F{\": 0,\n \"F~\": 0,\n \"I+\": 0,\n \"I-\": 0,\n \"I<\": 0,\n \"If\": 0,\n \"I{\": 0,\n \"I~\": 0,\n \"L'\": 0,\n \"L*\": 0,\n \"L+\": 0,\n \"L-\": 0,\n \"L4\": 0,\n \"L7\": 0,\n \"L<\": 0,\n \"L?\": 0,\n \"LT\": 0,\n \"LY\": 0,\n \"LZ\": 0,\n \"L\\\"\": 0,\n \"L\\\\\": 0,\n \"L^\": 0,\n \"L`\": 0,\n \"Lf\": 0,\n \"Lt\": 0,\n \"Lz\": 0,\n \"L{\": 0,\n \"L~\": 0,\n \"P,\": 0,\n \"P.\": 0,\n \"P/\": 0,\n \"PS\": 0,\n \"P_\": 0,\n \"Pj\": 0,\n \"Ps\": 0,\n \"S&\": 0,\n \"S+\": 0,\n \"S,\": 0,\n \"S-\": 0,\n \"S.\": 0,\n \"S/\": 0,\n \"S:\": 0,\n \"S;\": 0,\n \"S<\": 0,\n \"SJ\": 0,\n \"SS\": 0,\n \"S_\": 0,\n \"Sa\": 0,\n \"Se\": 0,\n \"Sf\": 0,\n \"Sg\": 0,\n \"Sj\": 0,\n \"Sq\": 0,\n \"Ss\": 0,\n \"S{\": 0,\n \"S~\": 0,\n \"T&\": 0,\n \"T+\": 0,\n \"T,\": 0,\n \"T-\": 0,\n \"T.\": 0,\n \"T/\": 0,\n \"T:\": 0,\n \"T;\": 0,\n \"T<\": 0,\n \"TJ\": 0,\n \"TS\": 0,\n \"T_\": 0,\n \"Ta\": 0,\n \"Te\": 0,\n \"Tf\": 0,\n \"Tg\": 0,\n \"Tj\": 0,\n \"Tq\": 0,\n \"Ts\": 0,\n \"T{\": 0,\n \"T~\": 0,\n \"V_\": 0,\n \"Y,\": 0,\n \"Y.\": 0,\n \"Y/\": 0,\n \"YS\": 0,\n \"Y_\": 0,\n \"Yj\": 0,\n \"Ys\": 0,\n \"Z'\": 0,\n \"Z*\": 0,\n \"Z+\": 0,\n \"Z-\": 0,\n \"Z4\": 0,\n \"Z7\": 0,\n \"Z<\": 0,\n \"Z?\": 0,\n \"ZT\": 0,\n \"ZY\": 0,\n \"ZZ\": 0,\n \"Z\\\"\": 0,\n \"Z\\\\\": 0,\n \"Z^\": 0,\n \"Z`\": 0,\n \"Zf\": 0,\n \"Zt\": 0,\n \"Zz\": 0,\n \"Z{\": 0,\n \"Z~\": 0,\n \"[+\": 0,\n \"[-\": 0,\n \"[<\": 0,\n \"[f\": 0,\n \"[{\": 0,\n \"[~\": 0,\n \"\\\",\": 0,\n \"\\\".\": 0,\n \"\\\"/\": 0,\n \"\\\"J\": 0,\n \"\\\"S\": 0,\n \"\\\"_\": 0,\n \"\\\"j\": 0,\n \"\\\"s\": 0,\n \"\\\\'\": 0,\n \"\\\\*\": 0,\n \"\\\\+\": 0,\n \"\\\\-\": 0,\n \"\\\\<\": 0,\n \"\\\\?\": 0,\n \"\\\\T\": 0,\n \"\\\\Y\": 0,\n \"\\\\Z\": 0,\n \"\\\\\\\"\": 0,\n \"\\\\\\\\\": 0,\n \"\\\\^\": 0,\n \"\\\\`\": 0,\n \"\\\\f\": 0,\n \"\\\\t\": 0,\n \"\\\\z\": 0,\n \"\\\\{\": 0,\n \"\\\\~\": 0,\n \"^,\": 0,\n \"^.\": 0,\n \"^/\": 0,\n \"^J\": 0,\n \"^S\": 0,\n \"^_\": 0,\n \"^j\": 0,\n \"^s\": 0,\n \"_#\": 0,\n \"_%\": 0,\n \"_'\": 0,\n \"_(\": 0,\n \"_*\": 0,\n \"_+\": 0,\n \"_-\": 0,\n \"_<\": 0,\n \"_=\": 0,\n \"_?\": 0,\n \"_@\": 0,\n \"_T\": 0,\n \"_V\": 0,\n \"_Y\": 0,\n \"_Z\": 0,\n \"_\\\"\": 0,\n \"_\\\\\": 0,\n \"_^\": 0,\n \"__\": 0,\n \"_`\": 0,\n \"_a\": 0,\n \"_e\": 0,\n \"_f\": 0,\n \"_t\": 0,\n \"_v\": 0,\n \"_z\": 0,\n \"_{\": 0,\n \"_~\": 0,\n \"`,\": 0,\n \"`.\": 0,\n \"`/\": 0,\n \"`J\": 0,\n \"`S\": 0,\n \"`_\": 0,\n \"`j\": 0,\n \"`s\": 0,\n \"f,\": 0,\n \"f.\": 0,\n \"f/\": 0,\n \"fS\": 0,\n \"f_\": 0,\n \"fj\": 0,\n \"fs\": 0,\n \"q#\": 0,\n \"q$\": 0,\n \"q%\": 0,\n \"q&\": 0,\n \"q'\": 0,\n \"q(\": 0,\n \"q*\": 0,\n \"q+\": 0,\n \"q-\": 0,\n \"q0\": 0,\n \"q1\": 0,\n \"q2\": 0,\n \"q3\": 0,\n \"q4\": 0,\n \"q5\": 0,\n \"q6\": 0,\n \"q7\": 0,\n \"q8\": 0,\n \"q9\": 0,\n \"q<\": 0,\n \"q=\": 0,\n \"q?\": 0,\n \"q@\": 0,\n \"qA\": 0,\n \"qB\": 0,\n \"qC\": 0,\n \"qD\": 0,\n \"qE\": 0,\n \"qF\": 0,\n \"qG\": 0,\n \"qH\": 0,\n \"qI\": 0,\n \"qJ\": 0,\n \"qK\": 0,\n \"qL\": 0,\n \"qM\": 0,\n \"qN\": 0,\n \"qO\": 0,\n \"qP\": 0,\n \"qQ\": 0,\n \"qR\": 0,\n \"qS\": 0,\n \"qT\": 0,\n \"qU\": 0,\n \"qV\": 0,\n \"qW\": 0,\n \"qX\": 0,\n \"qY\": 0,\n \"qZ\": 0,\n \"q[\": 0,\n \"q\\\"\": 0,\n \"q\\\\\": 0,\n \"q]\": 0,\n \"q^\": 0,\n \"q`\": 0,\n \"qa\": 0,\n \"qb\": 0,\n \"qc\": 0,\n \"qd\": 0,\n \"qe\": 0,\n \"qf\": 0,\n \"qh\": 0,\n \"qk\": 0,\n \"qm\": 0,\n \"qn\": 0,\n \"qo\": 0,\n \"qq\": 0,\n \"qr\": 0,\n \"qs\": 0,\n \"qt\": 0,\n \"qu\": 0,\n \"qv\": 0,\n \"qw\": 0,\n \"qx\": 0,\n \"qz\": 0,\n \"q{\": 0,\n \"q}\": 0,\n \"q~\": 0,\n \"r,\": 0,\n \"r.\": 0,\n \"r/\": 0,\n \"rS\": 0,\n \"r_\": 0,\n \"rj\": -1,\n \"rs\": 0,\n \"s,\": 0,\n \"s.\": 0,\n \"s/\": 0,\n \"sJ\": 0,\n \"sS\": 0,\n \"s_\": 0,\n \"sj\": 0,\n \"ss\": 0,\n \"z'\": 0,\n \"z*\": 0,\n \"z+\": 0,\n \"z-\": 0,\n \"z4\": 0,\n \"z7\": 0,\n \"z<\": 0,\n \"z?\": 0,\n \"zT\": 0,\n \"zY\": 0,\n \"zZ\": 0,\n \"z\\\"\": 0,\n \"z\\\\\": 0,\n \"z^\": 0,\n \"z`\": 0,\n \"zf\": 0,\n \"zt\": 0,\n \"zz\": 0,\n \"z{\": 0,\n \"z~\": 0,\n \"{+\": 0,\n \"{-\": 0,\n \"{<\": 0,\n \"{f\": 0,\n \"{{\": 0,\n \"{~\": 0,\n \"})\": 0,\n \"},\": 0,\n \"}.\": 0,\n \"}/\": 0,\n \"}>\": 0,\n \"}?\": 0,\n \"}I\": 0,\n \"}S\": 0,\n \"}T\": 0,\n \"}Z\": 0,\n \"}]\": 0,\n \"}_\": 0,\n \"}`\": 0,\n \"}j\": 0,\n \"}s\": 0,\n \"}}\": 0,\n \"~'\": 0,\n \"~?\": 0,\n \"~T\": 0,\n \"~Z\": 0,\n \"~\\\"\": 0,\n \"~\\\\\": 0,\n \"~^\": 0,\n \"~_\": 0,\n \"~`\": 0,\n \"~t\": 0,\n \"~z\": 0\n },\n \"defaultKerning\": 1,\n \"defaultWhitespaceKerning\": -1,\n \"endOfLineKerning\": 0,\n \"charWidth\": {\n \" \": 4,\n \"!\": 1,\n \"#\": 5,\n \"&\": 4,\n \"'\": 1,\n \"(\": 2,\n \")\": 2,\n \",\": 1,\n \".\": 1,\n \":\": 1,\n \";\": 1,\n \"@\": 5,\n \"M\": 5,\n \"W\": 5,\n \"[\": 2,\n \"\\n\": 0,\n \"]\": 2,\n \"`\": 2,\n \"i\": 1,\n \"l\": 1,\n \"m\": 5,\n \"q\": 4,\n \"w\": 5,\n \"|\": 1\n },\n \"defaultCharWidth\": 3\n}\n", null, "export const Layer = {\n Top: 0,\n UIA: 1,\n UIB: 2,\n UIC: 3,\n UID: 4,\n UIE: 5,\n UIF: 6,\n UIG: 7,\n A: 8,\n B: 9,\n C: 10,\n D: 11,\n E: 12,\n F: 13,\n Bottom: 14,\n Hidden: 15\n} as const\nexport type Layer = (typeof Layer)[keyof typeof Layer]\n\n/** negative is above. returns [top, bottom]; hidden is out of domain. */\nexport function layerOffset(layer: Layer, offset: number): Layer {\n return Math.max(Layer.Top, Math.min(Layer.Bottom, layer + offset)) as Layer\n}\n", "export type Box = XY & WH\nexport type WH = {w: number; h: number}\nexport type XY = {x: number; y: number}\nexport type XYZ = {x: number; y: number; z: number}\n\nexport type CardinalDir = 'W' | 'N' | 'E' | 'S'\nexport type CompassDir = CardinalDir | 'NE' | 'SE' | 'SW' | 'NW' | 'Origin'\n\nexport function boxEq(l: Readonly<Box>, r: Readonly<Box>): boolean {\n return xyEq(l, r) && whEq(l, r)\n}\n\nexport function boxHits(\n l: Readonly<Partial<XY> & WH>,\n r: Readonly<XY & Partial<WH>>\n): boolean {\n const rWH = {w: r.w ?? 1, h: r.h ?? 1} // point? an empty box has no w/h.\n if (!l.w || !l.h || !rWH.w || !rWH.h) return false // noncommutative.\n const lXY = {x: l.x ?? 0, y: l.y ?? 0}\n return (\n lXY.x < r.x + rWH.w &&\n lXY.x + l.w > r.x &&\n lXY.y < r.y + rWH.h &&\n lXY.y + l.h > r.y\n )\n}\n\nexport function whAssign(l: WH, r: Readonly<WH>): void {\n l.w = r.w\n l.h = r.h\n}\n\nexport function whEq(l: Readonly<WH>, r: Readonly<WH>): boolean {\n return l.w === r.w && l.h === r.h\n}\n\n/** l + r. */\nexport function xyAdd(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x + r.x, y: l.y + r.y}\n}\n\n/** l += r. */\nexport function xyAddTo(l: XY, r: Readonly<XY>): void {\n l.x += r.x\n l.y += r.y\n}\n\nexport function xyAssign(l: XY, r: Readonly<XY>): void {\n l.x = r.x\n l.y = r.y\n}\n\n/** nonnegative. */\nexport function xyDistance(from: Readonly<XY>, to: Readonly<XY>): number {\n return xyMagnitude(xySub(from, to))\n}\n\n/** l / r. */\nexport function xyDiv(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x / r.x, y: l.y / r.y}\n}\n\nexport function xyEq(l: Readonly<XY>, r: Readonly<XY>): boolean {\n return l.x === r.x && l.y === r.y\n}\n\n/** nonnegative. */\nexport function xyMagnitude(xy: Readonly<XY>): number {\n return Math.hypot(xy.x, xy.y)\n}\n\n/** the greater of each component. */\nexport function xyMax(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: Math.max(l.x, r.x), y: Math.max(l.y, r.y)}\n}\n\n/** the lesser of each component. */\nexport function xyMin(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: Math.min(l.x, r.x), y: Math.min(l.y, r.y)}\n}\n\n/** l - r. */\nexport function xySub(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x - r.x, y: l.y - r.y}\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport type {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {\n type CardinalDir,\n type CompassDir,\n type WH,\n whEq,\n type XY,\n xyEq\n} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport type NinePatchOpts<Tag extends TagFormat> = {\n margin?: {w?: number | undefined; h?: number | undefined} | undefined\n n: NinePatchDirOpts<Tag>\n origin: NinePatchDirOpts<Tag>\n border?: {[dir in Lowercase<CardinalDir>]?: number | undefined}\n wh?: {w?: number | undefined; h?: number | undefined} | undefined\n x?: number | undefined\n y?: number | undefined\n z?: Layer | undefined\n} & {\n [dir in 'w' | 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw']?:\n | NinePatchDirOpts<Tag>\n | undefined\n}\nexport type NinePatchDirOpts<Tag extends TagFormat> = {\n flip?: {x?: boolean; y?: boolean} | undefined\n tag: Tag\n stretch?: boolean | undefined\n}\n\nexport class NinePatchEnt<Tag extends TagFormat> implements Ent<Tag> {\n readonly #dir: {readonly [dir in Lowercase<CompassDir>]: Sprite<Tag>}\n readonly #margin: Readonly<WH>\n #invalid: boolean = true\n\n constructor(v: Void<Tag, string>, opts: Readonly<NinePatchOpts<Tag>>) {\n this.#dir = {\n w: v.sprites.alloc(),\n nw: v.sprites.alloc(),\n n: v.sprites.alloc(),\n ne: v.sprites.alloc(),\n e: v.sprites.alloc(),\n se: v.sprites.alloc(),\n s: v.sprites.alloc(),\n sw: v.sprites.alloc(),\n origin: v.sprites.alloc()\n }\n this.#dir.w.tag = opts.w?.tag ?? opts.e?.tag ?? opts.n.tag\n this.#dir.n.tag = opts.n.tag\n this.#dir.e.tag = opts.e?.tag ?? this.#dir.w.tag\n this.#dir.s.tag = opts.s?.tag ?? this.#dir.n.tag\n\n this.#dir.nw.tag = opts.nw?.tag ?? opts.se?.tag ?? opts.n.tag\n this.#dir.ne.tag =\n opts.ne?.tag ?? opts.sw?.tag ?? opts.nw?.tag ?? opts.n.tag\n this.#dir.se.tag = opts.se?.tag ?? this.#dir.nw.tag\n this.#dir.sw.tag = opts.sw?.tag ?? this.#dir.ne.tag\n\n this.#dir.origin.tag = opts.origin.tag\n\n this.#dir.w.z =\n this.#dir.nw.z =\n this.#dir.n.z =\n this.#dir.ne.z =\n this.#dir.e.z =\n this.#dir.se.z =\n this.#dir.s.z =\n this.#dir.sw.z =\n this.#dir.origin.z =\n opts.z ?? 0\n\n this.#dir.w.stretch = opts.w?.stretch ?? opts.e?.stretch ?? false\n this.#dir.n.stretch = opts.n.stretch ?? opts.s?.stretch ?? false\n this.#dir.e.stretch = opts.e?.stretch ?? this.#dir.w.stretch\n this.#dir.s.stretch = opts.s?.stretch ?? this.#dir.n.stretch\n\n this.#dir.nw.stretch = opts.nw?.stretch ?? opts.se?.stretch ?? false\n this.#dir.ne.stretch = opts.ne?.stretch ?? opts.sw?.stretch ?? false\n this.#dir.se.stretch = opts.se?.stretch ?? this.#dir.nw.stretch\n this.#dir.sw.stretch = opts.sw?.stretch ?? this.#dir.ne.stretch\n\n this.#dir.origin.stretch = opts.origin.stretch ?? false\n\n this.#dir.w.flipX = opts.w?.flip?.x ?? !opts.e?.flip?.x\n this.#dir.w.flipY = opts.w?.flip?.y ?? !!opts.e?.flip?.y\n this.#dir.n.flipX = opts.n.flip?.x ?? !!opts.s?.flip?.x\n this.#dir.n.flipY = opts.n.flip?.y ?? !opts.s?.flip?.y\n this.#dir.e.flipX = opts.e?.flip?.x ?? !this.#dir.w.flipX\n this.#dir.e.flipY = opts.e?.flip?.y ?? this.#dir.w.flipY\n this.#dir.s.flipX = opts.s?.flip?.x ?? this.#dir.n.flipX\n this.#dir.s.flipY = opts.s?.flip?.y ?? !this.#dir.n.flipY\n this.#dir.origin.flipX = !!opts.origin.flip?.x\n this.#dir.origin.flipY = !!opts.origin.flip?.y\n\n this.#dir.n.h = opts.border?.n ?? opts.border?.s ?? this.#dir.n.h\n this.#dir.w.w = opts.border?.w ?? opts.border?.e ?? this.#dir.n.h\n this.#dir.e.w = opts.border?.e ?? this.#dir.w.w\n this.#dir.s.h = opts.border?.s ?? this.#dir.n.h\n\n this.#dir.nw.w = this.#dir.w.w\n this.#dir.nw.h = this.#dir.n.h\n this.#dir.ne.w = this.#dir.e.w\n this.#dir.ne.h = this.#dir.n.h\n this.#dir.se.w = this.#dir.e.w\n this.#dir.se.h = this.#dir.s.h\n this.#dir.sw.w = this.#dir.w.w\n this.#dir.sw.h = this.#dir.s.h\n\n this.#margin = {w: opts.margin?.w ?? 0, h: opts.margin?.h ?? 0}\n\n const w =\n opts.wh?.w == null\n ? this.#dir.w.w + this.#dir.n.w + this.#dir.e.w\n : opts.wh.w\n this.#dir.n.w = w - 1 // force resize\n this.wh = {\n w,\n h:\n opts.wh?.h == null\n ? this.#dir.n.h + this.#dir.e.h + this.#dir.s.h\n : opts.wh.h\n }\n\n this.#dir.nw.x = (opts.x ?? 0) - 1 // force move.\n this.xy = {x: opts.x ?? 0, y: opts.y ?? 0}\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(\n this.#dir.w,\n this.#dir.nw,\n this.#dir.n,\n this.#dir.ne,\n this.#dir.e,\n this.#dir.se,\n this.#dir.s,\n this.#dir.sw,\n this.#dir.origin\n )\n }\n\n update(): boolean | undefined {\n if (!this.#invalid) return\n this.#invalid = false\n return true\n }\n\n get wh(): WH {\n return {\n w: this.#dir.w.w + this.#dir.n.w + this.#dir.e.w + this.#margin.w,\n h: this.#dir.n.h + this.#dir.w.h + this.#dir.s.h + this.#margin.h\n }\n }\n\n set wh(wh: Readonly<WH>) {\n if (whEq(wh, this.wh)) return\n\n this.#dir.w.h = wh.h - this.#dir.n.h - this.#dir.s.h - this.#margin.h\n this.#dir.n.w = wh.w - this.#dir.w.w - this.#dir.e.w - this.#margin.w\n this.#dir.s.w = this.#dir.n.w\n this.#dir.e.h = this.#dir.w.h\n\n this.#dir.origin.w = this.#dir.n.w\n this.#dir.origin.h = this.#dir.e.h\n\n this.#setXYRight()\n\n this.#invalid = true\n }\n\n get xy(): XY {\n return {\n x: this.#dir.nw.x - this.#margin.w / 2,\n y: this.#dir.nw.y - this.#margin.h / 2\n }\n }\n\n set xy(xy: Readonly<XY>) {\n if (xyEq(xy, this.xy)) return\n\n this.#dir.nw.x = xy.x + this.#margin.w / 2\n this.#dir.nw.y = xy.y + this.#margin.h / 2\n this.#dir.w.x = this.#dir.nw.x\n this.#dir.w.y = this.#dir.nw.y + this.#dir.nw.h\n this.#dir.n.x = this.#dir.nw.x + this.#dir.nw.w\n this.#dir.n.y = this.#dir.nw.y\n\n this.#dir.origin.x = this.#dir.n.x\n this.#dir.origin.y = this.#dir.nw.y + this.#dir.ne.h\n\n this.#setXYRight()\n\n this.#invalid = true\n }\n\n #setXYRight() {\n this.#dir.ne.x = this.#dir.n.x + this.#dir.n.w\n this.#dir.ne.y = this.#dir.nw.y\n this.#dir.e.x = this.#dir.ne.x\n this.#dir.e.y = this.#dir.nw.y + this.#dir.ne.h\n this.#dir.se.x = this.#dir.e.x\n this.#dir.se.y = this.#dir.e.y + this.#dir.e.h\n this.#dir.s.x = this.#dir.n.x\n this.#dir.s.y = this.#dir.se.y\n this.#dir.sw.x = this.#dir.nw.x\n this.#dir.sw.y = this.#dir.se.y\n }\n}\n", "import type {Font} from 'mem-font'\nimport type {TagFormat} from '../graphics/atlas.ts'\n\nexport function fontCharToTag(font: Readonly<Font>, char: string): TagFormat {\n let pt = char.codePointAt(0)\n if (pt == null || pt > 0xff) pt = 63 // ?\n return `${font.id}--${pt.toString(16).padStart(2, '0')}`\n}\n\n/** @arg r undefined means end of line. */\nexport function fontKerning(\n font: Readonly<Font>,\n l: string,\n r: string | undefined\n): number {\n if (r == null) return font.endOfLineKerning\n if (font.kerning[l + r] != null) return font.kerning[l + r]!\n if (/^\\s?$/.test(l) || /^\\s?$/.test(r)) return font.defaultWhitespaceKerning\n return font.defaultKerning\n}\n\nexport function fontCharWidth(font: Readonly<Font>, letter: string): number {\n return font.charWidth[letter] ?? font.defaultCharWidth\n}\n", "import type {Font} from 'mem-font'\nimport type {Box, WH, XY} from '../types/geo.ts'\nimport {fontCharWidth, fontKerning} from './font.ts'\n\nexport type TextLayout = {\n /** the length of this array matches the string length. */\n chars: (Box | undefined)[]\n /** the offset in pixels. */\n cursor: XY\n wh: WH\n}\n\nexport type TextLayoutOpts = {\n font: Font\n maxW?: number\n scale?: number\n start?: XY\n str: string\n}\n\nexport function layoutText(opts: Readonly<TextLayoutOpts>): TextLayout {\n const chars = []\n const scale = opts.scale ?? 1\n const start = opts.start ?? {x: 0, y: 0}\n const maxW = opts.maxW ?? Infinity\n let cursor = {x: start.x, y: start.y}\n let w = 0\n while (chars.length < opts.str.length) {\n const i = chars.length\n const char = opts.str[i]!\n let layout\n if (char === '\\n') layout = layoutNewline(opts.font, cursor, start.x, scale)\n else if (/^\\s*$/.test(char)) {\n layout = layoutSpace(\n opts.font,\n cursor,\n maxW,\n tracking(opts.font, char, opts.str[i + 1], scale),\n start.x,\n scale\n )\n } else {\n layout = layoutWord(opts.font, cursor, maxW, opts.str, i, start.x, scale)\n if (\n cursor.x > 0 &&\n layout.cursor.y === nextLine(opts.font, start.x, cursor.y, scale).y\n ) {\n const wordW = maxW - cursor.x + layout.cursor.x\n if (wordW <= maxW) {\n // word can fit on one line if cursor is reset to the start of line.\n cursor = nextLine(opts.font, start.x, cursor.y, scale)\n layout = layoutWord(\n opts.font,\n cursor,\n maxW,\n opts.str,\n i,\n start.x,\n scale\n )\n }\n }\n }\n chars.push(...layout.chars)\n cursor.x = layout.cursor.x\n cursor.y = layout.cursor.y\n w = Math.max(w, layout.cursor.x - start.x)\n }\n return {\n chars,\n cursor,\n wh: {w, h: nextLine(opts.font, start.x, cursor.y, scale).y - start.y}\n }\n}\n\n/** @internal */\nexport function layoutWord(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n maxW: number,\n word: string,\n index: number,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n const chars = []\n let {x, y} = cursor\n for (; ; index++) {\n const char = word[index]\n if (!char || /^\\s*$/.test(char)) break\n\n const span = tracking(font, char, word[index + 1], scale)\n if (x > startX && x + span > startX + maxW)\n ({x, y} = nextLine(font, startX, y, scale))\n\n // width is not span since, with kerning, that may exceed the actual\n // width of the character's sprite. eg, if w has the maximal character width\n // of five pixels and a one pixel kerning for a given pair of characters, it\n // will have a span of six pixels which is greater than the maximal five\n // pixel sprite that can be rendered.\n chars.push({x, y, w: fontCharWidth(font, char), h: font.cellHeight})\n x += span\n }\n return {chars, cursor: {x, y}}\n}\n\nfunction nextLine(\n font: Readonly<Font>,\n startX: number,\n curY: number,\n scale: number\n): XY {\n return {x: startX, y: curY + font.lineHeight * scale}\n}\n\nfunction layoutNewline(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n return {chars: [undefined], cursor: nextLine(font, startX, cursor.y, scale)}\n}\n\n/**\n * @arg span the distance in pixels from the start of the current character to\n * the start of the next including scale.\n */\nfunction layoutSpace(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n w: number,\n span: number,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n const nextCursor =\n cursor.x > 0 && cursor.x + span >= w\n ? nextLine(font, startX, cursor.y, scale)\n : {x: cursor.x + span, y: cursor.y}\n return {chars: [undefined], cursor: nextCursor}\n}\n\n/**\n * the distance in pixels from the start of lhs to the start of rhs including\n * scale.\n */\nfunction tracking(\n font: Readonly<Font>,\n l: string,\n r: string | undefined,\n scale: number\n): number {\n return scale * (fontCharWidth(font, l) + fontKerning(font, l, r))\n}\n", "import {memProp5x6} from 'mem-font'\nimport type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {fontCharToTag} from '../text/font.ts'\nimport {layoutText} from '../text/text-layout.ts'\nimport {type WH, type XY, xyEq} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport class TextEnt implements Ent<TagFormat> {\n #maxW: number = Infinity\n #layout: 'Rendered' | 'Updated' | 'Outdated' = 'Outdated'\n #z: Layer = Layer.UIA\n #scale: number = 1\n readonly #sprites: Sprite<TagFormat>[] = []\n #str: string = ''\n #wh: WH = {w: 0, h: 0}\n readonly #xy: XY = {x: 0, y: 0}\n\n free(v: Void<TagFormat, string>): void {\n v.sprites.free(...this.#sprites)\n }\n\n layout(v: Void<TagFormat, string>): boolean {\n if (this.#layout !== 'Outdated') return false\n let len = 0\n const layout = layoutText({\n font: memProp5x6,\n maxW: this.#maxW,\n scale: this.#scale,\n start: this.#xy,\n str: this.#str\n })\n this.#wh = {w: layout.wh.w, h: layout.wh.h}\n for (const [i, char] of layout.chars.entries()) {\n if (char == null) continue\n const sprite = (this.#sprites[len] ??= v.sprites.alloc())\n sprite.x = char.x\n sprite.y = char.y\n sprite.tag = fontCharToTag(memProp5x6, this.#str[i]!)\n sprite.stretch = true\n sprite.w *= this.#scale\n sprite.h *= this.#scale\n sprite.z = this.#z\n len++\n }\n while (this.#sprites.length > len) v.sprites.free(this.#sprites.pop()!)\n this.#layout = 'Updated'\n return true\n }\n\n get maxW(): number {\n return this.#maxW\n }\n\n set maxW(w: number) {\n if (w === this.#maxW) return\n this.#maxW = w\n this.#layout = 'Outdated'\n }\n\n get scale() {\n return this.#scale\n }\n\n set scale(scale: number) {\n if (scale === this.#scale) return\n this.#scale = scale\n this.#layout = 'Outdated'\n }\n\n get text(): string {\n return this.#str\n }\n\n set text(str: string) {\n if (str === this.#str) return\n this.#str = str\n this.#layout = 'Outdated'\n }\n\n update(v: Void<TagFormat, string>): boolean | undefined {\n if (this.#layout === 'Rendered') return\n if (this.#layout === 'Outdated') this.layout(v)\n this.#layout = 'Rendered'\n return true\n }\n\n get scaledLeading(): number {\n return memProp5x6.leading * this.#scale\n }\n\n get wh(): Readonly<WH> {\n return this.#wh\n }\n\n get xy(): Readonly<XY> {\n return this.#xy\n }\n\n set xy(xy: Readonly<XY>) {\n if (xyEq(xy, this.#xy)) return\n this.#xy.x = xy.x\n this.#xy.y = xy.y\n this.#layout = 'Outdated'\n }\n\n get z(): Layer {\n return this.#z\n }\n\n set z(layer: Layer) {\n if (layer === this.#z) return\n this.#z = layer\n this.#layout = 'Outdated'\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer, layerOffset} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {type XY, xyEq} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\nimport {NinePatchEnt, type NinePatchOpts} from './nine-patch-ent.ts'\nimport {TextEnt} from './text-ent.ts'\n\nexport type ButtonOpts<Tag extends TagFormat> = {\n button: Omit<NinePatchOpts<Tag>, 'x' | 'y' | 'wh'>\n pressed: {tag: Tag; z?: Layer | undefined}\n selected: {tag: Tag; z?: Layer | undefined}\n toggle?: boolean | undefined\n text?:\n | {\n text?: string | undefined\n scale?: number | undefined\n z?: Layer | undefined\n }\n | undefined\n w?: number | undefined\n h?: number | undefined\n x?: number | undefined\n y?: number | undefined\n}\n\nexport class ButtonEnt<Tag extends TagFormat, Button extends string>\n implements Ent<Tag>\n{\n readonly #button: NinePatchEnt<Tag>\n #invalid: boolean = true\n readonly #pressed: {sprite: Sprite<Tag>; z: Layer}\n readonly #selected: {sprite: Sprite<Tag>; z: Layer}\n #started: boolean = false\n readonly #toggle: boolean = false\n readonly #text: TextEnt = new TextEnt()\n readonly #xy: XY = {x: 0, y: 0}\n\n constructor(v: Void<Tag, string>, opts: Readonly<ButtonOpts<Tag>>) {\n const buttonZ = opts.button.z ?? Layer.UID\n this.#button = new NinePatchEnt(v, {\n ...opts.button,\n x: opts.x,\n y: opts.y,\n z: buttonZ,\n wh: {w: opts.w, h: opts.h}\n })\n this.#pressed = {\n sprite: v.sprites.alloc(),\n z: opts.pressed.z ?? layerOffset(buttonZ, 2)\n }\n this.#selected = {\n sprite: v.sprites.alloc(),\n z: opts.selected.z ?? layerOffset(this.#pressed.z, -1)\n }\n\n this.#pressed.sprite.tag = opts.pressed.tag\n this.#pressed.sprite.x = opts.x ?? 0\n this.#pressed.sprite.y = opts.y ?? 0\n this.#pressed.sprite.w = opts.w ?? this.#button.wh.w\n this.#pressed.sprite.h = opts.h ?? this.#button.wh.h\n this.#pressed.sprite.z = Layer.Hidden\n\n this.#selected.sprite.tag = opts.selected.tag\n this.#selected.sprite.x = opts.x ?? 0\n this.#selected.sprite.y = opts.y ?? 0\n this.#selected.sprite.w = opts.w ?? this.#button.wh.w\n this.#selected.sprite.h = opts.h ?? this.#button.wh.h\n this.#selected.sprite.z = Layer.Hidden\n\n this.#text.text = opts.text?.text ?? ''\n this.#text.scale = opts.text?.scale ?? 1\n this.#text.layout(v)\n this.#moveText(v)\n this.#text.maxW = opts.w ?? this.#button.wh.w\n this.#text.z = opts.text?.z ?? layerOffset(buttonZ, -1)\n\n this.#toggle = opts.toggle ?? false\n }\n\n get selected(): boolean {\n return this.#selected.z !== Layer.Hidden\n }\n\n free(v: Void<Tag, string>): void {\n this.#button.free(v)\n this.#text.free(v)\n v.sprites.free(this.#selected.sprite, this.#pressed.sprite)\n }\n\n get on(): boolean {\n return this.#pressed.sprite.z !== Layer.Hidden\n }\n\n set on(on: boolean) {\n this.#pressed.sprite.z = on ? this.#pressed.z : Layer.Hidden\n }\n\n // to-do: offStart() for pointer up listen? would need a boundary check too.\n get onStart(): boolean {\n return this.on && this.#started\n }\n\n set text(str: string) {\n this.#text.text = str\n }\n\n update(v: Void<Tag, 'A' | 'Click' | Button>): boolean | undefined {\n let invalid = this.#invalid\n if (this.#button.update()) invalid = true\n if (this.#text.update(v)) invalid = true\n\n const hitsCursor =\n !v.input.handled && !!v.zoo.cursor?.hits(v, this.#selected.sprite, 'UI')\n const clickStarted =\n (hitsCursor && v.input.isOnStart('Click')) ||\n (v.zoo.cursor?.keyboard && v.input.isOnStart('A'))\n\n const on = clickStarted\n ? this.#toggle\n ? !this.on\n : true\n : this.#toggle\n ? this.on\n : v.input.isOn('Click') ||\n (!!v.zoo.cursor?.keyboard && v.input.isOn('A'))\n this.#started = this.on !== on\n if (this.#started) {\n this.on = on\n invalid = true\n }\n\n if (\n hitsCursor &&\n (v.input.point?.click || v.input.point?.type === 'Mouse')\n ) {\n invalid ||= this.#selected.sprite.z !== this.#selected.z\n this.#selected.sprite.z = this.#selected.z\n } else {\n invalid ||= this.#selected.sprite.z !== Layer.Hidden\n this.#selected.sprite.z = Layer.Hidden\n }\n\n v.input.handled ||= hitsCursor\n this.#invalid = false\n return invalid\n }\n\n setXY(v: Void<Tag, string>, xy: Readonly<XY>): void {\n if (xyEq(xy, this.#xy)) return\n this.#xy.x = xy.x\n this.#xy.y = xy.y\n this.#button.xy = xy\n this.#moveText(v)\n this.#pressed.sprite.xy = xy\n this.#selected.sprite.xy = xy\n this.#invalid = true\n }\n\n #moveText(v: Void<Tag, string>): void {\n this.#text.layout(v)\n this.#text.xy = {\n x: this.#button.xy.x + this.#button.wh.w / 2 - this.#text.wh.w / 2,\n y:\n this.#button.xy.y +\n this.#button.wh.h / 2 -\n (this.#text.wh.h - this.#text.scaledLeading) / 2\n }\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {type Box, boxHits, type WH, type XY} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\n/**\n * update this ent first. always prefer testing against cursor, not input, in\n * other ents. the cursor may be moved by keyboard and has a hitbox.\n */\nexport class CursorEnt<out Tag extends TagFormat> implements Ent<Tag> {\n keyboard: boolean = false\n readonly #sprite: Sprite<Tag>\n #pick: Tag\n #point: Tag\n\n constructor(v: Void<Tag, string>, point: Tag, pick?: Tag | undefined) {\n this.#point = point\n this.#pick = pick ?? this.#point\n this.#sprite = v.sprites.alloc()\n this.#sprite.tag = point\n this.#sprite.z = Layer.Hidden\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(this.#sprite)\n }\n\n hitbox(v: Readonly<Void<Tag, string>>, coords: 'Level' | 'UI'): Box {\n const lvl = coords === 'Level'\n const hitbox = this.#sprite.hitbox\n if (!hitbox) throw Error('cursor has no hitbox')\n return {\n x: (lvl ? v.cam.x : 0) + hitbox.x,\n y: (lvl ? v.cam.y : 0) + hitbox.y,\n w: hitbox.w,\n h: hitbox.h\n }\n }\n\n hits(\n v: Readonly<Void<Tag, string>>,\n box: Readonly<XY & Partial<WH>>,\n coords: 'Level' | 'UI'\n ): boolean {\n return this.visible && boxHits(this.hitbox(v, coords), box)\n }\n\n update(v: Void<Tag, 'L' | 'R' | 'U' | 'D'>): boolean | undefined {\n if (v.input.point?.invalid) {\n this.#sprite.tag = v.input.point.click ? this.#pick : this.#point\n this.#sprite.xy = v.input.point.local\n this.#sprite.z =\n v.input.point?.type === 'Mouse' ? Layer.Top : Layer.Hidden\n return true\n }\n\n if (this.keyboard && v.input.isAnyOn('L', 'R', 'U', 'D')) {\n const epsilon = 1\n if (v.input.isOn('L')) this.#sprite.x -= epsilon\n if (v.input.isOn('R')) this.#sprite.x += epsilon\n if (v.input.isOn('U')) this.#sprite.y -= epsilon\n if (v.input.isOn('D')) this.#sprite.y += epsilon\n this.#sprite.z = Layer.Top\n\n return true\n }\n }\n\n get visible(): boolean {\n return this.#sprite.z !== Layer.Hidden\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport type {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {\n type CompassDir,\n type WH,\n whAssign,\n whEq,\n type XY,\n xyAssign,\n xyEq\n} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport class FollowCamEnt<Tag extends TagFormat> implements Ent<Tag> {\n #fill: 'X' | 'Y' | 'XY' | undefined\n #invalid: boolean = true\n readonly #margin: WH = {w: 0, h: 0}\n readonly #modulo: XY = {x: 0, y: 0}\n #pivot: CompassDir\n readonly #sprite: Sprite<Tag>\n\n constructor(v: Void<Tag, string>, tag: Tag, pivot: CompassDir) {\n this.#sprite = v.sprites.alloc()\n this.#sprite.tag = tag\n this.#pivot = pivot\n }\n\n get fill(): 'X' | 'Y' | 'XY' | undefined {\n return this.#fill\n }\n\n set fill(fill: 'X' | 'Y' | 'XY' | undefined) {\n if (this.#fill === fill) return\n this.#fill = fill\n this.#invalid = true\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(this.#sprite)\n }\n\n get h(): number {\n return this.#sprite.h\n }\n\n set h(h: number) {\n if (this.#sprite.h === h) return\n this.#sprite.h = h\n this.#invalid = true\n }\n\n get margin(): Readonly<WH> {\n return this.#margin\n }\n\n set margin(margin: Readonly<WH>) {\n if (whEq(margin, this.#margin)) return\n whAssign(this.#margin, margin)\n this.#invalid = true\n }\n\n get modulo(): Readonly<XY> {\n return this.#modulo\n }\n\n set modulo(modulo: Readonly<XY>) {\n if (xyEq(modulo, this.#modulo)) return\n xyAssign(this.#modulo, modulo)\n this.#invalid = true\n }\n\n get pivot(): CompassDir {\n return this.#pivot\n }\n\n set pivot(pivot: CompassDir) {\n if (this.#pivot === pivot) return\n this.#pivot = pivot\n this.#invalid = true\n }\n\n update(v: Void<Tag, string>): boolean | undefined {\n if (!this.#invalid && !v.cam.invalid) return\n const follow = v.cam.follow(\n {w: this.#sprite.w, h: this.#sprite.h},\n this.#sprite.z,\n this.#pivot,\n {fill: this.#fill, modulo: this.#modulo, margin: this.#margin}\n )\n this.#sprite.x = follow.x\n this.#sprite.y = follow.y\n this.#invalid = false\n return true\n }\n\n get w(): number {\n return this.#sprite.w\n }\n\n set w(w: number) {\n if (this.#sprite.w === w) return\n this.#sprite.w = w\n this.#invalid = true\n }\n\n get z(): Layer {\n return this.#sprite.z\n }\n\n set z(z: Layer) {\n this.#sprite.z = z\n }\n}\n", "/**\n * proxy for debug CSV query param with case-insensitive keys. when a key\n * exists, the value is as specified or `'true'` if no value. most void values\n * default to `'true'` when the `debug` param is empty or `'void'` is set (eg,\n * `localhost:1234?debug` or `localhost:1234?debug=void,foo=bar`). all values\n * default to true when `'all'` is set. extend interface for additional types.\n * doesn't handle multiple values like `localhost:1234?debug=a=1,b=2&debug=b=3`.\n */\nexport interface Debug {\n cam?: string\n input?: string\n /** debug render invalidations. */\n invalid?: string\n mem?: string\n render?: 'always' | string\n}\n\nexport const debug: Readonly<Debug> | undefined = Debug(\n globalThis.location?.href\n)\n\n/** @internal */\nexport function Debug(url: string | undefined): Debug | undefined {\n if (!url) return\n const csv = [...new URL(url).searchParams].find(\n ([k]) => k.toLowerCase() === 'debug'\n )?.[1]\n if (csv == null) return\n const map = Object.fromEntries(\n csv\n .split(',') // split KV pairs.\n .filter(Boolean) // drop empties.\n .map(kv => kv.split('=')) // split each pair.\n )\n\n const target: {[k: string]: string} = {}\n for (const k in map) target[k.toLowerCase()] = map[k] || 'true'\n\n const voidKeyset: {[_ in keyof Omit<Debug, 'invalid'>]-?: undefined} = {\n cam: undefined,\n input: undefined,\n mem: undefined,\n render: undefined\n }\n\n return new Proxy<{[k: string]: string}>(target, {\n get(target, k): string | undefined {\n if (typeof k !== 'string') return target[k as unknown as string]\n k = k.toLowerCase()\n if (target[k]) return target[k]\n if (!csv || 'all' in map || (k in voidKeyset && 'void' in map))\n return 'true'\n }\n })\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {debug} from '../utils/debug.ts'\nimport type {Void} from '../void.ts'\nimport {CursorEnt} from './cursor-ent.ts'\nimport type {Ent} from './ent.ts'\n\n/**\n * ents are updated in insertion order. composed ents are updated by their\n * owning ents.\n */\nexport class Zoo<out Tag extends TagFormat> {\n #cursor: CursorEnt<Tag> | undefined\n readonly #ents: Set<Ent<Tag>> = new Set()\n #invalid: boolean = false\n\n add(...ents: readonly Ent<Tag>[]): void {\n for (const ent of ents) {\n this.#ents.add(ent)\n if (ent instanceof CursorEnt) this.#cursor = ent\n }\n }\n\n clear(): void {\n this.#cursor = undefined\n this.#ents.clear()\n }\n\n get cursor(): CursorEnt<Tag> | undefined {\n return this.#cursor\n }\n\n get invalid(): boolean {\n return this.#invalid\n }\n\n remove(...ents: readonly Readonly<Ent<Tag>>[]): void {\n for (const ent of ents) {\n this.#ents.delete(ent)\n if (ent === this.#cursor) this.#cursor = undefined\n }\n }\n\n update(v: Void<Tag, string>): void {\n this.#invalid = false\n for (const ent of this.#ents)\n if (ent.update?.(v)) {\n if (!this.#invalid && debug?.invalid)\n console.debug('ent update invalid', ent)\n this.#invalid = true\n }\n }\n}\n", "import {type Anim, type Atlas, type AtlasJSON, animCels} from './atlas.ts'\n\nexport function parseAtlas(json: Readonly<AtlasJSON>): Atlas {\n return {\n anim: json.anim,\n celXYWH: parseCelXYWH(json),\n tags: Object.keys(json.anim)\n }\n}\n\nfunction parseCelXYWH(json: Readonly<AtlasJSON>): number[] {\n const cels = []\n let i = 0\n for (const anim of Object.values(json.anim)) {\n cels.push(...parseXYWH(anim, json.celXY, i))\n i += anim.cels * 2\n }\n return cels\n}\n\n/** @internal */\nexport function parseXYWH(\n anim: Readonly<Anim>,\n celXY: readonly number[],\n i: number\n): number[] {\n const xywh = []\n for (let ii = 0; ii < animCels; ii++) {\n const iii = i + 2 * (ii % anim.cels)\n xywh.push(celXY[iii]!, celXY[iii + 1]!, anim.w, anim.h)\n }\n return xywh\n}\n", "import {\n type Box,\n boxHits,\n type CompassDir,\n type WH,\n type XY\n} from '../types/geo.ts'\nimport {debug} from '../utils/debug.ts'\nimport {Layer} from './layer.ts'\n\nexport type LevelClientLocalXY = {\n /** position relative canvas top-left (in DPI scale). */\n client: XY\n /**\n * position relative canvas top-left in level scale (like level xy but no cam\n * offset) within cam.\n */\n local: XY\n /** level x-coord within cam. */\n x: number\n /** level y-coord within cam. */\n y: number\n}\n\ntype Canvas = {\n width: number\n height: number\n style: {width: string; height: string}\n parentElement: {clientWidth: number; clientHeight: number} | null\n}\n\n/** given a min WH and scale, size the camera to the max WH. */\nexport class Cam {\n #devicePixelRatio: number = 0\n #h: number = 1\n #invalid: boolean = true\n #minScale: number = 1\n readonly #minWH: WH = {w: Infinity, h: Infinity}\n #mode: 'Int' | 'Fraction' = 'Int'\n #scale: number = 1\n #w: number = 1\n readonly #whClient: WH = {w: 1, h: 1}\n #x: number = 0\n #y: number = 0\n #zoomOut: number = 0\n\n center(xy: Readonly<XY>): void {\n this.x = Math.floor(xy.x - this.w / 2)\n this.y = Math.floor(xy.y - this.h / 2)\n }\n\n /** position in fractional level coordinates. */\n clientToXY(client: Readonly<XY>): XY {\n const local = this.clientToXYLocal(client)\n return {x: this.#x + local.x, y: this.#y + local.y}\n }\n\n /**\n * position relative canvas top-left in level scale (like level xy but no cam\n * offset). often used for UI that is fixed within the cam.\n */\n clientToXYLocal(client: Readonly<XY>): XY {\n return {\n x: (client.x / this.#whClient.w) * this.#w,\n y: (client.y / this.#whClient.h) * this.#h\n }\n }\n\n follow(\n wh: Readonly<WH>,\n z: Layer,\n pivot: CompassDir,\n opts?: {\n readonly fill?: 'X' | 'Y' | 'XY' | undefined\n readonly margin?: Partial<Readonly<WH>> | undefined\n readonly modulo?: Partial<Readonly<XY>> | undefined\n }\n ): Box {\n const marginW = opts?.margin?.w ?? 0\n let x = z > Layer.UIG ? Math.trunc(this.x) : 0\n switch (pivot) {\n case 'SW':\n case 'W':\n case 'NW':\n x += marginW\n break\n case 'SE':\n case 'E':\n case 'NE':\n x += this.w - (wh.w + marginW)\n break\n case 'N':\n case 'S':\n case 'Origin':\n x += Math.trunc(this.w / 2) - Math.trunc(wh.w / 2)\n break\n }\n x -= x % ((opts?.modulo?.x ?? x) || 1)\n\n const marginH = opts?.margin?.h ?? 0\n let y = z > Layer.UIG ? Math.trunc(this.y) : 0\n switch (pivot) {\n case 'N':\n case 'NE':\n case 'NW':\n y += marginH\n break\n case 'SE':\n case 'S':\n case 'SW':\n y += this.h - (wh.h + marginH)\n break\n case 'E':\n case 'W':\n case 'Origin':\n y += Math.trunc(this.h / 2) - Math.trunc(wh.h / 2)\n break\n }\n y -= y % ((opts?.modulo?.y ?? y) || 1)\n\n const w =\n opts?.fill === 'X' || opts?.fill === 'XY' ? this.w - 2 * marginW : wh.w\n const h =\n opts?.fill === 'Y' || opts?.fill === 'XY' ? this.h - 2 * marginH : wh.h\n\n return {x, y, w, h}\n }\n\n /** positive int in level px. */\n get h(): number {\n return this.#h\n }\n\n isVisible(box: Readonly<XY & Partial<WH>>): boolean {\n return boxHits(this, box)\n }\n\n /** true if cam moved or resized since last update. */\n get invalid(): boolean {\n return this.#invalid\n }\n\n /** positive int or fraction depending on mode. */\n get minScale(): number {\n return this.#minScale\n }\n\n set minScale(scale: number) {\n if (this.#scale === scale) return\n this.#scale = scale\n this.#invalidateWH()\n }\n\n /**\n * positive int or infinite min dimensions. set to\n * `{w: Infinity, h: Infinity}` to always use min scale.\n */\n get minWH(): Readonly<WH> {\n return this.#minWH\n }\n\n set minWH(wh: Readonly<WH>) {\n if (this.#minWH.w === wh.w && this.#minWH.h === wh.h) return\n this.#minWH.w = wh.w\n this.#minWH.h = wh.h\n this.#invalidateWH()\n }\n\n get mode(): 'Int' | 'Fraction' {\n return this.#mode\n }\n\n set mode(mode: 'Int' | 'Fraction') {\n if (this.#mode === mode) return\n this.#mode = mode\n this.#invalidateWH()\n }\n\n get portrait(): boolean {\n return this.h > this.w\n }\n\n postupdate(): void {\n this.#invalid = false\n }\n\n /** positive int or fraction depending on mode. */\n get scale(): number {\n return this.#scale\n }\n\n toString(): string {\n return `Cam{(${this.x} ${this.y}) ${this.w}\u00D7${this.h}}`\n }\n\n /**\n * call after input processing but before ent processing. ents that move the\n * camera should be called immediately after update so that the invalid state\n * can be considered.\n */\n update(canvas: Canvas): void {\n if (!canvas.parentElement) throw Error('canvas has no parent')\n const {clientWidth, clientHeight} = canvas.parentElement\n\n this.#invalid ||=\n this.#whClient.w !== clientWidth ||\n this.#whClient.h !== clientHeight ||\n // doesn't seem like this should be necessary but it is when moving across\n // monitors.\n this.#devicePixelRatio !== devicePixelRatio\n if (!this.#invalid) return\n this.#devicePixelRatio = devicePixelRatio\n this.#whClient.w = clientWidth\n this.#whClient.h = clientHeight\n this.#invalidateWH()\n\n canvas.width = this.#w\n canvas.height = this.#h\n // ~parentW / parentH.\n canvas.style.width = `${(this.#w * this.#scale) / devicePixelRatio}px`\n canvas.style.height = `${(this.#h * this.#scale) / devicePixelRatio}px`\n }\n\n /** positive int in level px. */\n get w(): number {\n return this.#w\n }\n\n /**\n * positive int dimensions in client px of canvas (often\n * `canvas.parentElement.clientWidth/Height` since the canvas is resized)\n * which is assumed to be max WH.\n */\n get whClient(): Readonly<WH> {\n return this.#whClient\n }\n\n /** fractional. */\n get x(): number {\n return this.#x\n }\n\n set x(x: number) {\n this.#invalid ||= this.x !== x\n this.#x = x\n }\n\n /** fractional. */\n get y(): number {\n return this.#y\n }\n\n set y(y: number) {\n this.#invalid ||= this.y !== y\n this.#y = y\n }\n\n /** nonnegative int or fraction depending on mode. */\n get zoomOut(): number {\n return this.#zoomOut\n }\n\n set zoomOut(out: number) {\n out = Math.max(0, out)\n if (this.#zoomOut === out) return\n this.#zoomOut = out\n this.#invalidateWH()\n }\n\n #invalidateWH(): void {\n if (!this.#invalid && debug?.invalid) console.debug('cam invalid')\n this.#invalid = true\n\n const phy = {\n w: this.#whClient.w * devicePixelRatio,\n h: this.#whClient.h * devicePixelRatio\n }\n\n const scale = Math.max(\n this.#minScale,\n Math.min(phy.w / this.#minWH.w, phy.h / this.#minWH.h) -\n (this.#mode === 'Int' ? Math.trunc(this.#zoomOut) : this.#zoomOut)\n )\n this.#scale = this.#mode === 'Int' ? Math.trunc(scale) : scale\n\n this.#w = Math.ceil(phy.w / this.#scale)\n this.#h = Math.ceil(phy.h / this.#scale)\n }\n}\n", "// to-do: port tests.\nexport function clamp(val: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, val))\n}\n\nexport function closeTo(lhs: number, rhs: number, tolerance: number): boolean {\n return Math.abs(lhs - rhs) <= tolerance\n}\n\n// to-do: port tests.\n/** ratio is [0, 1] to return [start, end]. */\nexport function lerp(start: number, end: number, ratio: number): number {\n return start + (end - start) * ratio\n}\n\n// to-do: test.\n/** returns positive modulo. */\nexport function mod(dividend: number, divisor: number): number {\n return ((dividend % divisor) + divisor) % divisor\n}\n", "import {\n type Anim,\n type Atlas,\n animCels,\n celMillis,\n type TagFormat\n} from '../graphics/atlas.ts'\nimport type {Block} from '../mem/pool.ts'\nimport {type Box, boxHits, type WH, type XY} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {mod} from '../utils/math.ts'\nimport type {Layer} from './layer.ts'\n\nexport const drawableBytes: number = 12\n/** granularity (0.015625) of `Drawable` coords. */\nexport const drawableEpsilon: number = 1 / 64\nexport const drawableMaxWH: WH = {w: 4095, h: 4095}\n\n/**\n * everything not requiring an atlas. the box is the drawn region. assume little\n * endian.\n *\n * 0 xxxx xxxx x [-131072, 131071.984375] (1/64th fixed-point). 1b sign, 17b\n * 1 xxxx xxxx int, 6b fraction.\n * 2 xxxx xxxx\n * 3 yyyy yyyy y.\n * 4 yyyy yyyy\n * 5 yyyy yyyy\n * 6 sxyz llll stretch, flip x, flip y, zend, z layer (4b).\n * 7 wwww wwww width [0, 4095]. zero means discard.\n * 8 hhhh wwww height. zero means discard.\n * 9 hhhh hhhh\n * a iiic cccc animation ID [0, 2047], animation cel [0, 31].\n * b iiii iiii\n *\n * animations default to looping without CPU interaction.\n * @internal\n */\nexport abstract class Drawable implements Block, Box {\n i: number\n readonly #pool: {readonly view: DataView<ArrayBuffer>}\n\n constructor(pool: {readonly view: DataView<ArrayBuffer>}, i: number) {\n this.#pool = pool\n this.i = i\n }\n\n above(draw: Readonly<Drawable>): boolean {\n const compare =\n this.z === draw.z\n ? (draw.zend ? draw.y + draw.h : draw.y) -\n (this.zend ? this.y + this.h : this.y)\n : this.z - draw.z\n return compare < 0\n }\n\n get cel(): number {\n const iiic_cccc = this.#pool.view.getUint8(this.i + 10)\n return iiic_cccc & 0x1f\n }\n\n /**\n * [0, 31]. rendered cel offset. call reset() to play animation from start.\n */\n set cel(cel: number) {\n const iiic_cccc = this.#pool.view.getUint8(this.i + 10)\n this.#pool.view.setUint8(this.i + 10, (iiic_cccc & ~0x1f) | (cel & 0x1f))\n }\n\n /** test if render area overlaps box or sprite render area. */\n clips(box: Readonly<XY & Partial<WH>>): boolean {\n return boxHits(this, box)\n }\n\n get flipX(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x40)\n }\n\n set flipX(flip: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x40) | (-flip & 0x40))\n }\n\n get flipY(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x20)\n }\n\n set flipY(flip: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x20) | (-flip & 0x20))\n }\n\n get h(): number {\n const h12_wwww = this.#pool.view.getUint16(this.i + 8, true)\n return h12_wwww >>> 4\n }\n\n /** [0, 4095]. */\n set h(h: number) {\n const h12_wwww = this.#pool.view.getUint16(this.i + 8, true)\n this.#pool.view.setUint16(\n this.i + 8,\n (h12_wwww & ~(0xfff << 4)) | ((h & 0xfff) << 4),\n true\n )\n }\n\n get id(): number {\n const i11_c5 = this.#pool.view.getUint16(this.i + 10, true)\n return (i11_c5 >>> 5) & 0x7ff\n }\n\n /** [0, 2047]. */\n set id(id: number) {\n const i11_c5 = this.#pool.view.getUint16(this.i + 10, true)\n this.#pool.view.setUint16(\n this.i + 10,\n (i11_c5 & ~(0x7ff << 5)) | ((id & 0x7ff) << 5),\n true\n )\n }\n\n get stretch(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x80)\n }\n\n /** wrap texture (default) or stretch to width and height. */\n set stretch(stretch: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(\n this.i + 6,\n (sxyz_llll & ~0x80) | (-stretch & 0x80)\n )\n }\n\n get w(): number {\n const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true)\n return hhhh_w12 & 0xfff\n }\n\n /** [0, 4095]. */\n set w(w: number) {\n const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true)\n this.#pool.view.setUint16(\n this.i + 7,\n (hhhh_w12 & ~0xfff) | (w & 0xfff),\n true\n )\n }\n\n get x(): number {\n const y8_x24 = this.#pool.view.getUint32(this.i + 0, true)\n return ((y8_x24 << 8) >> 8) / 64 // signed shift.\n }\n\n /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */\n set x(x: number) {\n const y8_x24 = this.#pool.view.getUint32(this.i + 0, true)\n this.#pool.view.setUint32(\n this.i + 0,\n (y8_x24 & ~0xff_ffff) | ((x * 64) & 0xff_ffff),\n true\n )\n }\n\n get xy(): XY {\n return {x: this.x, y: this.y}\n }\n\n set xy(xy: Readonly<XY>) {\n this.x = xy.x\n this.y = xy.y\n }\n\n get y(): number {\n const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true)\n return ((sxyz_llll_y24 << 8) >> 8) / 64 // signed shift.\n }\n\n /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */\n set y(y: number) {\n const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true)\n this.#pool.view.setUint32(\n this.i + 3,\n (sxyz_llll_y24 & ~0xff_ffff) | ((y * 64) & 0xff_ffff),\n true\n )\n }\n\n get z(): Layer {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return (sxyz_llll & 0xf) as Layer\n }\n\n /** layer [0 (closest), 14 (furthest)]; 15 is hidden. */\n set z(z: Layer) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0xf) | (z & 0xf))\n }\n\n get zend(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x10)\n }\n\n /** z-order by top (default) or bottom of box. */\n set zend(end: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x10) | (-end & 0x10))\n }\n}\n\n// to-do: can I declaration merge or namespace merge away from the tag type?\nexport class Sprite<out Tag extends TagFormat> extends Drawable {\n readonly #atlas: Readonly<Atlas>\n #hitbox: Box | undefined\n #hurtbox: Box | undefined\n readonly #looper: {readonly age: Millis}\n\n constructor(\n pool: {readonly view: DataView<ArrayBuffer>},\n i: number,\n atlas: Readonly<Atlas>,\n looper: {readonly age: Millis}\n ) {\n super(pool, i)\n this.#atlas = atlas\n this.#looper = looper\n }\n\n get anim(): Anim {\n return this.#atlas.anim[this.tag]!\n }\n\n override get flipX(): boolean {\n return super.flipX\n }\n\n override set flipX(flip: boolean) {\n if (this.flipX === flip) return\n super.flipX = flip\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get flipY(): boolean {\n return super.flipY\n }\n\n override set flipY(flip: boolean) {\n if (this.flipY === flip) return\n super.flipY = flip\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get h(): number {\n return super.h\n }\n\n override set h(h: number) {\n if (this.h === h) return\n super.h = h\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n get hitbox(): Box | undefined {\n if (this.#hitbox) return this.#hitbox\n const {hitbox} = this.anim\n if (!hitbox) return\n return (this.#hitbox ??= {\n x: this.x + (this.flipX ? this.w - hitbox.w - hitbox.x : hitbox.x),\n y: this.y + (this.flipY ? this.h - hitbox.h - hitbox.y : hitbox.y),\n w: hitbox.w,\n h: hitbox.h\n })\n }\n\n hits(box: Readonly<XY | Box>): boolean {\n const hitbox = this.hitbox\n if (!hitbox) return false\n const hurtbox = box instanceof Sprite ? box.hurtbox : box\n return !!hurtbox && boxHits(hitbox, hurtbox)\n }\n\n get hurtbox(): Box | undefined {\n if (this.#hurtbox) return this.#hurtbox\n const {hurtbox} = this.anim\n if (!hurtbox) return\n return (this.#hurtbox ??= {\n x: this.x + (this.flipX ? this.w - hurtbox.w - hurtbox.x : hurtbox.x),\n y: this.y + (this.flipY ? this.h - hurtbox.h - hurtbox.y : hurtbox.y),\n w: hurtbox.w,\n h: hurtbox.h\n })\n }\n\n override get id(): number {\n return super.id\n }\n\n override set id(id: number) {\n if (this.id === id) return\n super.id = id\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n /** true if animation has played once. */\n get looped(): boolean {\n // this comparison resets after the second loop since cel can only count to\n // 2 * anim.cels.\n return mod(this.#currentCel - this.cel, animCels * 2) >= this.anim.cels\n }\n\n /** sets cel to animation start. */\n reset(): void {\n this.cel = this.#currentCel // setter truncates.\n }\n\n // to-do: unit test and catch up on unit tests elsewhere.\n\n get tag(): Tag {\n return this.#atlas.tags[this.id] as Tag\n }\n\n /** sets animation, resets cel, dimensions, hitbox, and hurtbox. */\n set tag(tag: Tag) {\n const anim = this.#atlas.anim[tag]!\n this.w = anim.w\n this.h = anim.h\n this.id = anim.id\n this.reset()\n }\n\n override toString(): string {\n return `Sprite{${this.tag} (${this.x} ${this.y} ${this.z}) ${this.w}\u00D7${this.h}}`\n }\n\n override get w(): number {\n return super.w\n }\n\n override set w(w: number) {\n if (this.w === w) return\n super.w = w\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get x(): number {\n return super.x\n }\n\n override set x(x: number) {\n if (this.x === x) return\n super.x = x\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get y(): number {\n return super.y\n }\n\n override set y(y: number) {\n if (this.y === y) return\n super.y = y\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n /** current fractional cel in [0, 2 * anim.cels). */\n get #currentCel(): number {\n const cel = this.#looper.age / celMillis\n return cel % (this.anim.cels * 2)\n }\n}\n", "/** @internal */\nexport class ContextMenu {\n enable: boolean = false\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('contextmenu', this.#onContextMenu as EventListener)\n // disable long press vibration. nonpassive must be explicit.\n fn('touchstart', this.#onContextMenu as EventListener, {passive: false})\n return this\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onContextMenu = (ev: PointerEvent | TouchEvent): void => {\n if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return\n if (!this.enable) ev.preventDefault()\n }\n}\n", "/** @internal */\nexport class Gamepad {\n bits: number = 0\n // to-do: support analog button values, expose connected status and vibration,\n // and distinct devices. would be nice if vibration could merge with\n // navigator.vibrate().\n readonly bitByAxis: {[axis: number]: [less: number, more: number]} = {}\n readonly bitByButton: {[btn: number]: number} = {}\n onEvent: () => void = () => {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n get connected(): boolean {\n return isSecureContext && navigator.getGamepads().filter(Boolean).length > 0\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('gamepadconnected', this.onEvent)\n fn('gamepaddisconnected', this.onEvent)\n return this\n }\n\n reset(): void {\n this.bits = 0\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n update(): void {\n if (!isSecureContext) return\n for (const pad of navigator.getGamepads()) {\n for (const [index, axis] of pad?.axes.entries() ?? []) {\n const lessMore = this.bitByAxis[index]\n if (!lessMore) continue\n const bit = axis < 0 ? lessMore[0] : axis === 0 ? 0 : lessMore[1]\n this.bits |= Math.abs(axis) >= 0.5 ? bit : 0\n }\n for (const [index, btn] of pad?.buttons.entries() ?? []) {\n const bit = this.bitByButton[index]\n if (bit == null) continue\n this.bits |= btn.pressed ? bit : 0\n }\n }\n }\n}\n", "/** @internal */\nexport class Keyboard {\n /** KeyboardEvent.code to bit. */\n readonly bitByCode: {[code: string]: number} = {}\n invalid: boolean = false\n /** KeyboardEvent.code to state. Multiple keys may map to the same bit. */\n onEvent: () => void = () => {}\n #on: {[code: string]: boolean} = {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n get bits(): number {\n let bits = 0\n for (const k in this.bitByCode) bits |= this.#on[k] ? this.bitByCode[k]! : 0\n return bits\n }\n\n postupdate(): void {\n this.invalid = false\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n for (const ev of ['keydown', 'keyup']) fn(ev, this.#onKey as EventListener)\n return this\n }\n\n reset(): void {\n this.invalid = false\n this.#on = {}\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onKey = (ev: KeyboardEvent): void => {\n if (!ev.isTrusted || this.bitByCode[ev.code] == null) return\n if (ev.type === 'keydown' && (ev.metaKey || ev.altKey || ev.ctrlKey)) return\n this.invalid = true\n this.#on[ev.code] = ev.type === 'keydown'\n ev.preventDefault()\n this.onEvent()\n }\n}\n", "import {\n type Box,\n type XY,\n xyAdd,\n xyDistance,\n xyMax,\n xyMin,\n xySub\n} from '../types/geo.ts'\n\nexport type PointType =\n (typeof pointTypeByPointerType)[keyof typeof pointTypeByPointerType]\n\nexport type PointEvent = {\n bits: number\n /** most recent click. */\n clickClient: XY | undefined\n drag: boolean\n ev: (typeof pointEvents)[number]\n id: number\n /**\n * cursors should only use the primary inputs to avoid flickering between\n * distant points. inputs may be only secondaries.\n */\n primary: boolean\n type: PointType | undefined\n xyClient: XY\n}\n\nconst pointTypeByPointerType = {\n mouse: 'Mouse',\n pen: 'Pen',\n touch: 'Touch'\n} as const\nconst pointEvents = [\n 'pointercancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup'\n] as const\n\n/** @internal */\nexport class Pointer {\n readonly bitByButton: {[btn: number]: number} = {}\n dragMinClient: number = 5\n invalid: boolean = false\n onEvent: () => void = () => {}\n /** primary may be on or off. */\n primary: Readonly<PointEvent> | undefined\n /**\n * secondaries are deleted when buttons are off. secondaries are only present\n * when primary is defined.\n */\n readonly secondary: {[id: number]: Readonly<PointEvent>} = {}\n /** nonnegative. */\n #pinchStartClient: XY | undefined\n readonly #target: Element\n\n constructor(target: Element) {\n this.#target = target\n }\n\n get boundsClient(): Box | undefined {\n if (!this.primary?.bits && !Object.keys(this.secondary).length) return\n let min = {x: Infinity, y: Infinity}\n let max = {x: -Infinity, y: -Infinity}\n for (const pt of [this.primary, ...Object.values(this.secondary)]) {\n if (!pt?.bits) continue\n min = xyMin(min, pt.xyClient)\n max = xyMax(max, pt.xyClient)\n }\n return {x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y}\n }\n\n get centerClient(): XY | undefined {\n const bounds = this.boundsClient\n if (!bounds) return this.primary?.xyClient\n return xyAdd(bounds, {x: bounds.w / 2, y: bounds.h / 2})\n }\n\n get locked(): boolean {\n return this.#target.ownerDocument.pointerLockElement === this.#target\n }\n\n get pinchClient(): XY | undefined {\n if (!this.#pinchStartClient) return\n const end = this.#newPinchClient\n return end ? xySub(end, this.#pinchStartClient) : undefined\n }\n\n postupdate(): void {\n this.invalid = false\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n for (const ev of pointEvents) fn(ev, this.#onInput as EventListener)\n return this\n }\n\n reset(): void {\n this.invalid = false\n this.primary = undefined\n for (const pt in this.secondary) delete this.secondary[pt]\n this.#pinchStartClient = undefined\n }\n\n update(): void {\n const on =\n (this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length\n if (on < 2 || !this.#pinchStartClient)\n this.#pinchStartClient = this.#newPinchClient\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #evButtonsToBits(btns: number): number {\n let bits = 0\n for (let btn = 1; btn <= btns; btn <<= 1)\n if ((btn & btns) === btn) bits |= this.bitByButton[btn] ?? 0\n return bits\n }\n\n #onInput = (ev: PointerEvent): void => {\n if (!ev.isTrusted) return\n\n this.invalid = true\n const bits =\n ev.metaKey || ev.altKey || ev.ctrlKey\n ? 0\n : this.#evButtonsToBits(ev.buttons)\n if (bits) ev.preventDefault() // only prevent mapped buttons.\n const locked = this.locked\n if (ev.type === 'pointerdown' && !locked)\n try {\n this.#target.setPointerCapture(ev.pointerId)\n } catch {}\n\n const prevPt = ev.isPrimary ? this.primary : this.secondary[ev.pointerId]\n\n let xyClient\n if (locked) {\n // `devicePixelRatio` seems to be incorrect. when zoom is 500%, DPR is 10.\n // in full screen, this would give the actual zoom allowing `movementX`\n // to match the `offsetX` delta:\n // const scale = document.documentElement.clientWidth / screen.availWidth\n // console.log(\n // `screenDelta=${ev.screenX - prevScreen.x} movementX=${ev.movementX} movementXScaled=${ev.movementX * scale} offsetDelta=${ev.offsetX - prevOffset.x} clientDelta=${ev.clientX - prevClient.x}`\n // )\n // probably wouldn't work across devices though.\n const scale = 1 / devicePixelRatio\n\n // to-do: this should allow offscreen.\n xyClient = {\n x: Math.min(\n Math.max(\n 0,\n (prevPt?.xyClient.x ?? ev.offsetX) + ev.movementX * scale\n ),\n this.#target.clientWidth\n ),\n y: Math.min(\n Math.max(\n 0,\n (prevPt?.xyClient.y ?? ev.offsetY) + ev.movementY * scale\n ),\n this.#target.clientHeight\n )\n }\n } else xyClient = {x: ev.offsetX, y: ev.offsetY}\n\n const evType = ev.type as (typeof pointEvents)[number]\n const type =\n pointTypeByPointerType[\n ev.pointerType as keyof typeof pointTypeByPointerType\n ]\n let clickClient\n if (ev.type === 'pointerdown') clickClient = {x: xyClient.x, y: xyClient.y}\n else if (ev.type === 'pointermove') clickClient = prevPt?.clickClient\n const drag =\n !!bits &&\n (prevPt?.drag ||\n (!!clickClient &&\n xyDistance(clickClient, xyClient) >= this.dragMinClient))\n\n const pt = {\n clickClient,\n bits,\n drag,\n ev: evType,\n id: ev.pointerId,\n primary: ev.isPrimary,\n type,\n xyClient\n }\n if (ev.isPrimary) this.primary = pt\n else if (!bits) delete this.secondary[ev.pointerId]\n else this.secondary[ev.pointerId] = pt\n\n this.onEvent()\n }\n\n get #newPinchClient(): XY | undefined {\n if ((this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length < 2)\n return\n const bounds = this.boundsClient\n return bounds ? {x: bounds.w, y: bounds.h} : undefined\n }\n}\n", "import type {XYZ} from '../types/geo.ts'\n\n/** @internal */\nexport class Wheel {\n deltaClient: Readonly<XYZ> | undefined\n onEvent: () => void = () => {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n postupdate(): void {\n this.deltaClient = undefined\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('wheel', this.#onInput as EventListener, {passive: true})\n return this\n }\n\n reset(): void {\n this.deltaClient = undefined\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onInput = (ev: WheelEvent): void => {\n if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return\n this.deltaClient = {x: ev.deltaX, y: ev.deltaY, z: ev.deltaZ}\n this.onEvent()\n }\n}\n", "import type {Cam, LevelClientLocalXY} from '../graphics/cam.ts'\nimport type {XY, XYZ} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {ContextMenu} from './context-menu.ts'\nimport {Gamepad} from './gamepad.ts'\nimport {Keyboard} from './keyboard.ts'\nimport type {PointType} from './pointer.ts'\nimport {Pointer} from './pointer.ts'\nimport {Wheel} from './wheel.ts'\n\nexport type Chord<Button> = [Button, ...Button[]]\nexport type Combo<Button> = [Chord<Button>, ...Chord<Button>[]]\n\n// biome-ignore format:;\nexport type DefaultButton =\n | 'L' | 'R' | 'U' | 'D' // dpad.\n | 'A' | 'B' | 'C' // primary, secondary, tertiary.\n | 'Click' | 'Click2' | 'ClickMiddle'\n | 'Menu' | 'Back'\n\nexport type Point = LevelClientLocalXY & {\n click: LevelClientLocalXY | undefined\n type: PointType | undefined\n}\n\n/**\n * doesn't consider handled. local and level positions are reevaluated each\n * frame.\n */\ntype PointerState = Point & {\n center: LevelClientLocalXY\n /** false when pinched. */\n drag: {on: boolean; start: boolean; end: boolean}\n /** true if changed since last update. */\n invalid: boolean\n /** may be negative. */\n pinch:\n | {\n client: XY\n /** level / local. */\n xy: XY\n }\n | undefined\n /** secondary points. */\n secondary: Point[]\n}\n\n/** triggered. */\ntype WheelState = {\n delta: {\n client: Readonly<XYZ>\n /** level / local. */\n xy: XY\n }\n}\n\n/**\n * input device abstraction. aggregates devices, records history, and provides\n * a convenient API.\n *\n * devices own as much device-specific detail and as little coordination (time\n * and device) as practical. devices avoid caching state which is the\n * responsibility of Input. devices strive to provide the current state and\n * nothing else.\n *\n * if you miss reporting on a event between long updates, you just miss it.\n * that's the nature of polling. there's no queue.\n *\n * to-do: expose analog state of gamepad. offer direction as a number instead of\n * bool.\n * to-do: multiplayer. possible if devices were requested instead of sought.\n * to-do: expose input source device.\n */\nexport class Input<Button extends string> {\n /** time allowed between combo inputs. */\n comboMaxIntervalMillis: Millis = 300 as Millis\n /**\n * true if any button, key, or click was _ever_ on. doesn't consider handled.\n */\n gestured: boolean = false\n /** clear buttonish inputs for rest of frame. */\n handled: boolean = false\n /** true if _any_ input has changed since previous update. */\n invalid: boolean = false\n /**\n * minimum duration for an input to be considered held. durations are\n * calculated at frame boundaries, not on actual press. devices are treated\n * strictly as polled aggregates.\n */\n minHeldMillis: Millis = 300 as Millis\n readonly #bitByButton: {[btn in Button]?: number} = {}\n readonly #buttonByBit: {[bit: number]: Button} = {}\n #bits: number = 0\n readonly #cam: Readonly<Cam>\n /**\n * sequence of nonzero bits ordered from oldest to latest. combos end only by\n * expiration.\n */\n readonly #combo: number[] = []\n readonly #contextMenu: ContextMenu\n readonly #gamepad: Gamepad\n /** time since buttons changed. */\n #heldMillis: Millis = 0 as Millis\n readonly #keyboard: Keyboard\n readonly #pointer: Pointer\n #pointerState: PointerState | undefined\n /** bits last update. may not be equal to `#combo.at(-1)`. */\n #prevBits: number = 0\n readonly #wheel: Wheel\n #wheelState: Readonly<WheelState> | undefined\n\n constructor(cam: Readonly<Cam>, target: Element) {\n this.#cam = cam\n this.#contextMenu = new ContextMenu(target)\n this.#gamepad = new Gamepad(globalThis)\n this.#keyboard = new Keyboard(target.ownerDocument)\n this.#pointer = new Pointer(target)\n this.#wheel = new Wheel(target)\n }\n\n get anyOn(): boolean {\n return this.#bits !== 0\n }\n\n /** for debugging. */\n get combo(): Button[][] {\n const chords: Button[][] = []\n for (const bits of this.#combo) {\n const chord: Button[] = []\n for (let bit = 1; bit <= bits; bit <<= 1) {\n if ((bit & bits) === bit && this.#buttonByBit[bit])\n chord.push(this.#buttonByBit[bit]!)\n }\n chord.sort()\n chords.push(chord)\n }\n return chords\n }\n\n /**\n * enable when game is paused or in photo mode to allow right clicks and long\n * presses to save canvas.\n */\n get contextMenu(): {enable: boolean} {\n return this.#contextMenu\n }\n\n /** doesn't consider handled. gamepads must be polled. */\n get gamepad(): Readonly<object | undefined> {\n return this.#gamepad.connected ? {} : undefined\n }\n\n /** true if bits hasn't changed for a while. */\n get held(): boolean {\n return !this.handled && this.#heldMillis >= this.minHeldMillis\n }\n\n isAnyOn(...btns: Readonly<Chord<Button>>): boolean {\n return !this.handled && !!(this.#bits & this.#mapBits(btns))\n }\n\n isAnyOnStart(...btns: Readonly<Chord<Button>>): boolean {\n return this.started && this.isAnyOn(...btns)\n }\n\n /**\n * buttons are exact. eg, up won't match up AND down like `isOn('U')` will.\n * combo is exact too. `['A'], ['A']` will match `['A'], ['A']` but not\n * `['A'], ['A'], ['A']`.\n */\n isCombo(...combo: Readonly<Combo<Button>>): boolean {\n return combo.length === this.#combo.length && this.isComboEndsWith(...combo)\n }\n\n /**\n * `['A'], ['A']` will match `['A'], ['A']` and `['B'], ['A'], ['A']`. eg,\n * double-clicks often don't care about any preceding buttons.\n */\n isComboEndsWith(...combo: Readonly<Combo<Button>>): boolean {\n for (const [i, btns] of combo.entries()) {\n const bits = this.#mapBits(btns)\n if (this.#combo.at(-combo.length + i) !== bits) return false\n }\n // #combo is a historical record of buttons. whenever buttons changes, a new\n // entry is pushed. make sure the current entry is the current state.\n return !this.handled && (this.#combo.at(-1) === this.#bits || !this.#bits)\n }\n\n /** like isComboEndsWith() but test if the last button is triggered. */\n isComboEndsWithStart(...combo: Readonly<Combo<Button>>): boolean {\n // isOnStart() can handle zero-length.\n return this.isOnStart(...combo.at(-1)!) && this.isComboEndsWith(...combo)\n }\n\n /** like isCombo() but test if the last button is triggered. */\n isComboStart(...combo: Readonly<Combo<Button>>): boolean {\n return this.isOnStart(...combo.at(-1)!) && this.isCombo(...combo)\n }\n\n /*:\n * true if any button in chord is not on. this is usually what's wanted. eg:\n * ```ts\n * if (isOn('A', 'B')) console.log('on')\n * if (isOff('A', 'B')) console.log('not A+B; A and/or B is off')\n * ```\n */\n isOff(...btns: Readonly<Chord<Button>>): boolean {\n return !this.handled && !this.isOn(...btns)\n }\n\n isOffStart(...btns: Readonly<Chord<Button>>): boolean {\n const bits = this.#mapBits(btns)\n const wasOn = (this.#prevBits & bits) === bits\n // don't test this.#bits === 0 since it might forever miss the off event for\n // the specific bits.\n return wasOn && this.started && this.isOff(...btns)\n }\n\n /**\n * true if all buttons are on inclusively. eg, `isOn('U')` is true when up is\n * pressed or when up and down are pressed.\n */\n isOn(...btns: Readonly<Chord<Button>>): boolean {\n const bits = this.#mapBits(btns)\n return !this.handled && (this.#bits & bits) === bits\n }\n\n isOnStart(...btns: Readonly<Chord<Button>>): boolean {\n return this.started && this.isOn(...btns)\n }\n\n get key(): {invalid: boolean} {\n return {invalid: this.#keyboard.invalid}\n }\n\n mapDefault(): Input<Button | DefaultButton> {\n const input = this as Input<Button | DefaultButton>\n input.mapKeyboardCode('L', 'ArrowLeft')\n input.mapKeyboardCode('R', 'ArrowRight')\n input.mapKeyboardCode('U', 'ArrowUp')\n input.mapKeyboardCode('D', 'ArrowDown')\n input.mapKeyboardCode('C', 'KeyC')\n input.mapKeyboardCode('A', 'KeyX')\n input.mapKeyboardCode('B', 'KeyZ')\n input.mapKeyboardCode('Menu', 'Enter')\n input.mapKeyboardCode('Back', 'Escape')\n\n // https://w3c.github.io/gamepad/#remapping\n input.mapGamepadAxis('L', 'R', 0, 2)\n input.mapGamepadAxis('U', 'D', 1, 3)\n input.mapGamepadButton('L', 14)\n input.mapGamepadButton('R', 15)\n input.mapGamepadButton('U', 12)\n input.mapGamepadButton('D', 13)\n input.mapGamepadButton('C', 2)\n input.mapGamepadButton('B', 0) // to-do: not good from PS perspective.\n input.mapGamepadButton('A', 1) // to-do: not good from PS perspective.\n input.mapGamepadButton('Menu', 9)\n input.mapGamepadButton('Back', 8)\n\n input.mapPointerClick('Click', 1)\n input.mapPointerClick('Click2', 2)\n input.mapPointerClick('ClickMiddle', 4)\n return input\n }\n\n // to-do: support analog values.\n mapGamepadAxis(less: Button, more: Button, ...axes: readonly number[]): void {\n for (const axis of axes) {\n this.#gamepad.bitByAxis[axis] = [\n this.#mapButton(less),\n this.#mapButton(more)\n ]\n }\n }\n\n mapGamepadButton(btn: Button, ...indices: readonly number[]): void {\n for (const index of indices)\n this.#gamepad.bitByButton[index] = this.#mapButton(btn)\n }\n\n /** @arg codes union of KeyboardEvent.code. */\n mapKeyboardCode(btn: Button, ...codes: readonly string[]): void {\n for (const code of codes)\n this.#keyboard.bitByCode[code] = this.#mapButton(btn)\n }\n\n mapPointerClick(btn: Button, ...clicks: readonly number[]): void {\n for (const click of clicks)\n this.#pointer.bitByButton[click] = this.#mapButton(btn)\n }\n\n get on(): Button[] {\n const on: Button[] = []\n for (const btn in this.#bitByButton) if (this.isOn(btn)) on.push(btn)\n return on.sort()\n }\n\n set onEvent(cb: () => void) {\n this.#gamepad.onEvent = cb\n this.#keyboard.onEvent = cb\n this.#pointer.onEvent = cb\n this.#wheel.onEvent = cb\n }\n\n /** doesn't consider handled. */\n get point(): PointerState | undefined {\n return this.#pointerState\n }\n\n get pointer(): {dragMinClient: number} {\n return this.#pointer\n }\n\n register(op: 'add' | 'remove'): this {\n globalThis[`${op}EventListener`]('blur', this.reset) // keyup is lost if window loses focus.\n this.#contextMenu.register(op)\n this.#gamepad.register(op)\n this.#keyboard.register(op)\n this.#pointer.register(op)\n this.#wheel.register(op)\n return this\n }\n\n reset = (): void => {\n this.#bits = 0\n this.#prevBits = 0\n this.handled = false\n this.#heldMillis = 0 as Millis\n this.#combo.length = 0\n this.#gamepad.reset()\n this.#keyboard.reset()\n this.#pointer.reset()\n this.#pointerState = undefined\n this.#wheel.reset()\n this.#wheelState = undefined\n }\n\n /** true if bits has changed. */\n get started(): boolean {\n return !this.handled && this.#bits !== this.#prevBits\n }\n\n /**\n * call on new frame before altering cam. dispatches always occur before an\n * update.\n * @arg millis duration since last update.\n */\n update(millis: Millis): void {\n this.handled = false\n this.#gamepad.update()\n this.#pointer.update()\n\n this.#prevBits = this.#bits\n this.#bits =\n this.#gamepad.bits |\n this.#keyboard.bits |\n (this.#pointer.primary?.bits ?? 0)\n this.invalid =\n this.#bits !== this.#prevBits ||\n this.#pointer.invalid ||\n !!this.#wheel.deltaClient\n this.gestured ||= !!this.#bits\n\n if (\n (millis > this.comboMaxIntervalMillis && this.#bits !== this.#prevBits) ||\n (this.#heldMillis + millis > this.comboMaxIntervalMillis && !this.#bits)\n )\n this.#combo.length = 0\n\n if (this.#bits === this.#prevBits)\n this.#heldMillis = (this.#heldMillis + millis) as Millis\n else this.#heldMillis = millis\n\n if (this.#bits && this.#bits !== this.#prevBits) {\n if (this.#prevBits) this.#combo.length = 0 // new button without release.\n this.#combo.push(this.#bits)\n }\n\n if (this.#pointer.primary) {\n const pinchClient = this.#pointer.pinchClient\n const dragOn =\n this.#pointer.primary.drag &&\n !Object.values(this.#pointer.secondary).length\n const secondary: Point[] = []\n for (const pt of Object.values(this.#pointer.secondary)) {\n secondary.push({\n type: pt.type,\n click: pt.clickClient\n ? {\n client: pt.clickClient,\n local: this.#cam.clientToXYLocal(pt.clickClient),\n ...this.#cam.clientToXY(pt.clickClient)\n }\n : undefined,\n ...this.#cam.clientToXY(pt.xyClient),\n client: pt.xyClient,\n local: this.#cam.clientToXYLocal(pt.xyClient)\n })\n }\n const centerClient = this.#pointer.centerClient!\n const center = {\n client: centerClient,\n local: this.#cam.clientToXYLocal(centerClient),\n ...this.#cam.clientToXY(centerClient)\n }\n this.#pointerState = {\n center,\n click: this.#pointer.primary.clickClient\n ? {\n client: this.#pointer.primary.clickClient,\n local: this.#cam.clientToXYLocal(\n this.#pointer.primary.clickClient\n ),\n ...this.#cam.clientToXY(this.#pointer.primary.clickClient)\n }\n : undefined,\n drag: {\n on: dragOn,\n start: !this.#pointerState?.drag.on && dragOn,\n end: !!this.#pointerState?.drag.on && !dragOn\n },\n invalid: this.#pointer.invalid,\n pinch: pinchClient\n ? {client: pinchClient, xy: this.#cam.clientToXY(pinchClient)}\n : undefined,\n secondary,\n type: this.#pointer.primary.type,\n ...this.#cam.clientToXY(this.#pointer.primary.xyClient),\n client: this.#pointer.primary.xyClient,\n local: this.#cam.clientToXYLocal(this.#pointer.primary.xyClient)\n }\n }\n // secondary should never be set when primary isn't.\n else this.#pointerState = undefined\n\n this.#wheelState = this.#wheel.deltaClient\n ? {\n delta: {\n client: this.#wheel.deltaClient,\n xy: this.#cam.clientToXY(this.#wheel.deltaClient)\n }\n }\n : undefined\n this.#keyboard.postupdate()\n this.#pointer.postupdate()\n this.#wheel.postupdate()\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n /** doesn't consider handled. */\n get wheel(): Readonly<WheelState | undefined> {\n return this.#wheelState\n }\n\n /** get bits for buttons. */\n #mapBits(btns: Readonly<Chord<Button>>): number {\n let bits = 0\n for (const btn of btns) bits |= this.#bitByButton[btn] ?? 0\n return bits\n }\n\n /** assign button to bit. */\n #mapButton(btn: Button): number {\n const bit = (this.#bitByButton[btn] ??=\n 1 << Object.keys(this.#bitByButton).length)\n this.#buttonByBit[bit] = btn\n return bit\n }\n}\n", "import {debug} from '../utils/debug.ts'\n\nexport type PoolOpts<out T extends Block> = {\n alloc(pool: Pool<T>): T\n allocBytes: number\n minPages?: number\n pageBlocks: number\n}\n\nexport type Block = {/** variable pool byte offset. */ i: number}\n\n/**\n * a contiguous resizable TypedArray associated with an array of objects.\n *\n * alternatives:\n * - operating on the array without classes would probably be faster but the DX\n * sucks:\n * this.#sprite = this.#pool.alloc()\n * this.#pool.setX(this.#sprite, this.#pool.getX(this.#sprite) + 1)\n * - sprite classes owning all the data is nice DX but requires a copy on every\n * frame.\n * - ArrayBuffer.resize() is incompatible with WebGL.\n */\nexport class Pool<out T extends Block> {\n /** the next free block is always at size. */\n readonly #blocks: T[]\n readonly #opts: Readonly<Required<PoolOpts<T>>>\n #size: number = 0\n #u8: Uint8Array<ArrayBuffer>\n #view!: DataView<ArrayBuffer>\n\n constructor(opts: Readonly<PoolOpts<T>>) {\n if (opts.allocBytes <= 0) throw Error('byte allocation must be > 0')\n if (opts.pageBlocks <= 0) throw Error('page blocks must be > 0')\n this.#opts = {...opts, minPages: opts.minPages ?? 1}\n const initSize = this.#opts.minPages * opts.pageBlocks\n this.#blocks = new Array(initSize)\n this.#u8 = new Uint8Array()\n this.#resize(initSize, 'Init')\n }\n\n alloc(): T {\n if (this.#size >= this.#currentCapacity)\n this.#resize(this.#currentCapacity + this.#opts.pageBlocks, 'Call')\n const block = this.#blocks[this.#size]!\n block.i = this.#size * this.#opts.allocBytes\n this.#size++\n return block\n }\n\n clear(): void {\n this.#size = 0\n const minCapacity = this.#opts.minPages * this.#opts.pageBlocks\n if (this.#currentCapacity > minCapacity) this.#resize(minCapacity, 'Call')\n }\n\n free(...blocks: readonly T[]): void {\n for (const block of blocks) this.#freeBlock(block)\n }\n\n get size(): number {\n return this.#size\n }\n\n get view(): DataView<ArrayBuffer> {\n return this.#view\n }\n\n toDebugString(): string {\n let str = ''\n for (let i = 0; i < this.#u8.buffer.byteLength; i++) {\n if (i && !(i % this.#opts.allocBytes)) str += ' '\n str += this.#u8[i]!.toString(16).padStart(2, '0')\n }\n return str\n }\n\n get #currentCapacity(): number {\n return this.#u8.buffer.byteLength / this.#opts.allocBytes\n }\n\n #freeBlock(block: T): void {\n if (!this.#size) throw Error('pool underflow')\n\n this.#size--\n const start = this.#size * this.#opts.allocBytes\n this.#u8.copyWithin(block.i, start, start + this.#opts.allocBytes)\n this.#blocks[this.#size]!.i = block.i\n ;[this.#blocks[block.i], this.#blocks[this.#size]] = [\n this.#blocks[this.#size]!,\n this.#blocks[block.i]!\n ]\n\n const free = Math.floor(\n (this.#currentCapacity - this.#size) / this.#opts.pageBlocks\n )\n if (\n free &&\n this.#currentCapacity / this.#opts.pageBlocks - free >=\n this.#opts.minPages\n )\n this.#resize(this.#currentCapacity - free * this.#opts.pageBlocks, 'Call')\n }\n\n #resize(capacity: number, origin: 'Init' | 'Call'): void {\n if (origin === 'Call' && debug?.mem)\n console.debug(\n `[mem] ${capacity < this.#currentCapacity ? 'shrinking' : 'growing'} pool to ${capacity}`\n )\n\n this.#blocks.length = capacity\n for (let i = this.#currentCapacity; i < capacity; i++)\n this.#blocks[i] = this.#opts.alloc(this)\n\n const buffer = new ArrayBuffer(capacity * this.#opts.allocBytes)\n const u8 = new Uint8Array(buffer)\n u8.set(this.#u8.subarray(0, capacity * this.#opts.allocBytes))\n this.#u8 = u8\n this.#view = new DataView(buffer)\n }\n}\n", "export function rgbaHex(rgba: number): `#${string}` {\n return `#${rgba.toString(16).padStart(8, '0')}`\n}\n", "import {rgbaHex} from './color-util.ts'\n\nexport function download(uri: string, filename: string): void {\n const a = document.createElement('a')\n a.href = uri\n a.download = filename\n a.click()\n a.remove()\n}\n\nexport function initBody(\n canvas: Readonly<HTMLCanvasElement>,\n rgba: number\n): void {\n if (canvas.parentNode !== document.body) return\n document.body.style.margin = '0'\n // fill the screen except for UI chrome.\n document.body.style.width = '100dvw'\n document.body.style.height = '100dvh'\n document.body.style.overflow = 'hidden'\n document.body.style.background = rgbaHex(rgba)\n}\n\nexport function initMetaViewport(): void {\n if (document.querySelector('meta[name=\"viewport\"]')) return\n const meta = document.createElement('meta')\n meta.name = 'viewport'\n // don't wait for double-tap scaling on mobile.\n meta.content =\n 'width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no'\n document.head.appendChild(meta)\n}\n", "import {dateToTimestamp} from '../types/time.ts'\nimport {download} from './dom-util.ts'\n\nexport async function downloadScreenshot(\n canvas: HTMLCanvasElement,\n name: string\n): Promise<void> {\n using img = await screenshot(canvas)\n download(img.uri, `${name}-screenshot-${dateToTimestamp(new Date())}.webp`)\n}\n\nexport function initCanvas(\n canvas: HTMLCanvasElement | undefined,\n mode: 'Int' | 'Fraction'\n): HTMLCanvasElement {\n canvas ??= document.createElement('canvas')\n canvas.width = 0 // guarantee Renderer.#resize().\n canvas.style.cursor = 'none'\n canvas.style.display = 'block' // no line height spacing.\n canvas.style.outline = 'none' // disable focus outline.\n canvas.style.cursor = 'none'\n if (mode === 'Int') canvas.style.imageRendering = 'pixelated' // to-do: why doesn't cam mode set this?\n // update on each pointermove *touch* Event like *mouse* Events.\n canvas.style.touchAction = 'none'\n canvas.tabIndex = 0\n canvas.focus()\n if (!canvas.parentNode) document.body.append(canvas)\n return canvas\n}\n\nexport async function requestFullscreen(\n canvas: HTMLCanvasElement\n): Promise<boolean> {\n if (!document.fullscreenEnabled) return false\n\n if (document.fullscreenElement !== canvas)\n try {\n await canvas.requestFullscreen({navigationUI: 'hide'})\n } catch {\n return false\n }\n\n if (!document.pointerLockElement) {\n try {\n await canvas.requestPointerLock({unadjustedMovement: true})\n } catch (err) {\n if (err instanceof Error && err.name === 'NotSupportedError')\n try {\n await canvas.requestPointerLock()\n } catch {}\n }\n }\n\n return true\n}\n\n/** draws a canvas to a blob URI. */\nexport function screenshot(\n canvas: HTMLCanvasElement\n): Promise<Disposable & {uri: string}> {\n return new Promise((fulfil, reject) => {\n canvas.toBlob(blob => {\n if (blob) {\n const img = {\n [Symbol.dispose]() {\n URL.revokeObjectURL(this.uri)\n },\n uri: URL.createObjectURL(blob)\n }\n fulfil(img)\n } else reject(Error('no blob'))\n }, 'image/webp')\n })\n}\n", "export async function fetchAudio(url: string): Promise<ArrayBuffer> {\n const rsp = await fetch(url, {headers: {accept: 'audio/mpeg'}})\n if (!rsp.ok)\n throw Error(`fetch error ${rsp.status}: ${rsp.statusText} for ${url}`)\n const type = rsp.headers.get('Content-Type')\n // to-do: ogg\n if (!type?.startsWith('audio/mpeg'))\n throw Error(`bad fetch response type ${type} for ${url}`)\n return await rsp.arrayBuffer()\n}\n\nexport function fetchImage(url: string): Promise<HTMLImageElement> {\n const img = new Image()\n const promise = loadImage(img)\n img.src = url\n return promise\n}\n\nexport async function loadImage(\n img: HTMLImageElement\n): Promise<HTMLImageElement> {\n const promise = new Promise<HTMLImageElement>((fulfil, reject) => {\n img.onload = () => fulfil(img)\n img.onerror = () => reject(Error(`image load error for ${img.src}`))\n })\n return img.complete ? img : await promise\n}\n", "import {debug} from '../utils/debug.ts'\n\n/** @internal */\nexport type GL2 = WebGL2RenderingContext\n/** @internal */\nexport type GLProgram = WebGLProgram\n/** @internal */\nexport type GLShader = WebGLShader\n/** @internal */\nexport type GLTexture = WebGLTexture\n/** @internal */\nexport type GLUniformLocation = WebGLUniformLocation\n/** @internal */\nexport type GLUniformMap = {[name: string]: GLUniformLocation}\n\n/** @internal */\nexport type Shader = {\n program: GLProgram | null\n buffer: WebGLBuffer | null\n uniform: GLUniformMap\n vao: WebGLVertexArrayObject | null\n textures: GLTexture[]\n}\n\n/** @internal */\nexport function Shader(\n gl: GL2,\n vertGLSL: string,\n fragGLSL: string,\n textures: GLTexture[]\n): Shader {\n const program = loadProgram(gl, vertGLSL, fragGLSL)\n gl.useProgram(program)\n return {\n buffer: gl.createBuffer(),\n program,\n textures,\n uniform: GLUniformMap(gl, program),\n vao: gl.createVertexArray()\n }\n}\n\nfunction GLUniformMap(gl: GL2, pgm: GLProgram | null): GLUniformMap {\n const len = pgm ? gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS) : 0\n const map = debug?.render\n ? new Proxy<GLUniformMap>(\n {},\n {\n get(target, k: string): GLUniformLocation {\n if (target[k] == null) throw Error(`no shader uniform \"${k}\"`)\n return target[k]\n }\n }\n )\n : {}\n for (let i = 0; i < len; ++i) {\n const uniform = gl.getActiveUniform(pgm!, i)\n if (!uniform) throw Error(`no shader uniform at index ${i}`)\n const location = gl.getUniformLocation(pgm!, uniform.name)\n if (!location) throw Error(`no shader uniform \"${uniform.name}\"`)\n const name = uniform.name.replace('[0]', '') // arrays.\n map[name] = location\n }\n return map\n}\n\nfunction loadProgram(\n gl: GL2,\n vertGLSL: string,\n fragGLSL: string\n): GLProgram | null {\n const pgm = gl.createProgram()\n if (!pgm) return null\n\n const vert = compileShader(gl, 'VERTEX_SHADER', vertGLSL)\n const frag = compileShader(gl, 'FRAGMENT_SHADER', fragGLSL)\n if (!vert || !frag) return null\n gl.attachShader(pgm, vert)\n gl.attachShader(pgm, frag)\n gl.linkProgram(pgm)\n\n if (debug?.render && !gl.getProgramParameter(pgm, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(pgm)?.slice(0, -1)\n throw Error(`shader link failure; ${log}`)\n }\n\n gl.detachShader(pgm, frag)\n gl.detachShader(pgm, vert)\n gl.deleteShader(frag)\n gl.deleteShader(vert)\n\n return pgm\n}\n\nfunction compileShader(\n gl: GL2,\n type: 'FRAGMENT_SHADER' | 'VERTEX_SHADER',\n glsl: string\n): GLShader | null {\n const shader = gl.createShader(gl[type])\n if (!shader) return shader\n gl.shaderSource(shader, glsl.trim())\n gl.compileShader(shader)\n\n if (debug?.render && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader)?.slice(0, -1)\n throw Error(`shader compile failure; ${log}`)\n }\n\n return shader\n}\n", "export const spriteFragGLSL: string = `#version 300 es\n#pragma debug(${debug?.render ? 'on' : 'off'}) \n#pragma optimize(${debug?.render ? 'off' : 'on'})\n\nprecision highp int;\nprecision highp float;\nprecision highp usampler2D;\n\nuniform sampler2D uTex;\nuniform uvec2 uTexWH;\n\nflat in uint vStretch;\nflat in ivec4 vTexXYWH;\nflat in int vZ;\nin vec2 vDstWH;\nflat in ivec2 vDstWHFixed;\n\nout vec4 oRGBA;\n\nvoid main() {\n if (vZ == ${Layer.Hidden} || vDstWHFixed.x == 0 || vDstWHFixed.y == 0)\n discard;\n\n vec2 px = vec2(vTexXYWH.xy) + (\n vStretch == 1u ? (vDstWH * vec2(vTexXYWH.zw) / vec2(vDstWHFixed))\n : mod(vDstWH, vec2(vTexXYWH.zw))\n );\n\n oRGBA = texture(uTex, px / vec2(uTexWH));\n if(oRGBA.a < .001) discard;\n}\n`\n\nimport {debug} from '../utils/debug.ts'\nimport {Layer} from './layer.ts'\n", "export const spriteVertGLSL: string = `#version 300 es\n#pragma debug(${debug?.render ? 'on' : 'off'}) \n#pragma optimize(${debug?.render ? 'off' : 'on'})\n\n// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2\nprecision highp int;\nprecision highp float;\nprecision highp usampler2D;\n\nuniform ivec4 uCam;\nuniform usampler2D uCels;\nuniform float uAge;\n\nlayout (location=0) in ivec2 iUV;\nlayout (location=1) in uint iy8_x24;\nlayout (location=2) in uint iw8_sxyz_llll_y16;\nlayout (location=3) in uint ii11_c5_h12_w4;\n\nconst int maxY = 0x20000;\nconst int layers = 16;\nconst int maxDepth = maxY * layers;\n\nflat out uint vStretch;\nflat out ivec4 vTexXYWH;\nflat out int vZ;\nout vec2 vDstWH;\nflat out ivec2 vDstWHFixed;\n\nvoid main() {\n int x = (int((iy8_x24 & 0xffffffu) << 8) >> 8) / 64;\n int y = (int(iy8_x24 >> 24) | (int(iw8_sxyz_llll_y16 & 0xffffu) << 16 >> 8)) / 64;\n int z = int((iw8_sxyz_llll_y16 >> 16) & 0xfu);\n bool zend = bool(iw8_sxyz_llll_y16 & 0x100000u);\n bool flipY = bool(iw8_sxyz_llll_y16 & 0x200000u);\n bool flipX = bool(iw8_sxyz_llll_y16 & 0x400000u);\n bool stretch = bool(iw8_sxyz_llll_y16 & 0x800000u);\n int id = int((ii11_c5_h12_w4 >> 17) & 0x7ff0u); // ignore cel.\n int cel = int((ii11_c5_h12_w4 >> 16) & 0xfu); // ignore the MSB.\n int w = int(((ii11_c5_h12_w4 & 0xfu) << 8) | (iw8_sxyz_llll_y16 >> 24));\n int h = int((ii11_c5_h12_w4 >> 4) & 0xfffu);\n\n // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel\n float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);\n\n ivec2 targetWH = iUV * ivec2(w, h);\n\n vec2 end = vec2(x + targetWH.x, y + targetWH.y);\n // UI layers are always given in screen coordinates.\n // to-do: how to handle non-int mode?\n vec2 camXY = z < ${Layer.A} ? vec2(0, 0) : vec2(uCam.xy);\n vec2 clip = ((-2. * camXY + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);\n gl_Position = vec4(clip, depth, 1);\n\n int frame = (((int(uAge / ${celMillis}) & 0x1f) - cel) + ${animCels}) & 0xf;\n uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);\n vTexXYWH = ivec4(texXYWH);\n vZ = z;\n\n vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));\n vDstWHFixed = ivec2(w, h) * ivec2(flipX ? -1 : 1, flipY ? -1 : 1);\n\n vStretch = stretch ? 1u : 0u;\n}\n`\n\nimport {debug} from '../utils/debug.ts'\nimport {animCels, celMillis} from './atlas.ts'\nimport {Layer} from './layer.ts'\n", "import type {Pool} from '../mem/pool.ts'\nimport {type WH, whEq} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {debug} from '../utils/debug.ts'\nimport type {Atlas, TagFormat} from './atlas.ts'\nimport type {Cam} from './cam.ts'\nimport {type GL2, Shader} from './gl.ts'\nimport {drawableBytes, type Sprite} from './sprite.ts'\nimport {spriteFragGLSL} from './sprite-frag.glsl.ts'\nimport {spriteVertGLSL} from './sprite-vert.glsl.ts'\n\n/** @internal */\nexport type Context = {gl: GL2; spriteShader: Shader; viewport: WH}\n\nconst uv: Readonly<Int8Array> = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0])\n\nexport class Renderer {\n /** when off, ents should avoid requesting renders. */\n always: boolean = debug?.render === 'always'\n clears: number = 0\n invalid: boolean = false\n loseContext: WEBGL_lose_context | undefined\n readonly #canvas: HTMLCanvasElement\n #clearRGBA: number = 0\n #depth: boolean = true\n #ctx: Context | undefined\n readonly #looper: {readonly age: Millis}\n readonly #preloadAtlas: Readonly<Atlas>\n #preloadAtlasImage: Readonly<HTMLImageElement> | undefined\n\n constructor(\n preloadAtlas: Readonly<Atlas>,\n canvas: HTMLCanvasElement,\n looper: {readonly age: Millis}\n ) {\n this.#preloadAtlas = preloadAtlas\n this.#canvas = canvas\n this.#looper = looper\n }\n\n clear(rgba: number): void {\n if (!this.#ctx) return\n const {gl} = this.#ctx\n if (this.#clearRGBA !== rgba) {\n this.#clearRGBA = rgba\n gl.clearColor(\n ((rgba >>> 24) & 0xff) / 0xff,\n ((rgba >>> 16) & 0xff) / 0xff,\n ((rgba >>> 8) & 0xff) / 0xff,\n ((rgba >>> 0) & 0xff) / 0xff\n )\n }\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)\n this.clears++\n }\n\n draw(pool: Readonly<Pool<Sprite<TagFormat>>>): void {\n if (!this.#preloadAtlasImage || !this.#ctx) return\n const {gl, spriteShader} = this.#ctx\n\n gl.bindBuffer(gl.ARRAY_BUFFER, spriteShader.buffer)\n gl.bufferData(\n gl.ARRAY_BUFFER,\n pool.view,\n gl.DYNAMIC_DRAW,\n 0,\n pool.size * drawableBytes\n )\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindVertexArray(spriteShader.vao)\n gl.drawArraysInstanced(\n gl.TRIANGLE_STRIP,\n 0,\n uv.length / 2, // d\n pool.size\n )\n gl.bindVertexArray(null)\n\n this.invalid = false\n }\n\n get hasContext(): boolean {\n return this.#ctx != null\n }\n\n load(preloadAtlas: Readonly<HTMLImageElement> | undefined): void {\n this.#preloadAtlasImage = preloadAtlas\n this.#ctx = this._Context()\n }\n\n predraw(cam: Readonly<Cam>): void {\n if (!this.#ctx) return\n const {gl, spriteShader, viewport} = this.#ctx\n\n if (!whEq(viewport, cam)) {\n gl.viewport(0, 0, cam.w, cam.h)\n viewport.w = cam.w\n viewport.h = cam.h\n }\n\n gl.useProgram(spriteShader.program)\n\n gl.uniform4i(spriteShader.uniform.uCam!, cam.x, cam.y, cam.w, cam.h)\n gl.uniform1f(spriteShader.uniform.uAge!, this.#looper.age)\n\n for (const [i, tex] of spriteShader.textures.entries()) {\n gl.activeTexture(gl.TEXTURE0 + i)\n gl.bindTexture(gl.TEXTURE_2D, tex)\n }\n }\n\n register(op: 'add' | 'remove'): this {\n this.#canvas[`${op}EventListener`]('webglcontextlost', this.#onContextLost)\n this.#canvas[`${op}EventListener`](\n 'webglcontextrestored',\n this.#onContextRestored\n )\n return this\n }\n\n setDepth(enable: boolean): void {\n this.#depth = enable\n if (!this.#ctx) return\n if (enable) this.#ctx.gl.enable(this.#ctx.gl.DEPTH_TEST)\n else this.#ctx.gl.disable(this.#ctx.gl.DEPTH_TEST)\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n /** @internal */\n _Context(): Context | undefined {\n const gl = this.#ctx?.gl ?? GL2(this.#canvas)\n if (!gl) return\n\n const shader = Shader(gl, spriteVertGLSL, spriteFragGLSL, [\n gl.createTexture(),\n gl.createTexture()\n ])\n\n // allow translucent textures to be layered.\n gl.enable(gl.BLEND)\n gl.blendFuncSeparate(\n gl.SRC_ALPHA,\n gl.ONE_MINUS_SRC_ALPHA,\n gl.ONE,\n gl.ONE_MINUS_SRC_ALPHA\n )\n\n this.setDepth(this.#depth)\n\n // enable z-buffer for [0, 1] ([foreground, background]).\n gl.depthRange(0, 1)\n gl.clearDepth(1)\n gl.depthFunc(gl.LESS)\n\n // disable image colorspace conversions. the default is browser dependent.\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false)\n\n gl.bindVertexArray(shader.vao)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())\n gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW)\n gl.enableVertexAttribArray(0)\n gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, shader.buffer)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, drawableBytes, 0)\n gl.vertexAttribDivisor(1, 1)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, drawableBytes, 4)\n gl.vertexAttribDivisor(2, 1)\n gl.enableVertexAttribArray(3)\n gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, drawableBytes, 8)\n gl.vertexAttribDivisor(3, 1)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindTexture(gl.TEXTURE_2D, shader.textures[0]!)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n if (this.#preloadAtlasImage)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n this.#preloadAtlasImage\n )\n gl.bindTexture(gl.TEXTURE_2D, null)\n\n gl.bindTexture(gl.TEXTURE_2D, shader.textures[1]!)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA16UI, // source XYWH cannot be > 65535.\n 1,\n this.#preloadAtlas.celXYWH.length / 4, // 4 u16s per row\n 0,\n gl.RGBA_INTEGER,\n gl.UNSIGNED_SHORT,\n new Uint16Array(this.#preloadAtlas.celXYWH)\n )\n gl.bindTexture(gl.TEXTURE_2D, null)\n\n gl.bindVertexArray(null)\n\n gl.uniform1i(shader.uniform.uTex!, 0)\n gl.uniform1i(shader.uniform.uCels!, 1)\n if (this.#preloadAtlasImage)\n gl.uniform2ui(\n shader.uniform.uTexWH!,\n this.#preloadAtlasImage.naturalWidth,\n this.#preloadAtlasImage.naturalHeight\n )\n\n if (!this.invalid && debug?.invalid) console.debug('renderer invalid')\n this.invalid = true\n // keep outside of #context so it can be restored.\n this.loseContext = gl.getExtension('WEBGL_lose_context') ?? undefined\n return (this.#ctx = {gl, spriteShader: shader, viewport: {w: 0, h: 0}})\n }\n\n #onContextLost = (ev: Event): void => {\n ev.preventDefault() // required.\n console.debug('[render] WebGL context lost')\n this.#ctx = undefined\n }\n\n #onContextRestored = (): void => {\n console.debug('[render] WebGL context restored')\n this.#ctx = this._Context()\n }\n}\n\nfunction GL2(canvas: HTMLCanvasElement): GL2 | undefined {\n const gl = canvas.getContext('webgl2', {\n // to-do: expose.\n antialias: false,\n powerPreference: 'low-power',\n // avoid flicker caused by clearing the drawing buffer. see\n // https://developer.chrome.com/blog/desynchronized/.\n preserveDrawingBuffer: true,\n ...(!debug?.render && {desynchronized: true})\n })\n if (!gl) {\n console.debug('[render] no GL context')\n return\n }\n\n if (debug?.render && !gl.getContextAttributes()?.desynchronized)\n console.debug('[render] no WebGL DOM desynchronization')\n\n return gl\n}\n", "import type {Millis} from './types/time.ts'\n\n/**\n * frame manager. passes frame requests when not hidden. callers should request\n * frames when an update occurs or a check for an update occurs. eg, gamepads\n * must be polled.\n *\n * when registered, restoring visibility triggers an automatic request.\n */\nexport class Looper {\n /** duration of frames observed. */\n age: Millis = 0 as Millis\n onFrame: ((millis: Millis) => void) | undefined\n #req: number = 0\n #registered: boolean = false\n\n register(op: 'add' | 'remove'): this {\n const fn = `${op}EventListener` as const\n document[fn]('visibilitychange', this.#onVisibility)\n if (op === 'remove') this.#cancel()\n // try to let user drive initial frame since assets may be loading.\n this.#registered = op === 'add'\n return this\n }\n\n requestFrame(): void {\n if (this.#req || document.hidden || !this.#registered) return\n this.#req = requestAnimationFrame(this.#onFrame as FrameRequestCallback)\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #cancel(): void {\n if (this.#req) cancelAnimationFrame(this.#req)\n this.#req = 0\n }\n\n #onFrame = (now: Millis): void => {\n const millis = (now - (this.age || now)) as Millis\n this.age = now\n this.#req = 0\n this.onFrame?.(millis)\n }\n\n #onVisibility = (ev: Event): void => {\n if (!ev.isTrusted) return\n if (document.hidden) this.#cancel()\n else this.requestFrame()\n }\n}\n", "import type {Millis} from '../types/time.ts'\n\nexport class DelayInterval {\n #delay: () => Millis\n #interval: Millis\n #intervalID: number = 0\n #onInterval: () => void\n #timerID: number = 0\n\n constructor(delay: () => Millis, interval: Millis, onInterval: () => void) {\n this.#delay = delay\n this.#interval = interval\n this.#onInterval = onInterval\n }\n\n register(op: 'add' | 'remove'): this {\n if (op === 'add') {\n this.#timerID = setTimeout(() => {\n this.#onInterval()\n this.#intervalID = setInterval(this.#onInterval, this.#interval)\n }, this.#delay())\n } else {\n clearTimeout(this.#timerID)\n clearInterval(this.#intervalID)\n }\n\n return this\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n}\n", "import {Zoo} from './ents/zoo.ts'\nimport type {Atlas, AtlasJSON, TagFormat} from './graphics/atlas.ts'\nimport {parseAtlas} from './graphics/atlas-parser.ts'\nimport {Cam} from './graphics/cam.ts'\nimport {Renderer} from './graphics/renderer.ts'\nimport {drawableBytes, Sprite} from './graphics/sprite.ts'\nimport {type DefaultButton, Input} from './input/input.ts'\nimport {Looper} from './looper.ts'\nimport {Pool, type PoolOpts} from './mem/pool.ts'\nimport type {WH} from './types/geo.ts'\nimport type {Millis} from './types/time.ts'\nimport {initCanvas} from './utils/canvas-util.ts'\nimport {DelayInterval} from './utils/delay-interval.ts'\nimport {initBody, initMetaViewport} from './utils/dom-util.ts'\nimport {loadImage} from './utils/fetch-util.ts'\n\nexport type VoidOpts<out Tag extends TagFormat> = {\n preloadAtlas?: {image: HTMLImageElement; json: AtlasJSON} | undefined\n backgroundRGBA?: number\n canvas?: HTMLCanvasElement | undefined\n minWH?: WH | undefined\n input?: 'Custom' | 'Default' | undefined\n mode?: 'Int' | 'Fraction' | undefined\n poll?: {delay?: (() => Millis) | undefined; period: Millis} | undefined\n sprites?:\n | Partial<Omit<PoolOpts<Sprite<Tag>>, 'alloc' | 'allocBytes'>>\n | undefined\n}\n\nexport class Void<\n out Tag extends TagFormat,\n Button extends string = DefaultButton\n> {\n readonly cam: Cam = new Cam()\n readonly canvas: HTMLCanvasElement\n readonly input: Input<Button>\n readonly preload: Atlas\n readonly renderer: Renderer\n readonly sprites: Pool<Sprite<Tag>>\n readonly zoo: Zoo<Tag> = new Zoo()\n readonly looper: Looper = new Looper()\n readonly #poll: DelayInterval | undefined\n readonly #preloadAtlasImage: HTMLImageElement | undefined\n // may trigger an initial force update.\n readonly #resizeObserver = new ResizeObserver(() => this.onResize())\n\n constructor(opts: Readonly<VoidOpts<Tag>>) {\n if (opts.poll != null)\n this.#poll = new DelayInterval(\n opts.poll.delay ?? (() => 0 as Millis),\n opts.poll.period,\n () => this.onPoll()\n )\n\n initMetaViewport()\n this.canvas = initCanvas(opts.canvas, opts.mode ?? 'Int')\n initBody(this.canvas, opts.backgroundRGBA ?? 0x000000ff)\n\n if (opts.minWH) this.cam.minWH = opts.minWH\n this.cam.mode = opts.mode ?? 'Int'\n this.cam.update(this.canvas)\n\n this.input = new Input(this.cam, this.canvas)\n if (opts.input !== 'Custom') this.input.mapDefault()\n this.input.onEvent = () => this.onEvent()\n\n if (opts.preloadAtlas) this.#preloadAtlasImage = opts.preloadAtlas.image\n\n this.preload = opts.preloadAtlas\n ? parseAtlas(opts.preloadAtlas.json)\n : {anim: {}, celXYWH: [], tags: []}\n\n this.renderer = new Renderer(this.preload ?? {}, this.canvas, this.looper)\n\n this.sprites = new Pool({\n alloc: pool => this.onAllocSprite(pool),\n allocBytes: drawableBytes,\n minPages: opts.sprites?.minPages ?? 3,\n pageBlocks: opts.sprites?.pageBlocks ?? 1000\n })\n\n this.looper.onFrame = millis => this.onFrame(millis)\n }\n\n onAllocSprite(pool: Pool<Sprite<Tag>>): Sprite<Tag> {\n return new Sprite(pool, 0, this.preload, this.looper)\n }\n\n onEvent(): void {\n this.requestFrame('Force')\n }\n\n /** update input, update canvas, update cam, update world, then render. */\n onFrame(millis: Millis): void {\n if (document.hidden) return\n this.input.update(millis)\n\n this.requestFrame() // request frame before in case loop cancels.\n\n this.onLoop(millis)\n\n this.cam.postupdate()\n }\n\n // biome-ignore lint/correctness/noUnusedFunctionParameters:;\n onLoop(millis: Millis): void {}\n\n onPoll(): void {\n this.requestFrame('Force')\n }\n\n onResize(): void {\n this.requestFrame('Force') // force cam reeval.\n }\n\n async register(op: 'add' | 'remove'): Promise<void> {\n this.input.register(op)\n this.renderer.register(op)\n this.looper.register(op)\n if (!this.canvas.parentElement) throw Error('no canvas parent')\n if (op === 'add') this.#resizeObserver.observe(this.canvas.parentElement)\n else this.#resizeObserver.unobserve(this.canvas.parentElement)\n\n if (op === 'add') this.looper.requestFrame()\n this.#poll?.register(op)\n\n if (this.#preloadAtlasImage) await loadImage(this.#preloadAtlasImage)\n this.renderer.load(this.#preloadAtlasImage)\n }\n\n requestFrame(force?: 'Force' | undefined): void {\n if (force || this.renderer.always || this.input.anyOn || this.input.gamepad)\n this.looper.requestFrame()\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.register('remove')\n }\n}\n", "import {voidVersion} from './types/void-version.ts'\n\nexport {type Font, memProp5x6} from 'mem-font'\nexport * from './ents/button-ent.ts'\nexport * from './ents/cursor-ent.ts'\nexport * from './ents/ent.ts'\nexport * from './ents/follow-cam-ent.ts'\nexport * from './ents/nine-patch-ent.ts'\nexport * from './ents/text-ent.ts'\nexport * from './ents/zoo.ts'\nexport * from './graphics/atlas.ts'\nexport * from './graphics/atlas-parser.ts'\nexport * from './graphics/cam.ts'\nexport * from './graphics/layer.ts'\nexport * from './graphics/sprite.ts'\nexport * from './input/input.ts'\nexport type {PointEvent} from './input/pointer.ts'\nexport * from './mem/pool.ts'\nexport * from './random/random.ts'\nexport * from './storage/local-storage.ts'\nexport * from './text/font.ts'\nexport * from './text/text-layout.ts'\nexport * from './types/geo.ts'\nexport * from './types/json.ts'\nexport * from './types/time.ts'\nexport * from './utils/async-util.ts'\nexport * from './utils/canvas-util.ts'\nexport * from './utils/debug.ts'\nexport * from './utils/dom-util.ts'\nexport * from './utils/fetch-util.ts'\nexport * from './void.ts'\n\nexport const version: string = voidVersion\n ? `${voidVersion.version}+${voidVersion.published}`\n : '?'\n", "{\n \"anim\": {\n \"background--OrangeCheckerboard\": {\"cels\": 1, \"h\": 2, \"id\": 0, \"w\": 2},\n \"background--GreyCheckerboard\": {\"cels\": 1, \"h\": 2, \"id\": 1, \"w\": 2},\n \"background--Kiwi\": {\"cels\": 1, \"h\": 2, \"id\": 2, \"w\": 2},\n \"background--Strawberry\": {\"cels\": 1, \"h\": 2, \"id\": 3, \"w\": 2},\n \"background--Grape\": {\"cels\": 1, \"h\": 2, \"id\": 4, \"w\": 2},\n \"background--Blueberry\": {\"cels\": 1, \"h\": 2, \"id\": 5, \"w\": 2},\n \"background--Bubblegum\": {\"cels\": 1, \"h\": 2, \"id\": 6, \"w\": 2},\n \"background--Transparent\": {\"cels\": 1, \"h\": 2, \"id\": 7, \"w\": 2},\n \"background--Black\": {\"cels\": 1, \"h\": 2, \"id\": 8, \"w\": 2},\n \"backpacker--WalkRight\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 9,\n \"w\": 8\n },\n \"backpacker--WalkDown\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 10,\n \"w\": 8\n },\n \"backpacker--WalkUp\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 11,\n \"w\": 8\n },\n \"cursor--Pointer\": {\n \"cels\": 1,\n \"h\": 14,\n \"hitbox\": {\"x\": 0, \"y\": 0, \"w\": 2, \"h\": 2},\n \"hurtbox\": {\"x\": 0, \"y\": 0, \"w\": 2, \"h\": 2},\n \"id\": 12,\n \"w\": 8\n },\n \"mem-prop-5x6--00\": {\"cels\": 1, \"h\": 6, \"id\": 13, \"w\": 5},\n \"mem-prop-5x6--01\": {\"cels\": 1, \"h\": 6, \"id\": 14, \"w\": 5},\n \"mem-prop-5x6--02\": {\"cels\": 1, \"h\": 6, \"id\": 15, \"w\": 5},\n \"mem-prop-5x6--03\": {\"cels\": 1, \"h\": 6, \"id\": 16, \"w\": 5},\n \"mem-prop-5x6--04\": {\"cels\": 1, \"h\": 6, \"id\": 17, \"w\": 5},\n \"mem-prop-5x6--05\": {\"cels\": 1, \"h\": 6, \"id\": 18, \"w\": 5},\n \"mem-prop-5x6--06\": {\"cels\": 1, \"h\": 6, \"id\": 19, \"w\": 5},\n \"mem-prop-5x6--07\": {\"cels\": 1, \"h\": 6, \"id\": 20, \"w\": 5},\n \"mem-prop-5x6--08\": {\"cels\": 1, \"h\": 6, \"id\": 21, \"w\": 5},\n \"mem-prop-5x6--09\": {\"cels\": 1, \"h\": 6, \"id\": 22, \"w\": 5},\n \"mem-prop-5x6--0a\": {\"cels\": 1, \"h\": 6, \"id\": 23, \"w\": 5},\n \"mem-prop-5x6--0b\": {\"cels\": 1, \"h\": 6, \"id\": 24, \"w\": 5},\n \"mem-prop-5x6--0c\": {\"cels\": 1, \"h\": 6, \"id\": 25, \"w\": 5},\n \"mem-prop-5x6--0d\": {\"cels\": 1, \"h\": 6, \"id\": 26, \"w\": 5},\n \"mem-prop-5x6--0e\": {\"cels\": 1, \"h\": 6, \"id\": 27, \"w\": 5},\n \"mem-prop-5x6--0f\": {\"cels\": 1, \"h\": 6, \"id\": 28, \"w\": 5},\n \"mem-prop-5x6--10\": {\"cels\": 1, \"h\": 6, \"id\": 29, \"w\": 5},\n \"mem-prop-5x6--11\": {\"cels\": 1, \"h\": 6, \"id\": 30, \"w\": 5},\n \"mem-prop-5x6--12\": {\"cels\": 1, \"h\": 6, \"id\": 31, \"w\": 5},\n \"mem-prop-5x6--13\": {\"cels\": 1, \"h\": 6, \"id\": 32, \"w\": 5},\n \"mem-prop-5x6--14\": {\"cels\": 1, \"h\": 6, \"id\": 33, \"w\": 5},\n \"mem-prop-5x6--15\": {\"cels\": 1, \"h\": 6, \"id\": 34, \"w\": 5},\n \"mem-prop-5x6--16\": {\"cels\": 1, \"h\": 6, \"id\": 35, \"w\": 5},\n \"mem-prop-5x6--17\": {\"cels\": 1, \"h\": 6, \"id\": 36, \"w\": 5},\n \"mem-prop-5x6--18\": {\"cels\": 1, \"h\": 6, \"id\": 37, \"w\": 5},\n \"mem-prop-5x6--19\": {\"cels\": 1, \"h\": 6, \"id\": 38, \"w\": 5},\n \"mem-prop-5x6--1a\": {\"cels\": 1, \"h\": 6, \"id\": 39, \"w\": 5},\n \"mem-prop-5x6--1b\": {\"cels\": 1, \"h\": 6, \"id\": 40, \"w\": 5},\n \"mem-prop-5x6--1c\": {\"cels\": 1, \"h\": 6, \"id\": 41, \"w\": 5},\n \"mem-prop-5x6--1d\": {\"cels\": 1, \"h\": 6, \"id\": 42, \"w\": 5},\n \"mem-prop-5x6--1e\": {\"cels\": 1, \"h\": 6, \"id\": 43, \"w\": 5},\n \"mem-prop-5x6--1f\": {\"cels\": 1, \"h\": 6, \"id\": 44, \"w\": 5},\n \"mem-prop-5x6--20\": {\"cels\": 1, \"h\": 6, \"id\": 45, \"w\": 5},\n \"mem-prop-5x6--21\": {\"cels\": 1, \"h\": 6, \"id\": 46, \"w\": 5},\n \"mem-prop-5x6--22\": {\"cels\": 1, \"h\": 6, \"id\": 47, \"w\": 5},\n \"mem-prop-5x6--23\": {\"cels\": 1, \"h\": 6, \"id\": 48, \"w\": 5},\n \"mem-prop-5x6--24\": {\"cels\": 1, \"h\": 6, \"id\": 49, \"w\": 5},\n \"mem-prop-5x6--25\": {\"cels\": 1, \"h\": 6, \"id\": 50, \"w\": 5},\n \"mem-prop-5x6--26\": {\"cels\": 1, \"h\": 6, \"id\": 51, \"w\": 5},\n \"mem-prop-5x6--27\": {\"cels\": 1, \"h\": 6, \"id\": 52, \"w\": 5},\n \"mem-prop-5x6--28\": {\"cels\": 1, \"h\": 6, \"id\": 53, \"w\": 5},\n \"mem-prop-5x6--29\": {\"cels\": 1, \"h\": 6, \"id\": 54, \"w\": 5},\n \"mem-prop-5x6--2a\": {\"cels\": 1, \"h\": 6, \"id\": 55, \"w\": 5},\n \"mem-prop-5x6--2b\": {\"cels\": 1, \"h\": 6, \"id\": 56, \"w\": 5},\n \"mem-prop-5x6--2c\": {\"cels\": 1, \"h\": 6, \"id\": 57, \"w\": 5},\n \"mem-prop-5x6--2d\": {\"cels\": 1, \"h\": 6, \"id\": 58, \"w\": 5},\n \"mem-prop-5x6--2e\": {\"cels\": 1, \"h\": 6, \"id\": 59, \"w\": 5},\n \"mem-prop-5x6--2f\": {\"cels\": 1, \"h\": 6, \"id\": 60, \"w\": 5},\n \"mem-prop-5x6--30\": {\"cels\": 1, \"h\": 6, \"id\": 61, \"w\": 5},\n \"mem-prop-5x6--31\": {\"cels\": 1, \"h\": 6, \"id\": 62, \"w\": 5},\n \"mem-prop-5x6--32\": {\"cels\": 1, \"h\": 6, \"id\": 63, \"w\": 5},\n \"mem-prop-5x6--33\": {\"cels\": 1, \"h\": 6, \"id\": 64, \"w\": 5},\n \"mem-prop-5x6--34\": {\"cels\": 1, \"h\": 6, \"id\": 65, \"w\": 5},\n \"mem-prop-5x6--35\": {\"cels\": 1, \"h\": 6, \"id\": 66, \"w\": 5},\n \"mem-prop-5x6--36\": {\"cels\": 1, \"h\": 6, \"id\": 67, \"w\": 5},\n \"mem-prop-5x6--37\": {\"cels\": 1, \"h\": 6, \"id\": 68, \"w\": 5},\n \"mem-prop-5x6--38\": {\"cels\": 1, \"h\": 6, \"id\": 69, \"w\": 5},\n \"mem-prop-5x6--39\": {\"cels\": 1, \"h\": 6, \"id\": 70, \"w\": 5},\n \"mem-prop-5x6--3a\": {\"cels\": 1, \"h\": 6, \"id\": 71, \"w\": 5},\n \"mem-prop-5x6--3b\": {\"cels\": 1, \"h\": 6, \"id\": 72, \"w\": 5},\n \"mem-prop-5x6--3c\": {\"cels\": 1, \"h\": 6, \"id\": 73, \"w\": 5},\n \"mem-prop-5x6--3d\": {\"cels\": 1, \"h\": 6, \"id\": 74, \"w\": 5},\n \"mem-prop-5x6--3e\": {\"cels\": 1, \"h\": 6, \"id\": 75, \"w\": 5},\n \"mem-prop-5x6--3f\": {\"cels\": 1, \"h\": 6, \"id\": 76, \"w\": 5},\n \"mem-prop-5x6--40\": {\"cels\": 1, \"h\": 6, \"id\": 77, \"w\": 5},\n \"mem-prop-5x6--41\": {\"cels\": 1, \"h\": 6, \"id\": 78, \"w\": 5},\n \"mem-prop-5x6--42\": {\"cels\": 1, \"h\": 6, \"id\": 79, \"w\": 5},\n \"mem-prop-5x6--43\": {\"cels\": 1, \"h\": 6, \"id\": 80, \"w\": 5},\n \"mem-prop-5x6--44\": {\"cels\": 1, \"h\": 6, \"id\": 81, \"w\": 5},\n \"mem-prop-5x6--45\": {\"cels\": 1, \"h\": 6, \"id\": 82, \"w\": 5},\n \"mem-prop-5x6--46\": {\"cels\": 1, \"h\": 6, \"id\": 83, \"w\": 5},\n \"mem-prop-5x6--47\": {\"cels\": 1, \"h\": 6, \"id\": 84, \"w\": 5},\n \"mem-prop-5x6--48\": {\"cels\": 1, \"h\": 6, \"id\": 85, \"w\": 5},\n \"mem-prop-5x6--49\": {\"cels\": 1, \"h\": 6, \"id\": 86, \"w\": 5},\n \"mem-prop-5x6--4a\": {\"cels\": 1, \"h\": 6, \"id\": 87, \"w\": 5},\n \"mem-prop-5x6--4b\": {\"cels\": 1, \"h\": 6, \"id\": 88, \"w\": 5},\n \"mem-prop-5x6--4c\": {\"cels\": 1, \"h\": 6, \"id\": 89, \"w\": 5},\n \"mem-prop-5x6--4d\": {\"cels\": 1, \"h\": 6, \"id\": 90, \"w\": 5},\n \"mem-prop-5x6--4e\": {\"cels\": 1, \"h\": 6, \"id\": 91, \"w\": 5},\n \"mem-prop-5x6--4f\": {\"cels\": 1, \"h\": 6, \"id\": 92, \"w\": 5},\n \"mem-prop-5x6--50\": {\"cels\": 1, \"h\": 6, \"id\": 93, \"w\": 5},\n \"mem-prop-5x6--51\": {\"cels\": 1, \"h\": 6, \"id\": 94, \"w\": 5},\n \"mem-prop-5x6--52\": {\"cels\": 1, \"h\": 6, \"id\": 95, \"w\": 5},\n \"mem-prop-5x6--53\": {\"cels\": 1, \"h\": 6, \"id\": 96, \"w\": 5},\n \"mem-prop-5x6--54\": {\"cels\": 1, \"h\": 6, \"id\": 97, \"w\": 5},\n \"mem-prop-5x6--55\": {\"cels\": 1, \"h\": 6, \"id\": 98, \"w\": 5},\n \"mem-prop-5x6--56\": {\"cels\": 1, \"h\": 6, \"id\": 99, \"w\": 5},\n \"mem-prop-5x6--57\": {\"cels\": 1, \"h\": 6, \"id\": 100, \"w\": 5},\n \"mem-prop-5x6--58\": {\"cels\": 1, \"h\": 6, \"id\": 101, \"w\": 5},\n \"mem-prop-5x6--59\": {\"cels\": 1, \"h\": 6, \"id\": 102, \"w\": 5},\n \"mem-prop-5x6--5a\": {\"cels\": 1, \"h\": 6, \"id\": 103, \"w\": 5},\n \"mem-prop-5x6--5b\": {\"cels\": 1, \"h\": 6, \"id\": 104, \"w\": 5},\n \"mem-prop-5x6--5c\": {\"cels\": 1, \"h\": 6, \"id\": 105, \"w\": 5},\n \"mem-prop-5x6--5d\": {\"cels\": 1, \"h\": 6, \"id\": 106, \"w\": 5},\n \"mem-prop-5x6--5e\": {\"cels\": 1, \"h\": 6, \"id\": 107, \"w\": 5},\n \"mem-prop-5x6--5f\": {\"cels\": 1, \"h\": 6, \"id\": 108, \"w\": 5},\n \"mem-prop-5x6--60\": {\"cels\": 1, \"h\": 6, \"id\": 109, \"w\": 5},\n \"mem-prop-5x6--61\": {\"cels\": 1, \"h\": 6, \"id\": 110, \"w\": 5},\n \"mem-prop-5x6--62\": {\"cels\": 1, \"h\": 6, \"id\": 111, \"w\": 5},\n \"mem-prop-5x6--63\": {\"cels\": 1, \"h\": 6, \"id\": 112, \"w\": 5},\n \"mem-prop-5x6--64\": {\"cels\": 1, \"h\": 6, \"id\": 113, \"w\": 5},\n \"mem-prop-5x6--65\": {\"cels\": 1, \"h\": 6, \"id\": 114, \"w\": 5},\n \"mem-prop-5x6--66\": {\"cels\": 1, \"h\": 6, \"id\": 115, \"w\": 5},\n \"mem-prop-5x6--67\": {\"cels\": 1, \"h\": 6, \"id\": 116, \"w\": 5},\n \"mem-prop-5x6--68\": {\"cels\": 1, \"h\": 6, \"id\": 117, \"w\": 5},\n \"mem-prop-5x6--69\": {\"cels\": 1, \"h\": 6, \"id\": 118, \"w\": 5},\n \"mem-prop-5x6--6a\": {\"cels\": 1, \"h\": 6, \"id\": 119, \"w\": 5},\n \"mem-prop-5x6--6b\": {\"cels\": 1, \"h\": 6, \"id\": 120, \"w\": 5},\n \"mem-prop-5x6--6c\": {\"cels\": 1, \"h\": 6, \"id\": 121, \"w\": 5},\n \"mem-prop-5x6--6d\": {\"cels\": 1, \"h\": 6, \"id\": 122, \"w\": 5},\n \"mem-prop-5x6--6e\": {\"cels\": 1, \"h\": 6, \"id\": 123, \"w\": 5},\n \"mem-prop-5x6--6f\": {\"cels\": 1, \"h\": 6, \"id\": 124, \"w\": 5},\n \"mem-prop-5x6--70\": {\"cels\": 1, \"h\": 6, \"id\": 125, \"w\": 5},\n \"mem-prop-5x6--71\": {\"cels\": 1, \"h\": 6, \"id\": 126, \"w\": 5},\n \"mem-prop-5x6--72\": {\"cels\": 1, \"h\": 6, \"id\": 127, \"w\": 5},\n \"mem-prop-5x6--73\": {\"cels\": 1, \"h\": 6, \"id\": 128, \"w\": 5},\n \"mem-prop-5x6--74\": {\"cels\": 1, \"h\": 6, \"id\": 129, \"w\": 5},\n \"mem-prop-5x6--75\": {\"cels\": 1, \"h\": 6, \"id\": 130, \"w\": 5},\n \"mem-prop-5x6--76\": {\"cels\": 1, \"h\": 6, \"id\": 131, \"w\": 5},\n \"mem-prop-5x6--77\": {\"cels\": 1, \"h\": 6, \"id\": 132, \"w\": 5},\n \"mem-prop-5x6--78\": {\"cels\": 1, \"h\": 6, \"id\": 133, \"w\": 5},\n \"mem-prop-5x6--79\": {\"cels\": 1, \"h\": 6, \"id\": 134, \"w\": 5},\n \"mem-prop-5x6--7a\": {\"cels\": 1, \"h\": 6, \"id\": 135, \"w\": 5},\n \"mem-prop-5x6--7b\": {\"cels\": 1, \"h\": 6, \"id\": 136, \"w\": 5},\n \"mem-prop-5x6--7c\": {\"cels\": 1, \"h\": 6, \"id\": 137, \"w\": 5},\n \"mem-prop-5x6--7d\": {\"cels\": 1, \"h\": 6, \"id\": 138, \"w\": 5},\n \"mem-prop-5x6--7e\": {\"cels\": 1, \"h\": 6, \"id\": 139, \"w\": 5},\n \"mem-prop-5x6--7f\": {\"cels\": 1, \"h\": 6, \"id\": 140, \"w\": 5},\n \"oidoid--Default\": {\"cels\": 1, \"h\": 16, \"id\": 141, \"w\": 16}\n },\n \"celXY\": [\n 22, 37, 21, 27, 21, 29, 21, 31, 20, 33, 22, 33, 20, 35, 22, 35, 20, 37, 24,\n 26, 24, 26, 8, 16, 8, 16, 0, 16, 0, 16, 16, 14, 16, 14, 72, 13, 72, 13, 32,\n 26, 32, 26, 0, 16, 0, 16, 64, 13, 64, 13, 56, 13, 56, 13, 48, 13, 48, 13,\n 40, 13, 40, 13, 32, 13, 32, 13, 56, 13, 56, 13, 24, 13, 24, 13, 72, 0, 72,\n 0, 64, 0, 64, 0, 24, 0, 24, 0, 56, 0, 56, 0, 48, 0, 48, 0, 48, 0, 48, 0, 24,\n 0, 24, 0, 40, 0, 40, 0, 32, 0, 32, 0, 32, 0, 32, 0, 16, 0, 45, 56, 45, 56,\n 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45,\n 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56,\n 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45,\n 56, 45, 56, 45, 56, 40, 56, 10, 53, 5, 53, 0, 53, 35, 51, 30, 51, 25, 51,\n 20, 51, 15, 51, 35, 45, 70, 50, 65, 50, 60, 50, 55, 50, 50, 50, 45, 50, 40,\n 50, 10, 47, 5, 47, 0, 47, 70, 62, 50, 56, 65, 62, 60, 62, 55, 62, 50, 62,\n 45, 62, 40, 62, 10, 59, 5, 59, 0, 59, 35, 57, 70, 32, 30, 57, 25, 57, 20,\n 57, 15, 57, 75, 56, 70, 56, 65, 56, 60, 56, 75, 50, 55, 56, 10, 35, 75, 32,\n 15, 33, 0, 35, 5, 35, 40, 38, 45, 38, 65, 32, 60, 32, 55, 32, 50, 32, 45,\n 32, 40, 26, 50, 26, 55, 26, 60, 26, 65, 26, 70, 26, 75, 26, 16, 27, 0, 29,\n 5, 29, 10, 29, 40, 32, 45, 26, 10, 41, 30, 45, 25, 45, 20, 45, 15, 45, 75,\n 44, 70, 44, 65, 44, 60, 44, 55, 44, 50, 44, 45, 44, 40, 44, 50, 38, 5, 41,\n 0, 41, 35, 39, 30, 39, 25, 39, 20, 39, 15, 39, 75, 38, 70, 38, 65, 38, 60,\n 38, 55, 38, 45, 56, 0, 0\n ]\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\nexport class ClockEnt implements V.Ent<Tag> {\n readonly #time: V.TextEnt = new V.TextEnt()\n\n constructor() {\n this.#time.scale = 3\n this.#time.z = V.Layer.A\n }\n\n free(v: Game): void {\n this.#time.free(v)\n }\n\n update(v: Game): boolean | undefined {\n const now = new Date()\n this.#time.text = timeString(now)\n\n if (this.#time.layout(v) || v.cam.invalid)\n this.#time.xy = v.cam.follow(\n {w: this.#time.wh.w, h: this.#time.wh.h - this.#time.scaledLeading},\n this.#time.z,\n 'N',\n {margin: {h: 8}}\n )\n\n return this.#time.update(v)\n }\n}\n\n/** @internal */\nexport function timeString(time: Readonly<Date>): string {\n const hh = `${time.getHours() % 12 || 12}`.padStart(2, ' ')\n const mm = `${time.getMinutes()}`.padStart(2, '0')\n const ss = `${time.getSeconds()}`.padStart(2, '0')\n return `${hh}:${mm}:${ss}`\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\n// to-do: follow cam sw.\nexport class RenderToggleEnt implements V.Ent<Tag> {\n readonly #toggle: V.ButtonEnt<Tag, V.DefaultButton>\n\n constructor(v: Game) {\n this.#toggle = new V.ButtonEnt(v, {\n button: {\n w: {tag: 'background--Strawberry'},\n nw: {tag: 'background--Transparent'},\n n: {tag: 'background--Bubblegum'},\n e: {tag: 'background--Blueberry'},\n s: {tag: 'background--Kiwi'},\n origin: {tag: 'background--Grape'},\n border: {n: 1},\n margin: {w: 2, h: 2}\n },\n selected: {tag: 'background--OrangeCheckerboard'},\n toggle: true,\n text: {text: 'render', scale: 2},\n w: 64,\n h: 22,\n x: 50,\n y: 25,\n pressed: {tag: 'background--Bubblegum'}\n })\n }\n\n get on(): boolean {\n return this.#toggle.on\n }\n\n set on(on: boolean) {\n this.#toggle.on = on\n }\n\n free(v: Game): void {\n this.#toggle.free(v)\n }\n\n /** always updates but never invalidates. */\n update(v: Game): boolean | undefined {\n return this.#toggle.update(v)\n }\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\nexport class WorkCounterEnt implements V.Ent<Tag> {\n readonly #text: V.TextEnt = new V.TextEnt()\n #updates: number = 0\n\n constructor() {\n this.#text.z = V.Layer.A\n }\n\n free(v: Game): void {\n this.#text.free(v)\n }\n\n /** always updates but never invalidates. */\n update(v: Game): undefined {\n this.#updates++\n this.#text.text = `${this.#updates} updates\\n${v.renderer.clears + 1} renders`\n this.#text.layout(v)\n this.#text.xy = v.cam.follow(\n {w: this.#text.wh.w, h: this.#text.wh.h - this.#text.scaledLeading},\n this.#text.z,\n 'NE',\n {margin: {w: 8, h: 8}}\n )\n this.#text.update(v)\n }\n}\n", "import * as V from '../index.ts'\nimport preloadAtlasJSON from './assets/preload-atlas.json' with {type: 'json'}\nimport {ClockEnt} from './ents/clock-ent.ts'\nimport {RenderToggleEnt} from './ents/render-toggle-ent.ts'\nimport {WorkCounterEnt} from './ents/work-counter-ent.ts'\nimport type {Tag} from './types/tag.ts'\n\nexport class Game extends V.Void<Tag> {\n #filterSprites: V.Pool<V.Sprite<Tag>>\n #renderToggle: RenderToggleEnt\n #workCounter: WorkCounterEnt\n\n constructor() {\n super({\n preloadAtlas: {\n image: document.querySelector('#preload-atlas')!,\n json: preloadAtlasJSON\n },\n backgroundRGBA: 0xffffb1ff,\n minWH: {w: 320, h: 240},\n poll: {\n delay: () => renderDelayMillis(new Date(), V.debug?.seconds),\n period: ((V.debug?.seconds ? 1 : 60) * 1000) as V.Millis\n }\n })\n this.#filterSprites = new V.Pool<V.Sprite<Tag>>({\n alloc: pool => new V.Sprite(pool, 0, this.preload, this.looper),\n allocBytes: V.drawableBytes,\n pageBlocks: 10\n })\n this.#renderToggle = new RenderToggleEnt(this)\n this.#renderToggle.on = this.renderer.always\n this.#workCounter = new WorkCounterEnt()\n this.#initZoo()\n }\n\n override onLoop(_millis: V.Millis): void {\n if (V.debug?.input) this.#printInput()\n this.renderer.always = this.#renderToggle.on\n\n let render = this.#updateCam()\n this.zoo.update(this)\n\n render ||=\n this.zoo.invalid ||\n this.cam.invalid ||\n this.renderer.invalid ||\n this.renderer.always\n if (render) {\n this.renderer.clear(0xffffb1ff)\n this.renderer.predraw(this.cam)\n this.renderer.setDepth(true)\n this.renderer.draw(this.sprites)\n this.renderer.setDepth(false)\n this.renderer.draw(this.#filterSprites)\n }\n }\n\n #initZoo(): void {\n const border = new V.NinePatchEnt<Tag>(this, {\n n: {tag: 'background--Black'},\n origin: {tag: 'background--Transparent'},\n border: {n: 1},\n z: V.Layer.UIA\n })\n this.zoo.add(border)\n const box = this.cam.follow({w: 0, h: 0}, V.Layer.UIA, 'NW', {fill: 'XY'})\n border.xy = box\n border.wh = box\n\n const backpacker = this.sprites.alloc()\n backpacker.tag = 'backpacker--WalkRight'\n backpacker.x = 7\n backpacker.y = 7\n backpacker.z = V.Layer.C\n backpacker.stretch = true\n backpacker.w *= 5\n backpacker.h *= 5\n\n const oidoid = new V.FollowCamEnt(this, 'oidoid--Default', 'SW')\n oidoid.z = V.Layer.UIG\n oidoid.margin = {w: 4, h: 4}\n\n this.zoo.add(\n new V.CursorEnt(this, 'cursor--Pointer'),\n this.#renderToggle,\n new ClockEnt(),\n this.#workCounter,\n oidoid\n )\n\n const overlay = this.#filterSprites.alloc()\n overlay.tag = 'background--GreyCheckerboard'\n overlay.w = V.drawableMaxWH.w\n overlay.h = V.drawableMaxWH.h\n overlay.z = V.Layer.UIA\n }\n\n #printInput(): void {\n if (this.input.started) {\n const on = !!this.input.on.length\n if (on) console.debug(`[input] buttons on: ${this.input.on.join(' ')}.`)\n else console.debug(`[input] buttons off.`)\n const combo = this.input.combo\n if (combo.length > 1 && on)\n console.debug(\n `[input] combo: ${combo.map(set => set.join('+')).join(' ')}.`\n )\n }\n if (\n this.input.point?.invalid &&\n this.input.point?.click &&\n !this.input.point.pinch\n )\n console.debug(\n `[input] ${this.input.point.drag.on ? 'drag' : 'click'} xy: ${this.input.point.x} ${this.input.point.y}.`\n )\n if (this.input.point?.pinch)\n console.debug(\n `[input] pinch xy: ${this.input.point.pinch.xy.x} ${this.input.point.pinch.xy.y}.`\n )\n if (this.input.wheel)\n console.debug(\n `[input] wheel xy: ${this.input.wheel.delta.xy.x} ${this.input.wheel.delta.xy.y}.`\n )\n }\n\n #updateCam(): boolean {\n let render = this.input.isAnyOn('L', 'R', 'U', 'D')\n\n if (this.input.isAnyOnStart('L', 'R', 'U', 'D')) {\n this.cam.x = Math.trunc(this.cam.x)\n this.cam.y = Math.trunc(this.cam.y)\n }\n\n const d = 1 / 4\n if (this.input.isOn('L')) this.cam.x -= d\n if (this.input.isOn('R')) this.cam.x += d\n if (this.input.isOn('U')) this.cam.y -= d\n if (this.input.isOn('D')) this.cam.y += d\n\n if (this.input.wheel?.delta.xy.y) {\n render = true\n this.cam.zoomOut -= this.input.wheel.delta.client.y * 0.01\n }\n\n this.cam.update(this.canvas)\n\n return render\n }\n}\n\n/**\n * returns [0, 59_999].\n * @internal\n */\nexport function renderDelayMillis(\n time: Readonly<Date>,\n debugSecs: string | undefined\n): V.Millis {\n return (((debugSecs ? 0 : (59 - (time.getSeconds() % 60)) * 1000) +\n 1000 -\n (time.getMilliseconds() % 1000)) %\n (debugSecs ? 1000 : 60_000)) as V.Millis\n}\n", "import * as V from '../index.ts'\nimport {Game} from './game.ts'\n\nconsole.debug(`void v${V.version} \u2500\u2500\u2500oidoid>\u00B0\u2500\u2500`)\n\nconst v = new Game()\nawait v.register('add')\nif (V.debug) (globalThis as unknown as {v: Game}).v = v\n"],
|
|
4
|
+
"sourcesContent": ["{\"published\":\"20251022\",\"version\":\"0.1.0-8\"}", "export type VoidVersion = {\n /** package.json `published` YYYYMMDD. */\n published: string\n /** package.json semantic `version`. */\n version: string\n}\n\ndeclare namespace globalThis {\n var voidVersion: VoidVersion // set by esbuild.\n}\n\nexport const voidVersion: VoidVersion = globalThis.voidVersion\n", "{\n \"id\": \"mem-prop-5x6\",\n \"name\": \"mem 5x6\",\n \"cellWidth\": 5,\n \"cellHeight\": 6,\n \"leading\": 1,\n \"lineHeight\": 7,\n \"baseline\": 1,\n \"kerning\": {\n \" 0\": 0,\n \" 1\": 0,\n \" 2\": 0,\n \" 3\": 0,\n \" 4\": 0,\n \" 5\": 0,\n \" 6\": 0,\n \" 7\": 0,\n \" 8\": 0,\n \" 9\": 0,\n \"##\": -1,\n \"#_\": 0,\n \"',\": 0,\n \"'.\": 0,\n \"'/\": 0,\n \"'J\": 0,\n \"'S\": 0,\n \"'_\": 0,\n \"'j\": 0,\n \"'s\": 0,\n \"(+\": 0,\n \"(-\": 0,\n \"(<\": 0,\n \"(f\": 0,\n \"({\": 0,\n \"(~\": 0,\n \")_\": 0,\n \"*,\": 0,\n \"*.\": 0,\n \"*/\": 0,\n \"*S\": 0,\n \"*_\": 0,\n \"*j\": 0,\n \"*s\": 0,\n \"+)\": 0,\n \"+,\": 0,\n \"+.\": 0,\n \"+/\": 0,\n \"+>\": 0,\n \"+?\": 0,\n \"+I\": 0,\n \"+S\": 0,\n \"+T\": 0,\n \"+Z\": 0,\n \"+]\": 0,\n \"+_\": 0,\n \"+`\": 0,\n \"+j\": 0,\n \"+s\": 0,\n \"+}\": 0,\n \",'\": 0,\n \",*\": 0,\n \",+\": 0,\n \",-\": 0,\n \",<\": 0,\n \",?\": 0,\n \",T\": 0,\n \",Y\": 0,\n \",Z\": 0,\n \",\\\"\": 0,\n \",\\\\\": 0,\n \",^\": 0,\n \",`\": 0,\n \",f\": 0,\n \",t\": 0,\n \",z\": 0,\n \",{\": 0,\n \",~\": 0,\n \"-)\": 0,\n \"-,\": 0,\n \"--\": 0,\n \"-.\": 0,\n \"-/\": 0,\n \"->\": 0,\n \"-?\": 0,\n \"-I\": 0,\n \"-S\": 0,\n \"-T\": 0,\n \"-Z\": 0,\n \"-]\": 0,\n \"-_\": 0,\n \"-`\": 0,\n \"-j\": 0,\n \"-s\": 0,\n \"-}\": 0,\n \".'\": 0,\n \".*\": 0,\n \".+\": 0,\n \".-\": 0,\n \".<\": 0,\n \".?\": 0,\n \".T\": 0,\n \".Y\": 0,\n \".Z\": 0,\n \".\\\"\": 0,\n \".\\\\\": 0,\n \".^\": 0,\n \".`\": 0,\n \".f\": 0,\n \".t\": 0,\n \".z\": 0,\n \".{\": 0,\n \".~\": 0,\n \"/,\": 0,\n \"/.\": 0,\n \"//\": 0,\n \"/J\": 0,\n \"/S\": 0,\n \"/_\": 0,\n \"/j\": 0,\n \"/s\": 0,\n \"0 \": 0,\n \"1 \": 0,\n \"1T\": 0,\n \"1Y\": 0,\n \"1Z\": 0,\n \"1f\": 0,\n \"1t\": 0,\n \"1z\": 0,\n \"2 \": 0,\n \"3 \": 0,\n \"4 \": 0,\n \"5 \": 0,\n \"6 \": 0,\n \"7 \": 0,\n \"8 \": 0,\n \"9 \": 0,\n \":?\": 0,\n \":T\": 0,\n \":Z\": 0,\n \":`\": 0,\n \";?\": 0,\n \";T\": 0,\n \";Z\": 0,\n \"<+\": 0,\n \"<-\": 0,\n \"<<\": 0,\n \"<f\": 0,\n \"<{\": 0,\n \"<~\": 0,\n \"==\": 0,\n \"=_\": 0,\n \">)\": 0,\n \">,\": 0,\n \">.\": 0,\n \">/\": 0,\n \">>\": 0,\n \">?\": 0,\n \">I\": 0,\n \">S\": 0,\n \">T\": 0,\n \">Z\": 0,\n \">]\": 0,\n \">_\": 0,\n \">`\": 0,\n \">j\": 0,\n \">s\": 0,\n \">}\": 0,\n \"?,\": 0,\n \"?.\": 0,\n \"?/\": 0,\n \"?S\": 0,\n \"?_\": 0,\n \"?j\": 0,\n \"?s\": 0,\n \"@_\": 0,\n \"C+\": 0,\n \"C-\": 0,\n \"C<\": 0,\n \"Cf\": 0,\n \"C{\": 0,\n \"C~\": 0,\n \"D_\": 0,\n \"E+\": 0,\n \"E-\": 0,\n \"E<\": 0,\n \"Ef\": 0,\n \"E{\": 0,\n \"E~\": 0,\n \"F&\": 0,\n \"F+\": 0,\n \"F,\": 0,\n \"F-\": 0,\n \"F.\": 0,\n \"F/\": 0,\n \"F:\": 0,\n \"F;\": 0,\n \"F<\": 0,\n \"FJ\": 0,\n \"FS\": 0,\n \"F_\": 0,\n \"Fa\": 0,\n \"Fe\": 0,\n \"Ff\": 0,\n \"Fg\": 0,\n \"Fj\": 0,\n \"Fq\": 0,\n \"Fs\": 0,\n \"F{\": 0,\n \"F~\": 0,\n \"I+\": 0,\n \"I-\": 0,\n \"I<\": 0,\n \"If\": 0,\n \"I{\": 0,\n \"I~\": 0,\n \"L'\": 0,\n \"L*\": 0,\n \"L+\": 0,\n \"L-\": 0,\n \"L4\": 0,\n \"L7\": 0,\n \"L<\": 0,\n \"L?\": 0,\n \"LT\": 0,\n \"LY\": 0,\n \"LZ\": 0,\n \"L\\\"\": 0,\n \"L\\\\\": 0,\n \"L^\": 0,\n \"L`\": 0,\n \"Lf\": 0,\n \"Lt\": 0,\n \"Lz\": 0,\n \"L{\": 0,\n \"L~\": 0,\n \"P,\": 0,\n \"P.\": 0,\n \"P/\": 0,\n \"PS\": 0,\n \"P_\": 0,\n \"Pj\": 0,\n \"Ps\": 0,\n \"S&\": 0,\n \"S+\": 0,\n \"S,\": 0,\n \"S-\": 0,\n \"S.\": 0,\n \"S/\": 0,\n \"S:\": 0,\n \"S;\": 0,\n \"S<\": 0,\n \"SJ\": 0,\n \"SS\": 0,\n \"S_\": 0,\n \"Sa\": 0,\n \"Se\": 0,\n \"Sf\": 0,\n \"Sg\": 0,\n \"Sj\": 0,\n \"Sq\": 0,\n \"Ss\": 0,\n \"S{\": 0,\n \"S~\": 0,\n \"T&\": 0,\n \"T+\": 0,\n \"T,\": 0,\n \"T-\": 0,\n \"T.\": 0,\n \"T/\": 0,\n \"T:\": 0,\n \"T;\": 0,\n \"T<\": 0,\n \"TJ\": 0,\n \"TS\": 0,\n \"T_\": 0,\n \"Ta\": 0,\n \"Te\": 0,\n \"Tf\": 0,\n \"Tg\": 0,\n \"Tj\": 0,\n \"Tq\": 0,\n \"Ts\": 0,\n \"T{\": 0,\n \"T~\": 0,\n \"V_\": 0,\n \"Y,\": 0,\n \"Y.\": 0,\n \"Y/\": 0,\n \"YS\": 0,\n \"Y_\": 0,\n \"Yj\": 0,\n \"Ys\": 0,\n \"Z'\": 0,\n \"Z*\": 0,\n \"Z+\": 0,\n \"Z-\": 0,\n \"Z4\": 0,\n \"Z7\": 0,\n \"Z<\": 0,\n \"Z?\": 0,\n \"ZT\": 0,\n \"ZY\": 0,\n \"ZZ\": 0,\n \"Z\\\"\": 0,\n \"Z\\\\\": 0,\n \"Z^\": 0,\n \"Z`\": 0,\n \"Zf\": 0,\n \"Zt\": 0,\n \"Zz\": 0,\n \"Z{\": 0,\n \"Z~\": 0,\n \"[+\": 0,\n \"[-\": 0,\n \"[<\": 0,\n \"[f\": 0,\n \"[{\": 0,\n \"[~\": 0,\n \"\\\",\": 0,\n \"\\\".\": 0,\n \"\\\"/\": 0,\n \"\\\"J\": 0,\n \"\\\"S\": 0,\n \"\\\"_\": 0,\n \"\\\"j\": 0,\n \"\\\"s\": 0,\n \"\\\\'\": 0,\n \"\\\\*\": 0,\n \"\\\\+\": 0,\n \"\\\\-\": 0,\n \"\\\\<\": 0,\n \"\\\\?\": 0,\n \"\\\\T\": 0,\n \"\\\\Y\": 0,\n \"\\\\Z\": 0,\n \"\\\\\\\"\": 0,\n \"\\\\\\\\\": 0,\n \"\\\\^\": 0,\n \"\\\\`\": 0,\n \"\\\\f\": 0,\n \"\\\\t\": 0,\n \"\\\\z\": 0,\n \"\\\\{\": 0,\n \"\\\\~\": 0,\n \"^,\": 0,\n \"^.\": 0,\n \"^/\": 0,\n \"^J\": 0,\n \"^S\": 0,\n \"^_\": 0,\n \"^j\": 0,\n \"^s\": 0,\n \"_#\": 0,\n \"_%\": 0,\n \"_'\": 0,\n \"_(\": 0,\n \"_*\": 0,\n \"_+\": 0,\n \"_-\": 0,\n \"_<\": 0,\n \"_=\": 0,\n \"_?\": 0,\n \"_@\": 0,\n \"_T\": 0,\n \"_V\": 0,\n \"_Y\": 0,\n \"_Z\": 0,\n \"_\\\"\": 0,\n \"_\\\\\": 0,\n \"_^\": 0,\n \"__\": 0,\n \"_`\": 0,\n \"_a\": 0,\n \"_e\": 0,\n \"_f\": 0,\n \"_t\": 0,\n \"_v\": 0,\n \"_z\": 0,\n \"_{\": 0,\n \"_~\": 0,\n \"`,\": 0,\n \"`.\": 0,\n \"`/\": 0,\n \"`J\": 0,\n \"`S\": 0,\n \"`_\": 0,\n \"`j\": 0,\n \"`s\": 0,\n \"f,\": 0,\n \"f.\": 0,\n \"f/\": 0,\n \"fS\": 0,\n \"f_\": 0,\n \"fj\": 0,\n \"fs\": 0,\n \"q#\": 0,\n \"q$\": 0,\n \"q%\": 0,\n \"q&\": 0,\n \"q'\": 0,\n \"q(\": 0,\n \"q*\": 0,\n \"q+\": 0,\n \"q-\": 0,\n \"q0\": 0,\n \"q1\": 0,\n \"q2\": 0,\n \"q3\": 0,\n \"q4\": 0,\n \"q5\": 0,\n \"q6\": 0,\n \"q7\": 0,\n \"q8\": 0,\n \"q9\": 0,\n \"q<\": 0,\n \"q=\": 0,\n \"q?\": 0,\n \"q@\": 0,\n \"qA\": 0,\n \"qB\": 0,\n \"qC\": 0,\n \"qD\": 0,\n \"qE\": 0,\n \"qF\": 0,\n \"qG\": 0,\n \"qH\": 0,\n \"qI\": 0,\n \"qJ\": 0,\n \"qK\": 0,\n \"qL\": 0,\n \"qM\": 0,\n \"qN\": 0,\n \"qO\": 0,\n \"qP\": 0,\n \"qQ\": 0,\n \"qR\": 0,\n \"qS\": 0,\n \"qT\": 0,\n \"qU\": 0,\n \"qV\": 0,\n \"qW\": 0,\n \"qX\": 0,\n \"qY\": 0,\n \"qZ\": 0,\n \"q[\": 0,\n \"q\\\"\": 0,\n \"q\\\\\": 0,\n \"q]\": 0,\n \"q^\": 0,\n \"q`\": 0,\n \"qa\": 0,\n \"qb\": 0,\n \"qc\": 0,\n \"qd\": 0,\n \"qe\": 0,\n \"qf\": 0,\n \"qh\": 0,\n \"qk\": 0,\n \"qm\": 0,\n \"qn\": 0,\n \"qo\": 0,\n \"qq\": 0,\n \"qr\": 0,\n \"qs\": 0,\n \"qt\": 0,\n \"qu\": 0,\n \"qv\": 0,\n \"qw\": 0,\n \"qx\": 0,\n \"qz\": 0,\n \"q{\": 0,\n \"q}\": 0,\n \"q~\": 0,\n \"r,\": 0,\n \"r.\": 0,\n \"r/\": 0,\n \"rS\": 0,\n \"r_\": 0,\n \"rj\": -1,\n \"rs\": 0,\n \"s,\": 0,\n \"s.\": 0,\n \"s/\": 0,\n \"sJ\": 0,\n \"sS\": 0,\n \"s_\": 0,\n \"sj\": 0,\n \"ss\": 0,\n \"z'\": 0,\n \"z*\": 0,\n \"z+\": 0,\n \"z-\": 0,\n \"z4\": 0,\n \"z7\": 0,\n \"z<\": 0,\n \"z?\": 0,\n \"zT\": 0,\n \"zY\": 0,\n \"zZ\": 0,\n \"z\\\"\": 0,\n \"z\\\\\": 0,\n \"z^\": 0,\n \"z`\": 0,\n \"zf\": 0,\n \"zt\": 0,\n \"zz\": 0,\n \"z{\": 0,\n \"z~\": 0,\n \"{+\": 0,\n \"{-\": 0,\n \"{<\": 0,\n \"{f\": 0,\n \"{{\": 0,\n \"{~\": 0,\n \"})\": 0,\n \"},\": 0,\n \"}.\": 0,\n \"}/\": 0,\n \"}>\": 0,\n \"}?\": 0,\n \"}I\": 0,\n \"}S\": 0,\n \"}T\": 0,\n \"}Z\": 0,\n \"}]\": 0,\n \"}_\": 0,\n \"}`\": 0,\n \"}j\": 0,\n \"}s\": 0,\n \"}}\": 0,\n \"~'\": 0,\n \"~?\": 0,\n \"~T\": 0,\n \"~Z\": 0,\n \"~\\\"\": 0,\n \"~\\\\\": 0,\n \"~^\": 0,\n \"~_\": 0,\n \"~`\": 0,\n \"~t\": 0,\n \"~z\": 0\n },\n \"defaultKerning\": 1,\n \"defaultWhitespaceKerning\": -1,\n \"endOfLineKerning\": 0,\n \"charWidth\": {\n \" \": 4,\n \"!\": 1,\n \"#\": 5,\n \"&\": 4,\n \"'\": 1,\n \"(\": 2,\n \")\": 2,\n \",\": 1,\n \".\": 1,\n \":\": 1,\n \";\": 1,\n \"@\": 5,\n \"M\": 5,\n \"W\": 5,\n \"[\": 2,\n \"\\n\": 0,\n \"]\": 2,\n \"`\": 2,\n \"i\": 1,\n \"l\": 1,\n \"m\": 5,\n \"q\": 4,\n \"w\": 5,\n \"|\": 1\n },\n \"defaultCharWidth\": 3\n}\n", null, "export const Layer = {\n Top: 0,\n UIA: 1,\n UIB: 2,\n UIC: 3,\n UID: 4,\n UIE: 5,\n UIF: 6,\n UIG: 7,\n A: 8,\n B: 9,\n C: 10,\n D: 11,\n E: 12,\n F: 13,\n Bottom: 14,\n Hidden: 15\n} as const\nexport type Layer = (typeof Layer)[keyof typeof Layer]\n\n/** negative is above. returns [top, bottom]; hidden is out of domain. */\nexport function layerOffset(layer: Layer, offset: number): Layer {\n return Math.max(Layer.Top, Math.min(Layer.Bottom, layer + offset)) as Layer\n}\n", "export type Box = XY & WH\nexport type WH = {w: number; h: number}\nexport type XY = {x: number; y: number}\nexport type XYZ = {x: number; y: number; z: number}\n\nexport type CardinalDir = 'W' | 'N' | 'E' | 'S'\nexport type CompassDir = CardinalDir | 'NE' | 'SE' | 'SW' | 'NW' | 'Origin'\n\nexport function boxEq(l: Readonly<Box>, r: Readonly<Box>): boolean {\n return xyEq(l, r) && whEq(l, r)\n}\n\nexport function boxHits(\n l: Readonly<Partial<XY> & WH>,\n r: Readonly<XY & Partial<WH>>\n): boolean {\n const rWH = {w: r.w ?? 1, h: r.h ?? 1} // point? an empty box has no w/h.\n if (!l.w || !l.h || !rWH.w || !rWH.h) return false // noncommutative.\n const lXY = {x: l.x ?? 0, y: l.y ?? 0}\n return (\n lXY.x < r.x + rWH.w &&\n lXY.x + l.w > r.x &&\n lXY.y < r.y + rWH.h &&\n lXY.y + l.h > r.y\n )\n}\n\nexport function whAssign(l: WH, r: Readonly<WH>): void {\n l.w = r.w\n l.h = r.h\n}\n\nexport function whEq(l: Readonly<WH>, r: Readonly<WH>): boolean {\n return l.w === r.w && l.h === r.h\n}\n\n/** l + r. */\nexport function xyAdd(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x + r.x, y: l.y + r.y}\n}\n\n/** l += r. */\nexport function xyAddTo(l: XY, r: Readonly<XY>): void {\n l.x += r.x\n l.y += r.y\n}\n\nexport function xyAssign(l: XY, r: Readonly<XY>): void {\n l.x = r.x\n l.y = r.y\n}\n\n/** nonnegative. */\nexport function xyDistance(from: Readonly<XY>, to: Readonly<XY>): number {\n return xyMagnitude(xySub(from, to))\n}\n\n/** l / r. */\nexport function xyDiv(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x / r.x, y: l.y / r.y}\n}\n\nexport function xyEq(l: Readonly<XY>, r: Readonly<XY>): boolean {\n return l.x === r.x && l.y === r.y\n}\n\n/** nonnegative. */\nexport function xyMagnitude(xy: Readonly<XY>): number {\n return Math.hypot(xy.x, xy.y)\n}\n\n/** the greater of each component. */\nexport function xyMax(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: Math.max(l.x, r.x), y: Math.max(l.y, r.y)}\n}\n\n/** the lesser of each component. */\nexport function xyMin(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: Math.min(l.x, r.x), y: Math.min(l.y, r.y)}\n}\n\n/** l - r. */\nexport function xySub(l: Readonly<XY>, r: Readonly<XY>): XY {\n return {x: l.x - r.x, y: l.y - r.y}\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport type {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {\n type CardinalDir,\n type CompassDir,\n type WH,\n whEq,\n type XY,\n xyEq\n} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport type NinePatchOpts<Tag extends TagFormat> = {\n margin?: {w?: number | undefined; h?: number | undefined} | undefined\n n: NinePatchDirOpts<Tag>\n origin: NinePatchDirOpts<Tag>\n border?: {[dir in Lowercase<CardinalDir>]?: number | undefined}\n wh?: {w?: number | undefined; h?: number | undefined} | undefined\n x?: number | undefined\n y?: number | undefined\n z?: Layer | undefined\n} & {\n [dir in 'w' | 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw']?:\n | NinePatchDirOpts<Tag>\n | undefined\n}\nexport type NinePatchDirOpts<Tag extends TagFormat> = {\n flip?: {x?: boolean; y?: boolean} | undefined\n tag: Tag\n stretch?: boolean | undefined\n}\n\nexport class NinePatchEnt<Tag extends TagFormat> implements Ent<Tag> {\n readonly #dir: {readonly [dir in Lowercase<CompassDir>]: Sprite<Tag>}\n readonly #margin: Readonly<WH>\n #invalid: boolean = true\n\n constructor(v: Void<Tag, string>, opts: Readonly<NinePatchOpts<Tag>>) {\n this.#dir = {\n w: v.sprites.alloc(),\n nw: v.sprites.alloc(),\n n: v.sprites.alloc(),\n ne: v.sprites.alloc(),\n e: v.sprites.alloc(),\n se: v.sprites.alloc(),\n s: v.sprites.alloc(),\n sw: v.sprites.alloc(),\n origin: v.sprites.alloc()\n }\n this.#dir.w.tag = opts.w?.tag ?? opts.e?.tag ?? opts.n.tag\n this.#dir.n.tag = opts.n.tag\n this.#dir.e.tag = opts.e?.tag ?? this.#dir.w.tag\n this.#dir.s.tag = opts.s?.tag ?? this.#dir.n.tag\n\n this.#dir.nw.tag = opts.nw?.tag ?? opts.se?.tag ?? opts.n.tag\n this.#dir.ne.tag =\n opts.ne?.tag ?? opts.sw?.tag ?? opts.nw?.tag ?? opts.n.tag\n this.#dir.se.tag = opts.se?.tag ?? this.#dir.nw.tag\n this.#dir.sw.tag = opts.sw?.tag ?? this.#dir.ne.tag\n\n this.#dir.origin.tag = opts.origin.tag\n\n this.#dir.w.z =\n this.#dir.nw.z =\n this.#dir.n.z =\n this.#dir.ne.z =\n this.#dir.e.z =\n this.#dir.se.z =\n this.#dir.s.z =\n this.#dir.sw.z =\n this.#dir.origin.z =\n opts.z ?? 0\n\n this.#dir.w.stretch = opts.w?.stretch ?? opts.e?.stretch ?? false\n this.#dir.n.stretch = opts.n.stretch ?? opts.s?.stretch ?? false\n this.#dir.e.stretch = opts.e?.stretch ?? this.#dir.w.stretch\n this.#dir.s.stretch = opts.s?.stretch ?? this.#dir.n.stretch\n\n this.#dir.nw.stretch = opts.nw?.stretch ?? opts.se?.stretch ?? false\n this.#dir.ne.stretch = opts.ne?.stretch ?? opts.sw?.stretch ?? false\n this.#dir.se.stretch = opts.se?.stretch ?? this.#dir.nw.stretch\n this.#dir.sw.stretch = opts.sw?.stretch ?? this.#dir.ne.stretch\n\n this.#dir.origin.stretch = opts.origin.stretch ?? false\n\n this.#dir.w.flipX = opts.w?.flip?.x ?? !opts.e?.flip?.x\n this.#dir.w.flipY = opts.w?.flip?.y ?? !!opts.e?.flip?.y\n this.#dir.n.flipX = opts.n.flip?.x ?? !!opts.s?.flip?.x\n this.#dir.n.flipY = opts.n.flip?.y ?? !opts.s?.flip?.y\n this.#dir.e.flipX = opts.e?.flip?.x ?? !this.#dir.w.flipX\n this.#dir.e.flipY = opts.e?.flip?.y ?? this.#dir.w.flipY\n this.#dir.s.flipX = opts.s?.flip?.x ?? this.#dir.n.flipX\n this.#dir.s.flipY = opts.s?.flip?.y ?? !this.#dir.n.flipY\n this.#dir.origin.flipX = !!opts.origin.flip?.x\n this.#dir.origin.flipY = !!opts.origin.flip?.y\n\n this.#dir.n.h = opts.border?.n ?? opts.border?.s ?? this.#dir.n.h\n this.#dir.w.w = opts.border?.w ?? opts.border?.e ?? this.#dir.n.h\n this.#dir.e.w = opts.border?.e ?? this.#dir.w.w\n this.#dir.s.h = opts.border?.s ?? this.#dir.n.h\n\n this.#dir.nw.w = this.#dir.w.w\n this.#dir.nw.h = this.#dir.n.h\n this.#dir.ne.w = this.#dir.e.w\n this.#dir.ne.h = this.#dir.n.h\n this.#dir.se.w = this.#dir.e.w\n this.#dir.se.h = this.#dir.s.h\n this.#dir.sw.w = this.#dir.w.w\n this.#dir.sw.h = this.#dir.s.h\n\n this.#margin = {w: opts.margin?.w ?? 0, h: opts.margin?.h ?? 0}\n\n const w =\n opts.wh?.w == null\n ? this.#dir.w.w + this.#dir.n.w + this.#dir.e.w\n : opts.wh.w\n this.#dir.n.w = w - 1 // force resize\n this.wh = {\n w,\n h:\n opts.wh?.h == null\n ? this.#dir.n.h + this.#dir.e.h + this.#dir.s.h\n : opts.wh.h\n }\n\n this.#dir.nw.x = (opts.x ?? 0) - 1 // force move.\n this.xy = {x: opts.x ?? 0, y: opts.y ?? 0}\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(\n this.#dir.w,\n this.#dir.nw,\n this.#dir.n,\n this.#dir.ne,\n this.#dir.e,\n this.#dir.se,\n this.#dir.s,\n this.#dir.sw,\n this.#dir.origin\n )\n }\n\n update(): boolean | undefined {\n if (!this.#invalid) return\n this.#invalid = false\n return true\n }\n\n get wh(): WH {\n return {\n w: this.#dir.w.w + this.#dir.n.w + this.#dir.e.w + this.#margin.w,\n h: this.#dir.n.h + this.#dir.w.h + this.#dir.s.h + this.#margin.h\n }\n }\n\n set wh(wh: Readonly<WH>) {\n if (whEq(wh, this.wh)) return\n\n this.#dir.w.h = wh.h - this.#dir.n.h - this.#dir.s.h - this.#margin.h\n this.#dir.n.w = wh.w - this.#dir.w.w - this.#dir.e.w - this.#margin.w\n this.#dir.s.w = this.#dir.n.w\n this.#dir.e.h = this.#dir.w.h\n\n this.#dir.origin.w = this.#dir.n.w\n this.#dir.origin.h = this.#dir.e.h\n\n this.#setXYRight()\n\n this.#invalid = true\n }\n\n get xy(): XY {\n return {\n x: this.#dir.nw.x - this.#margin.w / 2,\n y: this.#dir.nw.y - this.#margin.h / 2\n }\n }\n\n set xy(xy: Readonly<XY>) {\n if (xyEq(xy, this.xy)) return\n\n this.#dir.nw.x = xy.x + this.#margin.w / 2\n this.#dir.nw.y = xy.y + this.#margin.h / 2\n this.#dir.w.x = this.#dir.nw.x\n this.#dir.w.y = this.#dir.nw.y + this.#dir.nw.h\n this.#dir.n.x = this.#dir.nw.x + this.#dir.nw.w\n this.#dir.n.y = this.#dir.nw.y\n\n this.#dir.origin.x = this.#dir.n.x\n this.#dir.origin.y = this.#dir.nw.y + this.#dir.ne.h\n\n this.#setXYRight()\n\n this.#invalid = true\n }\n\n #setXYRight() {\n this.#dir.ne.x = this.#dir.n.x + this.#dir.n.w\n this.#dir.ne.y = this.#dir.nw.y\n this.#dir.e.x = this.#dir.ne.x\n this.#dir.e.y = this.#dir.nw.y + this.#dir.ne.h\n this.#dir.se.x = this.#dir.e.x\n this.#dir.se.y = this.#dir.e.y + this.#dir.e.h\n this.#dir.s.x = this.#dir.n.x\n this.#dir.s.y = this.#dir.se.y\n this.#dir.sw.x = this.#dir.nw.x\n this.#dir.sw.y = this.#dir.se.y\n }\n}\n", "import type {Font} from 'mem-font'\nimport type {TagFormat} from '../graphics/atlas.ts'\n\nexport function fontCharToTag(font: Readonly<Font>, char: string): TagFormat {\n let pt = char.codePointAt(0)\n if (pt == null || pt > 0xff) pt = 63 // ?\n return `${font.id}--${pt.toString(16).padStart(2, '0')}`\n}\n\n/** @arg r undefined means end of line. */\nexport function fontKerning(\n font: Readonly<Font>,\n l: string,\n r: string | undefined\n): number {\n if (r == null) return font.endOfLineKerning\n if (font.kerning[l + r] != null) return font.kerning[l + r]!\n if (/^\\s?$/.test(l) || /^\\s?$/.test(r)) return font.defaultWhitespaceKerning\n return font.defaultKerning\n}\n\nexport function fontCharWidth(font: Readonly<Font>, letter: string): number {\n return font.charWidth[letter] ?? font.defaultCharWidth\n}\n", "import type {Font} from 'mem-font'\nimport type {Box, WH, XY} from '../types/geo.ts'\nimport {fontCharWidth, fontKerning} from './font.ts'\n\nexport type TextLayout = {\n /** the length of this array matches the string length. */\n chars: (Box | undefined)[]\n /** the offset in pixels. */\n cursor: XY\n wh: WH\n}\n\nexport type TextLayoutOpts = {\n font: Font\n maxW?: number\n scale?: number\n start?: XY\n str: string\n}\n\nexport function layoutText(opts: Readonly<TextLayoutOpts>): TextLayout {\n const chars = []\n const scale = opts.scale ?? 1\n const start = opts.start ?? {x: 0, y: 0}\n const maxW = opts.maxW ?? Infinity\n let cursor = {x: start.x, y: start.y}\n let w = 0\n while (chars.length < opts.str.length) {\n const i = chars.length\n const char = opts.str[i]!\n let layout\n if (char === '\\n') layout = layoutNewline(opts.font, cursor, start.x, scale)\n else if (/^\\s*$/.test(char)) {\n layout = layoutSpace(\n opts.font,\n cursor,\n maxW,\n tracking(opts.font, char, opts.str[i + 1], scale),\n start.x,\n scale\n )\n } else {\n layout = layoutWord(opts.font, cursor, maxW, opts.str, i, start.x, scale)\n if (\n cursor.x > 0 &&\n layout.cursor.y === nextLine(opts.font, start.x, cursor.y, scale).y\n ) {\n const wordW = maxW - cursor.x + layout.cursor.x\n if (wordW <= maxW) {\n // word can fit on one line if cursor is reset to the start of line.\n cursor = nextLine(opts.font, start.x, cursor.y, scale)\n layout = layoutWord(\n opts.font,\n cursor,\n maxW,\n opts.str,\n i,\n start.x,\n scale\n )\n }\n }\n }\n chars.push(...layout.chars)\n cursor.x = layout.cursor.x\n cursor.y = layout.cursor.y\n w = Math.max(w, layout.cursor.x - start.x)\n }\n return {\n chars,\n cursor,\n wh: {w, h: nextLine(opts.font, start.x, cursor.y, scale).y - start.y}\n }\n}\n\n/** @internal */\nexport function layoutWord(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n maxW: number,\n word: string,\n index: number,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n const chars = []\n let {x, y} = cursor\n for (; ; index++) {\n const char = word[index]\n if (!char || /^\\s*$/.test(char)) break\n\n const span = tracking(font, char, word[index + 1], scale)\n if (x > startX && x + span > startX + maxW)\n ({x, y} = nextLine(font, startX, y, scale))\n\n // width is not span since, with kerning, that may exceed the actual\n // width of the character's sprite. eg, if w has the maximal character width\n // of five pixels and a one pixel kerning for a given pair of characters, it\n // will have a span of six pixels which is greater than the maximal five\n // pixel sprite that can be rendered.\n chars.push({x, y, w: fontCharWidth(font, char), h: font.cellHeight})\n x += span\n }\n return {chars, cursor: {x, y}}\n}\n\nfunction nextLine(\n font: Readonly<Font>,\n startX: number,\n curY: number,\n scale: number\n): XY {\n return {x: startX, y: curY + font.lineHeight * scale}\n}\n\nfunction layoutNewline(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n return {chars: [undefined], cursor: nextLine(font, startX, cursor.y, scale)}\n}\n\n/**\n * @arg span the distance in pixels from the start of the current character to\n * the start of the next including scale.\n */\nfunction layoutSpace(\n font: Readonly<Font>,\n cursor: Readonly<XY>,\n w: number,\n span: number,\n startX: number,\n scale: number\n): Omit<TextLayout, 'wh'> {\n const nextCursor =\n cursor.x > 0 && cursor.x + span >= w\n ? nextLine(font, startX, cursor.y, scale)\n : {x: cursor.x + span, y: cursor.y}\n return {chars: [undefined], cursor: nextCursor}\n}\n\n/**\n * the distance in pixels from the start of lhs to the start of rhs including\n * scale.\n */\nfunction tracking(\n font: Readonly<Font>,\n l: string,\n r: string | undefined,\n scale: number\n): number {\n return scale * (fontCharWidth(font, l) + fontKerning(font, l, r))\n}\n", "import {memProp5x6} from 'mem-font'\nimport type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {fontCharToTag} from '../text/font.ts'\nimport {layoutText} from '../text/text-layout.ts'\nimport {type WH, type XY, xyEq} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport class TextEnt implements Ent<TagFormat> {\n #maxW: number = Infinity\n #layout: 'Rendered' | 'Updated' | 'Outdated' = 'Outdated'\n #z: Layer = Layer.UIA\n #scale: number = 1\n readonly #sprites: Sprite<TagFormat>[] = []\n #str: string = ''\n #wh: WH = {w: 0, h: 0}\n readonly #xy: XY = {x: 0, y: 0}\n\n free(v: Void<TagFormat, string>): void {\n v.sprites.free(...this.#sprites)\n }\n\n layout(v: Void<TagFormat, string>): boolean {\n if (this.#layout !== 'Outdated') return false\n let len = 0\n const layout = layoutText({\n font: memProp5x6,\n maxW: this.#maxW,\n scale: this.#scale,\n start: this.#xy,\n str: this.#str\n })\n this.#wh = {w: layout.wh.w, h: layout.wh.h}\n for (const [i, char] of layout.chars.entries()) {\n if (char == null) continue\n const sprite = (this.#sprites[len] ??= v.sprites.alloc())\n sprite.x = char.x\n sprite.y = char.y\n sprite.tag = fontCharToTag(memProp5x6, this.#str[i]!)\n sprite.stretch = true\n sprite.w *= this.#scale\n sprite.h *= this.#scale\n sprite.z = this.#z\n len++\n }\n while (this.#sprites.length > len) v.sprites.free(this.#sprites.pop()!)\n this.#layout = 'Updated'\n return true\n }\n\n get maxW(): number {\n return this.#maxW\n }\n\n set maxW(w: number) {\n if (w === this.#maxW) return\n this.#maxW = w\n this.#layout = 'Outdated'\n }\n\n get scale() {\n return this.#scale\n }\n\n set scale(scale: number) {\n if (scale === this.#scale) return\n this.#scale = scale\n this.#layout = 'Outdated'\n }\n\n get text(): string {\n return this.#str\n }\n\n set text(str: string) {\n if (str === this.#str) return\n this.#str = str\n this.#layout = 'Outdated'\n }\n\n update(v: Void<TagFormat, string>): boolean | undefined {\n if (this.#layout === 'Rendered') return\n if (this.#layout === 'Outdated') this.layout(v)\n this.#layout = 'Rendered'\n return true\n }\n\n get scaledLeading(): number {\n return memProp5x6.leading * this.#scale\n }\n\n get wh(): Readonly<WH> {\n return this.#wh\n }\n\n get xy(): Readonly<XY> {\n return this.#xy\n }\n\n set xy(xy: Readonly<XY>) {\n if (xyEq(xy, this.#xy)) return\n this.#xy.x = xy.x\n this.#xy.y = xy.y\n this.#layout = 'Outdated'\n }\n\n get z(): Layer {\n return this.#z\n }\n\n set z(layer: Layer) {\n if (layer === this.#z) return\n this.#z = layer\n this.#layout = 'Outdated'\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer, layerOffset} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {type XY, xyEq} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\nimport {NinePatchEnt, type NinePatchOpts} from './nine-patch-ent.ts'\nimport {TextEnt} from './text-ent.ts'\n\nexport type ButtonOpts<Tag extends TagFormat> = {\n button: Omit<NinePatchOpts<Tag>, 'x' | 'y' | 'wh'>\n pressed: {tag: Tag; z?: Layer | undefined}\n selected: {tag: Tag; z?: Layer | undefined}\n toggle?: boolean | undefined\n text?:\n | {\n text?: string | undefined\n scale?: number | undefined\n z?: Layer | undefined\n }\n | undefined\n w?: number | undefined\n h?: number | undefined\n x?: number | undefined\n y?: number | undefined\n}\n\nexport class ButtonEnt<Tag extends TagFormat, Button extends string>\n implements Ent<Tag>\n{\n readonly #button: NinePatchEnt<Tag>\n #invalid: boolean = true\n readonly #pressed: {sprite: Sprite<Tag>; z: Layer}\n readonly #selected: {sprite: Sprite<Tag>; z: Layer}\n #started: boolean = false\n readonly #toggle: boolean = false\n readonly #text: TextEnt = new TextEnt()\n readonly #xy: XY = {x: 0, y: 0}\n\n constructor(v: Void<Tag, string>, opts: Readonly<ButtonOpts<Tag>>) {\n const buttonZ = opts.button.z ?? Layer.UID\n this.#button = new NinePatchEnt(v, {\n ...opts.button,\n x: opts.x,\n y: opts.y,\n z: buttonZ,\n wh: {w: opts.w, h: opts.h}\n })\n this.#pressed = {\n sprite: v.sprites.alloc(),\n z: opts.pressed.z ?? layerOffset(buttonZ, 2)\n }\n this.#selected = {\n sprite: v.sprites.alloc(),\n z: opts.selected.z ?? layerOffset(this.#pressed.z, -1)\n }\n\n this.#pressed.sprite.tag = opts.pressed.tag\n this.#pressed.sprite.x = opts.x ?? 0\n this.#pressed.sprite.y = opts.y ?? 0\n this.#pressed.sprite.w = opts.w ?? this.#button.wh.w\n this.#pressed.sprite.h = opts.h ?? this.#button.wh.h\n this.#pressed.sprite.z = Layer.Hidden\n\n this.#selected.sprite.tag = opts.selected.tag\n this.#selected.sprite.x = opts.x ?? 0\n this.#selected.sprite.y = opts.y ?? 0\n this.#selected.sprite.w = opts.w ?? this.#button.wh.w\n this.#selected.sprite.h = opts.h ?? this.#button.wh.h\n this.#selected.sprite.z = Layer.Hidden\n\n this.#text.text = opts.text?.text ?? ''\n this.#text.scale = opts.text?.scale ?? 1\n this.#text.layout(v)\n this.#moveText(v)\n this.#text.maxW = opts.w ?? this.#button.wh.w\n this.#text.z = opts.text?.z ?? layerOffset(buttonZ, -1)\n\n this.#toggle = opts.toggle ?? false\n }\n\n get selected(): boolean {\n return this.#selected.z !== Layer.Hidden\n }\n\n free(v: Void<Tag, string>): void {\n this.#button.free(v)\n this.#text.free(v)\n v.sprites.free(this.#selected.sprite, this.#pressed.sprite)\n }\n\n get on(): boolean {\n return this.#pressed.sprite.z !== Layer.Hidden\n }\n\n set on(on: boolean) {\n this.#pressed.sprite.z = on ? this.#pressed.z : Layer.Hidden\n }\n\n // to-do: offStart() for pointer up listen? would need a boundary check too.\n get onStart(): boolean {\n return this.on && this.#started\n }\n\n set text(str: string) {\n this.#text.text = str\n }\n\n update(v: Void<Tag, 'A' | 'Click' | Button>): boolean | undefined {\n let invalid = this.#invalid\n if (this.#button.update()) invalid = true\n if (this.#text.update(v)) invalid = true\n\n const hitsCursor =\n !v.input.handled && !!v.zoo.cursor?.hits(v, this.#selected.sprite, 'UI')\n const clickStarted =\n (hitsCursor && v.input.isOnStart('Click')) ||\n (v.zoo.cursor?.keyboard && v.input.isOnStart('A'))\n\n const on = clickStarted\n ? this.#toggle\n ? !this.on\n : true\n : this.#toggle\n ? this.on\n : v.input.isOn('Click') ||\n (!!v.zoo.cursor?.keyboard && v.input.isOn('A'))\n this.#started = this.on !== on\n if (this.#started) {\n this.on = on\n invalid = true\n }\n\n if (\n hitsCursor &&\n (v.input.point?.click || v.input.point?.type === 'Mouse')\n ) {\n invalid ||= this.#selected.sprite.z !== this.#selected.z\n this.#selected.sprite.z = this.#selected.z\n } else {\n invalid ||= this.#selected.sprite.z !== Layer.Hidden\n this.#selected.sprite.z = Layer.Hidden\n }\n\n v.input.handled ||= hitsCursor\n this.#invalid = false\n return invalid\n }\n\n setXY(v: Void<Tag, string>, xy: Readonly<XY>): void {\n if (xyEq(xy, this.#xy)) return\n this.#xy.x = xy.x\n this.#xy.y = xy.y\n this.#button.xy = xy\n this.#moveText(v)\n this.#pressed.sprite.xy = xy\n this.#selected.sprite.xy = xy\n this.#invalid = true\n }\n\n #moveText(v: Void<Tag, string>): void {\n this.#text.layout(v)\n this.#text.xy = {\n x: this.#button.xy.x + this.#button.wh.w / 2 - this.#text.wh.w / 2,\n y:\n this.#button.xy.y +\n this.#button.wh.h / 2 -\n (this.#text.wh.h - this.#text.scaledLeading) / 2\n }\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {type Box, boxHits, type WH, type XY} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\n/**\n * update this ent first. always prefer testing against cursor, not input, in\n * other ents. the cursor may be moved by keyboard and has a hitbox.\n */\nexport class CursorEnt<out Tag extends TagFormat> implements Ent<Tag> {\n keyboard: boolean = false\n readonly #sprite: Sprite<Tag>\n #pick: Tag\n #point: Tag\n\n constructor(v: Void<Tag, string>, point: Tag, pick?: Tag | undefined) {\n this.#point = point\n this.#pick = pick ?? this.#point\n this.#sprite = v.sprites.alloc()\n this.#sprite.tag = point\n this.#sprite.z = Layer.Hidden\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(this.#sprite)\n }\n\n hitbox(v: Readonly<Void<Tag, string>>, coords: 'Level' | 'UI'): Box {\n const lvl = coords === 'Level'\n const hitbox = this.#sprite.hitbox\n if (!hitbox) throw Error('cursor has no hitbox')\n return {\n x: (lvl ? v.cam.x : 0) + hitbox.x,\n y: (lvl ? v.cam.y : 0) + hitbox.y,\n w: hitbox.w,\n h: hitbox.h\n }\n }\n\n hits(\n v: Readonly<Void<Tag, string>>,\n box: Readonly<XY & Partial<WH>>,\n coords: 'Level' | 'UI'\n ): boolean {\n return this.visible && boxHits(this.hitbox(v, coords), box)\n }\n\n update(v: Void<Tag, 'L' | 'R' | 'U' | 'D'>): boolean | undefined {\n if (v.input.point?.invalid) {\n this.#sprite.tag = v.input.point.click ? this.#pick : this.#point\n this.#sprite.xy = v.input.point.local\n this.#sprite.z =\n v.input.point?.type === 'Mouse' ? Layer.Top : Layer.Hidden\n return true\n }\n\n if (this.keyboard && v.input.isAnyOn('L', 'R', 'U', 'D')) {\n const epsilon = 1\n if (v.input.isOn('L')) this.#sprite.x -= epsilon\n if (v.input.isOn('R')) this.#sprite.x += epsilon\n if (v.input.isOn('U')) this.#sprite.y -= epsilon\n if (v.input.isOn('D')) this.#sprite.y += epsilon\n this.#sprite.z = Layer.Top\n\n return true\n }\n }\n\n get visible(): boolean {\n return this.#sprite.z !== Layer.Hidden\n }\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport type {Layer} from '../graphics/layer.ts'\nimport type {Sprite} from '../graphics/sprite.ts'\nimport {\n type CompassDir,\n type WH,\n whAssign,\n whEq,\n type XY,\n xyAssign,\n xyEq\n} from '../types/geo.ts'\nimport type {Void} from '../void.ts'\nimport type {Ent} from './ent.ts'\n\nexport class FollowCamEnt<Tag extends TagFormat> implements Ent<Tag> {\n #fill: 'X' | 'Y' | 'XY' | undefined\n #invalid: boolean = true\n readonly #margin: WH = {w: 0, h: 0}\n readonly #modulo: XY = {x: 0, y: 0}\n #pivot: CompassDir\n readonly #sprite: Sprite<Tag>\n\n constructor(v: Void<Tag, string>, tag: Tag, pivot: CompassDir) {\n this.#sprite = v.sprites.alloc()\n this.#sprite.tag = tag\n this.#pivot = pivot\n }\n\n get fill(): 'X' | 'Y' | 'XY' | undefined {\n return this.#fill\n }\n\n set fill(fill: 'X' | 'Y' | 'XY' | undefined) {\n if (this.#fill === fill) return\n this.#fill = fill\n this.#invalid = true\n }\n\n free(v: Void<Tag, string>): void {\n v.sprites.free(this.#sprite)\n }\n\n get h(): number {\n return this.#sprite.h\n }\n\n set h(h: number) {\n if (this.#sprite.h === h) return\n this.#sprite.h = h\n this.#invalid = true\n }\n\n get margin(): Readonly<WH> {\n return this.#margin\n }\n\n set margin(margin: Readonly<WH>) {\n if (whEq(margin, this.#margin)) return\n whAssign(this.#margin, margin)\n this.#invalid = true\n }\n\n get modulo(): Readonly<XY> {\n return this.#modulo\n }\n\n set modulo(modulo: Readonly<XY>) {\n if (xyEq(modulo, this.#modulo)) return\n xyAssign(this.#modulo, modulo)\n this.#invalid = true\n }\n\n get pivot(): CompassDir {\n return this.#pivot\n }\n\n set pivot(pivot: CompassDir) {\n if (this.#pivot === pivot) return\n this.#pivot = pivot\n this.#invalid = true\n }\n\n update(v: Void<Tag, string>): boolean | undefined {\n if (!this.#invalid && !v.cam.invalid) return\n const follow = v.cam.follow(\n {w: this.#sprite.w, h: this.#sprite.h},\n this.#sprite.z,\n this.#pivot,\n {fill: this.#fill, modulo: this.#modulo, margin: this.#margin}\n )\n this.#sprite.x = follow.x\n this.#sprite.y = follow.y\n this.#invalid = false\n return true\n }\n\n get w(): number {\n return this.#sprite.w\n }\n\n set w(w: number) {\n if (this.#sprite.w === w) return\n this.#sprite.w = w\n this.#invalid = true\n }\n\n get z(): Layer {\n return this.#sprite.z\n }\n\n set z(z: Layer) {\n this.#sprite.z = z\n }\n}\n", "/**\n * proxy for debug CSV query param with case-insensitive keys. when a key\n * exists, the value is as specified or `'true'` if no value. most void values\n * default to `'true'` when the `debug` param is empty or `'void'` is set (eg,\n * `localhost:1234?debug` or `localhost:1234?debug=void,foo=bar`). all values\n * default to true when `'all'` is set. extend interface for additional types.\n * doesn't handle multiple values like `localhost:1234?debug=a=1,b=2&debug=b=3`.\n */\nexport interface Debug {\n cam?: string\n input?: string\n /** debug render invalidations. */\n invalid?: string\n mem?: string\n render?: 'always' | string\n}\n\nexport const debug: Readonly<Debug> | undefined = Debug(\n globalThis.location?.href\n)\n\n/** @internal */\nexport function Debug(url: string | undefined): Debug | undefined {\n if (!url) return\n const csv = [...new URL(url).searchParams].find(\n ([k]) => k.toLowerCase() === 'debug'\n )?.[1]\n if (csv == null) return\n const map = Object.fromEntries(\n csv\n .split(',') // split KV pairs.\n .filter(Boolean) // drop empties.\n .map(kv => kv.split('=')) // split each pair.\n )\n\n const target: {[k: string]: string} = {}\n for (const k in map) target[k.toLowerCase()] = map[k] || 'true'\n\n const voidKeyset: {[_ in keyof Omit<Debug, 'invalid'>]-?: undefined} = {\n cam: undefined,\n input: undefined,\n mem: undefined,\n render: undefined\n }\n\n return new Proxy<{[k: string]: string}>(target, {\n get(target, k): string | undefined {\n if (typeof k !== 'string') return target[k as unknown as string]\n k = k.toLowerCase()\n if (target[k]) return target[k]\n if (!csv || 'all' in map || (k in voidKeyset && 'void' in map))\n return 'true'\n }\n })\n}\n", "import type {TagFormat} from '../graphics/atlas.ts'\nimport {debug} from '../utils/debug.ts'\nimport type {Void} from '../void.ts'\nimport {CursorEnt} from './cursor-ent.ts'\nimport type {Ent} from './ent.ts'\n\n/**\n * ents are updated in insertion order. composed ents are updated by their\n * owning ents.\n */\nexport class Zoo<out Tag extends TagFormat> {\n #cursor: CursorEnt<Tag> | undefined\n readonly #ents: Set<Ent<Tag>> = new Set()\n #invalid: boolean = false\n\n add(...ents: readonly Ent<Tag>[]): void {\n for (const ent of ents) {\n this.#ents.add(ent)\n if (ent instanceof CursorEnt) this.#cursor = ent\n }\n }\n\n clear(): void {\n this.#cursor = undefined\n this.#ents.clear()\n }\n\n get cursor(): CursorEnt<Tag> | undefined {\n return this.#cursor\n }\n\n get invalid(): boolean {\n return this.#invalid\n }\n\n remove(...ents: readonly Readonly<Ent<Tag>>[]): void {\n for (const ent of ents) {\n this.#ents.delete(ent)\n if (ent === this.#cursor) this.#cursor = undefined\n }\n }\n\n update(v: Void<Tag, string>): void {\n this.#invalid = false\n for (const ent of this.#ents)\n if (ent.update?.(v)) {\n if (!this.#invalid && debug?.invalid)\n console.debug('ent update invalid', ent)\n this.#invalid = true\n }\n }\n}\n", "import {type Anim, type Atlas, type AtlasJSON, animCels} from './atlas.ts'\n\nexport function parseAtlas(json: Readonly<AtlasJSON>): Atlas {\n return {\n anim: json.anim,\n celXYWH: parseCelXYWH(json),\n tags: Object.keys(json.anim)\n }\n}\n\nfunction parseCelXYWH(json: Readonly<AtlasJSON>): number[] {\n const cels = []\n let i = 0\n for (const anim of Object.values(json.anim)) {\n cels.push(...parseXYWH(anim, json.celXY, i))\n i += anim.cels * 2\n }\n return cels\n}\n\n/** @internal */\nexport function parseXYWH(\n anim: Readonly<Anim>,\n celXY: readonly number[],\n i: number\n): number[] {\n const xywh = []\n for (let ii = 0; ii < animCels; ii++) {\n const iii = i + 2 * (ii % anim.cels)\n xywh.push(celXY[iii]!, celXY[iii + 1]!, anim.w, anim.h)\n }\n return xywh\n}\n", "import {\n type Box,\n boxHits,\n type CompassDir,\n type WH,\n type XY\n} from '../types/geo.ts'\nimport {debug} from '../utils/debug.ts'\nimport {Layer} from './layer.ts'\n\nexport type LevelClientLocalXY = {\n /** position relative canvas top-left (in DPI scale). */\n client: XY\n /**\n * position relative canvas top-left in level scale (like level xy but no cam\n * offset) within cam.\n */\n local: XY\n /** level x-coord within cam. */\n x: number\n /** level y-coord within cam. */\n y: number\n}\n\ntype Canvas = {\n width: number\n height: number\n style: {width: string; height: string}\n parentElement: {clientWidth: number; clientHeight: number} | null\n}\n\n/** given a min WH and scale, size the camera to the max WH. */\nexport class Cam {\n #devicePixelRatio: number = 0\n #h: number = 1\n #invalid: boolean = true\n #minScale: number = 1\n readonly #minWH: WH = {w: Infinity, h: Infinity}\n #mode: 'Int' | 'Fraction' = 'Int'\n #scale: number = 1\n #w: number = 1\n readonly #whClient: WH = {w: 1, h: 1}\n #x: number = 0\n #y: number = 0\n #zoomOut: number = 0\n\n center(xy: Readonly<XY>): void {\n this.x = Math.floor(xy.x - this.w / 2)\n this.y = Math.floor(xy.y - this.h / 2)\n }\n\n /** position in fractional level coordinates. */\n clientToXY(client: Readonly<XY>): XY {\n const local = this.clientToXYLocal(client)\n return {x: this.#x + local.x, y: this.#y + local.y}\n }\n\n /**\n * position relative canvas top-left in level scale (like level xy but no cam\n * offset). often used for UI that is fixed within the cam.\n */\n clientToXYLocal(client: Readonly<XY>): XY {\n return {\n x: (client.x / this.#whClient.w) * this.#w,\n y: (client.y / this.#whClient.h) * this.#h\n }\n }\n\n follow(\n wh: Readonly<WH>,\n z: Layer,\n pivot: CompassDir,\n opts?: {\n readonly fill?: 'X' | 'Y' | 'XY' | undefined\n readonly margin?: Partial<Readonly<WH>> | undefined\n readonly modulo?: Partial<Readonly<XY>> | undefined\n }\n ): Box {\n const marginW = opts?.margin?.w ?? 0\n let x = z > Layer.UIG ? Math.trunc(this.x) : 0\n switch (pivot) {\n case 'SW':\n case 'W':\n case 'NW':\n x += marginW\n break\n case 'SE':\n case 'E':\n case 'NE':\n x += this.w - (wh.w + marginW)\n break\n case 'N':\n case 'S':\n case 'Origin':\n x += Math.trunc(this.w / 2) - Math.trunc(wh.w / 2)\n break\n }\n x -= x % ((opts?.modulo?.x ?? x) || 1)\n\n const marginH = opts?.margin?.h ?? 0\n let y = z > Layer.UIG ? Math.trunc(this.y) : 0\n switch (pivot) {\n case 'N':\n case 'NE':\n case 'NW':\n y += marginH\n break\n case 'SE':\n case 'S':\n case 'SW':\n y += this.h - (wh.h + marginH)\n break\n case 'E':\n case 'W':\n case 'Origin':\n y += Math.trunc(this.h / 2) - Math.trunc(wh.h / 2)\n break\n }\n y -= y % ((opts?.modulo?.y ?? y) || 1)\n\n const w =\n opts?.fill === 'X' || opts?.fill === 'XY' ? this.w - 2 * marginW : wh.w\n const h =\n opts?.fill === 'Y' || opts?.fill === 'XY' ? this.h - 2 * marginH : wh.h\n\n return {x, y, w, h}\n }\n\n /** positive int in level px. */\n get h(): number {\n return this.#h\n }\n\n isVisible(box: Readonly<XY & Partial<WH>>): boolean {\n return boxHits(this, box)\n }\n\n /** true if cam moved or resized since last update. */\n get invalid(): boolean {\n return this.#invalid\n }\n\n /** positive int or fraction depending on mode. */\n get minScale(): number {\n return this.#minScale\n }\n\n set minScale(scale: number) {\n if (this.#scale === scale) return\n this.#scale = scale\n this.#invalidateWH()\n }\n\n /**\n * positive int or infinite min dimensions. set to\n * `{w: Infinity, h: Infinity}` to always use min scale.\n */\n get minWH(): Readonly<WH> {\n return this.#minWH\n }\n\n set minWH(wh: Readonly<WH>) {\n if (this.#minWH.w === wh.w && this.#minWH.h === wh.h) return\n this.#minWH.w = wh.w\n this.#minWH.h = wh.h\n this.#invalidateWH()\n }\n\n get mode(): 'Int' | 'Fraction' {\n return this.#mode\n }\n\n set mode(mode: 'Int' | 'Fraction') {\n if (this.#mode === mode) return\n this.#mode = mode\n this.#invalidateWH()\n }\n\n get portrait(): boolean {\n return this.h > this.w\n }\n\n postupdate(): void {\n this.#invalid = false\n }\n\n /** positive int or fraction depending on mode. */\n get scale(): number {\n return this.#scale\n }\n\n toString(): string {\n return `Cam{(${this.x} ${this.y}) ${this.w}\u00D7${this.h}}`\n }\n\n /**\n * call after input processing but before ent processing. ents that move the\n * camera should be called immediately after update so that the invalid state\n * can be considered.\n */\n update(canvas: Canvas): void {\n if (!canvas.parentElement) throw Error('canvas has no parent')\n const {clientWidth, clientHeight} = canvas.parentElement\n\n this.#invalid ||=\n this.#whClient.w !== clientWidth ||\n this.#whClient.h !== clientHeight ||\n // doesn't seem like this should be necessary but it is when moving across\n // monitors.\n this.#devicePixelRatio !== devicePixelRatio\n if (!this.#invalid) return\n this.#devicePixelRatio = devicePixelRatio\n this.#whClient.w = clientWidth\n this.#whClient.h = clientHeight\n this.#invalidateWH()\n\n canvas.width = this.#w\n canvas.height = this.#h\n // ~parentW / parentH.\n canvas.style.width = `${(this.#w * this.#scale) / devicePixelRatio}px`\n canvas.style.height = `${(this.#h * this.#scale) / devicePixelRatio}px`\n }\n\n /** positive int in level px. */\n get w(): number {\n return this.#w\n }\n\n /**\n * positive int dimensions in client px of canvas (often\n * `canvas.parentElement.clientWidth/Height` since the canvas is resized)\n * which is assumed to be max WH.\n */\n get whClient(): Readonly<WH> {\n return this.#whClient\n }\n\n /** fractional. */\n get x(): number {\n return this.#x\n }\n\n set x(x: number) {\n this.#invalid ||= this.x !== x\n this.#x = x\n }\n\n /** fractional. */\n get y(): number {\n return this.#y\n }\n\n set y(y: number) {\n this.#invalid ||= this.y !== y\n this.#y = y\n }\n\n /** nonnegative int or fraction depending on mode. */\n get zoomOut(): number {\n return this.#zoomOut\n }\n\n set zoomOut(out: number) {\n out = Math.max(0, out)\n if (this.#zoomOut === out) return\n this.#zoomOut = out\n this.#invalidateWH()\n }\n\n #invalidateWH(): void {\n if (!this.#invalid && debug?.invalid) console.debug('cam invalid')\n this.#invalid = true\n\n const phy = {\n w: this.#whClient.w * devicePixelRatio,\n h: this.#whClient.h * devicePixelRatio\n }\n\n const scale = Math.max(\n this.#minScale,\n Math.min(phy.w / this.#minWH.w, phy.h / this.#minWH.h) -\n (this.#mode === 'Int' ? Math.trunc(this.#zoomOut) : this.#zoomOut)\n )\n this.#scale = this.#mode === 'Int' ? Math.trunc(scale) : scale\n\n this.#w = Math.ceil(phy.w / this.#scale)\n this.#h = Math.ceil(phy.h / this.#scale)\n }\n}\n", "// to-do: port tests.\nexport function clamp(val: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, val))\n}\n\nexport function closeTo(lhs: number, rhs: number, tolerance: number): boolean {\n return Math.abs(lhs - rhs) <= tolerance\n}\n\n// to-do: port tests.\n/** ratio is [0, 1] to return [start, end]. */\nexport function lerp(start: number, end: number, ratio: number): number {\n return start + (end - start) * ratio\n}\n\n// to-do: test.\n/** returns positive modulo. */\nexport function mod(dividend: number, divisor: number): number {\n return ((dividend % divisor) + divisor) % divisor\n}\n", "import {\n type Anim,\n type Atlas,\n animCels,\n celMillis,\n type TagFormat\n} from '../graphics/atlas.ts'\nimport type {Block} from '../mem/pool.ts'\nimport {type Box, boxHits, type WH, type XY} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {mod} from '../utils/math.ts'\nimport type {Layer} from './layer.ts'\n\nexport const drawableBytes: number = 12\n/** granularity (0.015625) of `Drawable` coords. */\nexport const drawableEpsilon: number = 1 / 64\nexport const drawableMaxWH: WH = {w: 4095, h: 4095}\n\n/**\n * everything not requiring an atlas. the box is the drawn region. assume little\n * endian.\n *\n * 0 xxxx xxxx x [-131072, 131071.984375] (1/64th fixed-point). 1b sign, 17b\n * 1 xxxx xxxx int, 6b fraction.\n * 2 xxxx xxxx\n * 3 yyyy yyyy y.\n * 4 yyyy yyyy\n * 5 yyyy yyyy\n * 6 sxyz llll stretch, flip x, flip y, zend, z layer (4b).\n * 7 wwww wwww width [0, 4095]. zero means discard.\n * 8 hhhh wwww height. zero means discard.\n * 9 hhhh hhhh\n * a iiic cccc animation ID [0, 2047], animation cel [0, 31].\n * b iiii iiii\n *\n * animations default to looping without CPU interaction.\n * @internal\n */\nexport abstract class Drawable implements Block, Box {\n i: number\n readonly #pool: {readonly view: DataView<ArrayBuffer>}\n\n constructor(pool: {readonly view: DataView<ArrayBuffer>}, i: number) {\n this.#pool = pool\n this.i = i\n }\n\n above(draw: Readonly<Drawable>): boolean {\n const compare =\n this.z === draw.z\n ? (draw.zend ? draw.y + draw.h : draw.y) -\n (this.zend ? this.y + this.h : this.y)\n : this.z - draw.z\n return compare < 0\n }\n\n get cel(): number {\n const iiic_cccc = this.#pool.view.getUint8(this.i + 10)\n return iiic_cccc & 0x1f\n }\n\n /**\n * [0, 31]. rendered cel offset. call reset() to play animation from start.\n */\n set cel(cel: number) {\n const iiic_cccc = this.#pool.view.getUint8(this.i + 10)\n this.#pool.view.setUint8(this.i + 10, (iiic_cccc & ~0x1f) | (cel & 0x1f))\n }\n\n /** test if render area overlaps box or sprite render area. */\n clips(box: Readonly<XY & Partial<WH>>): boolean {\n return boxHits(this, box)\n }\n\n get flipX(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x40)\n }\n\n set flipX(flip: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x40) | (-flip & 0x40))\n }\n\n get flipY(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x20)\n }\n\n set flipY(flip: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x20) | (-flip & 0x20))\n }\n\n get h(): number {\n const h12_wwww = this.#pool.view.getUint16(this.i + 8, true)\n return h12_wwww >>> 4\n }\n\n /** [0, 4095]. */\n set h(h: number) {\n const h12_wwww = this.#pool.view.getUint16(this.i + 8, true)\n this.#pool.view.setUint16(\n this.i + 8,\n (h12_wwww & ~(0xfff << 4)) | ((h & 0xfff) << 4),\n true\n )\n }\n\n get id(): number {\n const i11_c5 = this.#pool.view.getUint16(this.i + 10, true)\n return (i11_c5 >>> 5) & 0x7ff\n }\n\n /** [0, 2047]. */\n set id(id: number) {\n const i11_c5 = this.#pool.view.getUint16(this.i + 10, true)\n this.#pool.view.setUint16(\n this.i + 10,\n (i11_c5 & ~(0x7ff << 5)) | ((id & 0x7ff) << 5),\n true\n )\n }\n\n get stretch(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x80)\n }\n\n /** wrap texture (default) or stretch to width and height. */\n set stretch(stretch: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(\n this.i + 6,\n (sxyz_llll & ~0x80) | (-stretch & 0x80)\n )\n }\n\n get w(): number {\n const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true)\n return hhhh_w12 & 0xfff\n }\n\n /** [0, 4095]. */\n set w(w: number) {\n const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true)\n this.#pool.view.setUint16(\n this.i + 7,\n (hhhh_w12 & ~0xfff) | (w & 0xfff),\n true\n )\n }\n\n get x(): number {\n const y8_x24 = this.#pool.view.getUint32(this.i + 0, true)\n return ((y8_x24 << 8) >> 8) / 64 // signed shift.\n }\n\n /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */\n set x(x: number) {\n const y8_x24 = this.#pool.view.getUint32(this.i + 0, true)\n this.#pool.view.setUint32(\n this.i + 0,\n (y8_x24 & ~0xff_ffff) | ((x * 64) & 0xff_ffff),\n true\n )\n }\n\n get xy(): XY {\n return {x: this.x, y: this.y}\n }\n\n set xy(xy: Readonly<XY>) {\n this.x = xy.x\n this.y = xy.y\n }\n\n get y(): number {\n const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true)\n return ((sxyz_llll_y24 << 8) >> 8) / 64 // signed shift.\n }\n\n /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */\n set y(y: number) {\n const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true)\n this.#pool.view.setUint32(\n this.i + 3,\n (sxyz_llll_y24 & ~0xff_ffff) | ((y * 64) & 0xff_ffff),\n true\n )\n }\n\n get z(): Layer {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return (sxyz_llll & 0xf) as Layer\n }\n\n /** layer [0 (closest), 14 (furthest)]; 15 is hidden. */\n set z(z: Layer) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0xf) | (z & 0xf))\n }\n\n get zend(): boolean {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n return !!(sxyz_llll & 0x10)\n }\n\n /** z-order by top (default) or bottom of box. */\n set zend(end: boolean) {\n const sxyz_llll = this.#pool.view.getUint8(this.i + 6)\n this.#pool.view.setUint8(this.i + 6, (sxyz_llll & ~0x10) | (-end & 0x10))\n }\n}\n\n// to-do: can I declaration merge or namespace merge away from the tag type?\nexport class Sprite<out Tag extends TagFormat> extends Drawable {\n readonly #atlas: Readonly<Atlas>\n #hitbox: Box | undefined\n #hurtbox: Box | undefined\n readonly #looper: {readonly age: Millis}\n\n constructor(\n pool: {readonly view: DataView<ArrayBuffer>},\n i: number,\n atlas: Readonly<Atlas>,\n looper: {readonly age: Millis}\n ) {\n super(pool, i)\n this.#atlas = atlas\n this.#looper = looper\n }\n\n get anim(): Anim {\n return this.#atlas.anim[this.tag]!\n }\n\n override get flipX(): boolean {\n return super.flipX\n }\n\n override set flipX(flip: boolean) {\n if (this.flipX === flip) return\n super.flipX = flip\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get flipY(): boolean {\n return super.flipY\n }\n\n override set flipY(flip: boolean) {\n if (this.flipY === flip) return\n super.flipY = flip\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get h(): number {\n return super.h\n }\n\n override set h(h: number) {\n if (this.h === h) return\n super.h = h\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n get hitbox(): Box | undefined {\n if (this.#hitbox) return this.#hitbox\n const {hitbox} = this.anim\n if (!hitbox) return\n return (this.#hitbox ??= {\n x: this.x + (this.flipX ? this.w - hitbox.w - hitbox.x : hitbox.x),\n y: this.y + (this.flipY ? this.h - hitbox.h - hitbox.y : hitbox.y),\n w: hitbox.w,\n h: hitbox.h\n })\n }\n\n hits(box: Readonly<XY | Box>): boolean {\n const hitbox = this.hitbox\n if (!hitbox) return false\n const hurtbox = box instanceof Sprite ? box.hurtbox : box\n return !!hurtbox && boxHits(hitbox, hurtbox)\n }\n\n get hurtbox(): Box | undefined {\n if (this.#hurtbox) return this.#hurtbox\n const {hurtbox} = this.anim\n if (!hurtbox) return\n return (this.#hurtbox ??= {\n x: this.x + (this.flipX ? this.w - hurtbox.w - hurtbox.x : hurtbox.x),\n y: this.y + (this.flipY ? this.h - hurtbox.h - hurtbox.y : hurtbox.y),\n w: hurtbox.w,\n h: hurtbox.h\n })\n }\n\n override get id(): number {\n return super.id\n }\n\n override set id(id: number) {\n if (this.id === id) return\n super.id = id\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n /** true if animation has played once. */\n get looped(): boolean {\n // this comparison resets after the second loop since cel can only count to\n // 2 * anim.cels.\n return mod(this.#currentCel - this.cel, animCels * 2) >= this.anim.cels\n }\n\n /** sets cel to animation start. */\n reset(): void {\n this.cel = this.#currentCel // setter truncates.\n }\n\n // to-do: unit test and catch up on unit tests elsewhere.\n\n get tag(): Tag {\n return this.#atlas.tags[this.id] as Tag\n }\n\n /** sets animation, resets cel, dimensions, hitbox, and hurtbox. */\n set tag(tag: Tag) {\n const anim = this.#atlas.anim[tag]!\n this.w = anim.w\n this.h = anim.h\n this.id = anim.id\n this.reset()\n }\n\n override toString(): string {\n return `Sprite{${this.tag} (${this.x} ${this.y} ${this.z}) ${this.w}\u00D7${this.h}}`\n }\n\n override get w(): number {\n return super.w\n }\n\n override set w(w: number) {\n if (this.w === w) return\n super.w = w\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get x(): number {\n return super.x\n }\n\n override set x(x: number) {\n if (this.x === x) return\n super.x = x\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n override get y(): number {\n return super.y\n }\n\n override set y(y: number) {\n if (this.y === y) return\n super.y = y\n this.#hitbox = undefined\n this.#hurtbox = undefined\n }\n\n /** current fractional cel in [0, 2 * anim.cels). */\n get #currentCel(): number {\n const cel = this.#looper.age / celMillis\n return cel % (this.anim.cels * 2)\n }\n}\n", "/** @internal */\nexport class ContextMenu {\n enable: boolean = false\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('contextmenu', this.#onContextMenu as EventListener)\n // disable long press vibration. nonpassive must be explicit.\n fn('touchstart', this.#onContextMenu as EventListener, {passive: false})\n return this\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onContextMenu = (ev: PointerEvent | TouchEvent): void => {\n if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return\n if (!this.enable) ev.preventDefault()\n }\n}\n", "/** @internal */\nexport class Gamepad {\n bits: number = 0\n // to-do: support analog button values, expose connected status and vibration,\n // and distinct devices. would be nice if vibration could merge with\n // navigator.vibrate().\n readonly bitByAxis: {[axis: number]: [less: number, more: number]} = {}\n readonly bitByButton: {[btn: number]: number} = {}\n onEvent: () => void = () => {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n get connected(): boolean {\n return isSecureContext && navigator.getGamepads().filter(Boolean).length > 0\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('gamepadconnected', this.onEvent)\n fn('gamepaddisconnected', this.onEvent)\n return this\n }\n\n reset(): void {\n this.bits = 0\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n update(): void {\n if (!isSecureContext) return\n for (const pad of navigator.getGamepads()) {\n for (const [index, axis] of pad?.axes.entries() ?? []) {\n const lessMore = this.bitByAxis[index]\n if (!lessMore) continue\n const bit = axis < 0 ? lessMore[0] : axis === 0 ? 0 : lessMore[1]\n this.bits |= Math.abs(axis) >= 0.5 ? bit : 0\n }\n for (const [index, btn] of pad?.buttons.entries() ?? []) {\n const bit = this.bitByButton[index]\n if (bit == null) continue\n this.bits |= btn.pressed ? bit : 0\n }\n }\n }\n}\n", "/** @internal */\nexport class Keyboard {\n /** KeyboardEvent.code to bit. */\n readonly bitByCode: {[code: string]: number} = {}\n invalid: boolean = false\n /** KeyboardEvent.code to state. Multiple keys may map to the same bit. */\n onEvent: () => void = () => {}\n #on: {[code: string]: boolean} = {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n get bits(): number {\n let bits = 0\n for (const k in this.bitByCode) bits |= this.#on[k] ? this.bitByCode[k]! : 0\n return bits\n }\n\n postupdate(): void {\n this.invalid = false\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n for (const ev of ['keydown', 'keyup']) fn(ev, this.#onKey as EventListener)\n return this\n }\n\n reset(): void {\n this.invalid = false\n this.#on = {}\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onKey = (ev: KeyboardEvent): void => {\n if (!ev.isTrusted || this.bitByCode[ev.code] == null) return\n if (ev.type === 'keydown' && (ev.metaKey || ev.altKey || ev.ctrlKey)) return\n this.invalid = true\n this.#on[ev.code] = ev.type === 'keydown'\n ev.preventDefault()\n this.onEvent()\n }\n}\n", "import {\n type Box,\n type XY,\n xyAdd,\n xyDistance,\n xyMax,\n xyMin,\n xySub\n} from '../types/geo.ts'\n\nexport type PointType =\n (typeof pointTypeByPointerType)[keyof typeof pointTypeByPointerType]\n\nexport type PointEvent = {\n bits: number\n /** most recent click. */\n clickClient: XY | undefined\n drag: boolean\n ev: (typeof pointEvents)[number]\n id: number\n /**\n * cursors should only use the primary inputs to avoid flickering between\n * distant points. inputs may be only secondaries.\n */\n primary: boolean\n type: PointType | undefined\n xyClient: XY\n}\n\nconst pointTypeByPointerType = {\n mouse: 'Mouse',\n pen: 'Pen',\n touch: 'Touch'\n} as const\nconst pointEvents = [\n 'pointercancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup'\n] as const\n\n/** @internal */\nexport class Pointer {\n readonly bitByButton: {[btn: number]: number} = {}\n dragMinClient: number = 5\n invalid: boolean = false\n onEvent: () => void = () => {}\n /** primary may be on or off. */\n primary: Readonly<PointEvent> | undefined\n /**\n * secondaries are deleted when buttons are off. secondaries are only present\n * when primary is defined.\n */\n readonly secondary: {[id: number]: Readonly<PointEvent>} = {}\n /** nonnegative. */\n #pinchStartClient: XY | undefined\n readonly #target: Element\n\n constructor(target: Element) {\n this.#target = target\n }\n\n get boundsClient(): Box | undefined {\n if (!this.primary?.bits && !Object.keys(this.secondary).length) return\n let min = {x: Infinity, y: Infinity}\n let max = {x: -Infinity, y: -Infinity}\n for (const pt of [this.primary, ...Object.values(this.secondary)]) {\n if (!pt?.bits) continue\n min = xyMin(min, pt.xyClient)\n max = xyMax(max, pt.xyClient)\n }\n return {x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y}\n }\n\n get centerClient(): XY | undefined {\n const bounds = this.boundsClient\n if (!bounds) return this.primary?.xyClient\n return xyAdd(bounds, {x: bounds.w / 2, y: bounds.h / 2})\n }\n\n get locked(): boolean {\n return this.#target.ownerDocument.pointerLockElement === this.#target\n }\n\n get pinchClient(): XY | undefined {\n if (!this.#pinchStartClient) return\n const end = this.#newPinchClient\n return end ? xySub(end, this.#pinchStartClient) : undefined\n }\n\n postupdate(): void {\n this.invalid = false\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n for (const ev of pointEvents) fn(ev, this.#onInput as EventListener)\n return this\n }\n\n reset(): void {\n this.invalid = false\n this.primary = undefined\n for (const pt in this.secondary) delete this.secondary[pt]\n this.#pinchStartClient = undefined\n }\n\n update(): void {\n const on =\n (this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length\n if (on < 2 || !this.#pinchStartClient)\n this.#pinchStartClient = this.#newPinchClient\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #evButtonsToBits(btns: number): number {\n let bits = 0\n for (let btn = 1; btn <= btns; btn <<= 1)\n if ((btn & btns) === btn) bits |= this.bitByButton[btn] ?? 0\n return bits\n }\n\n #onInput = (ev: PointerEvent): void => {\n if (!ev.isTrusted) return\n\n this.invalid = true\n const bits =\n ev.metaKey || ev.altKey || ev.ctrlKey\n ? 0\n : this.#evButtonsToBits(ev.buttons)\n if (bits) ev.preventDefault() // only prevent mapped buttons.\n const locked = this.locked\n if (ev.type === 'pointerdown' && !locked)\n try {\n this.#target.setPointerCapture(ev.pointerId)\n } catch {}\n\n const prevPt = ev.isPrimary ? this.primary : this.secondary[ev.pointerId]\n\n let xyClient\n if (locked) {\n // `devicePixelRatio` seems to be incorrect. when zoom is 500%, DPR is 10.\n // in full screen, this would give the actual zoom allowing `movementX`\n // to match the `offsetX` delta:\n // const scale = document.documentElement.clientWidth / screen.availWidth\n // console.log(\n // `screenDelta=${ev.screenX - prevScreen.x} movementX=${ev.movementX} movementXScaled=${ev.movementX * scale} offsetDelta=${ev.offsetX - prevOffset.x} clientDelta=${ev.clientX - prevClient.x}`\n // )\n // probably wouldn't work across devices though.\n const scale = 1 / devicePixelRatio\n\n // to-do: this should allow offscreen.\n xyClient = {\n x: Math.min(\n Math.max(\n 0,\n (prevPt?.xyClient.x ?? ev.offsetX) + ev.movementX * scale\n ),\n this.#target.clientWidth\n ),\n y: Math.min(\n Math.max(\n 0,\n (prevPt?.xyClient.y ?? ev.offsetY) + ev.movementY * scale\n ),\n this.#target.clientHeight\n )\n }\n } else xyClient = {x: ev.offsetX, y: ev.offsetY}\n\n const evType = ev.type as (typeof pointEvents)[number]\n const type =\n pointTypeByPointerType[\n ev.pointerType as keyof typeof pointTypeByPointerType\n ]\n let clickClient\n if (ev.type === 'pointerdown') clickClient = {x: xyClient.x, y: xyClient.y}\n else if (ev.type === 'pointermove') clickClient = prevPt?.clickClient\n const drag =\n !!bits &&\n (prevPt?.drag ||\n (!!clickClient &&\n xyDistance(clickClient, xyClient) >= this.dragMinClient))\n\n const pt = {\n clickClient,\n bits,\n drag,\n ev: evType,\n id: ev.pointerId,\n primary: ev.isPrimary,\n type,\n xyClient\n }\n if (ev.isPrimary) this.primary = pt\n else if (!bits) delete this.secondary[ev.pointerId]\n else this.secondary[ev.pointerId] = pt\n\n this.onEvent()\n }\n\n get #newPinchClient(): XY | undefined {\n if ((this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length < 2)\n return\n const bounds = this.boundsClient\n return bounds ? {x: bounds.w, y: bounds.h} : undefined\n }\n}\n", "import type {XYZ} from '../types/geo.ts'\n\n/** @internal */\nexport class Wheel {\n deltaClient: Readonly<XYZ> | undefined\n onEvent: () => void = () => {}\n readonly #target: EventTarget\n\n constructor(target: EventTarget) {\n this.#target = target\n }\n\n postupdate(): void {\n this.deltaClient = undefined\n }\n\n register(op: 'add' | 'remove'): this {\n const fn = this.#target[`${op}EventListener`].bind(this.#target)\n fn('wheel', this.#onInput as EventListener, {passive: true})\n return this\n }\n\n reset(): void {\n this.deltaClient = undefined\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #onInput = (ev: WheelEvent): void => {\n if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return\n this.deltaClient = {x: ev.deltaX, y: ev.deltaY, z: ev.deltaZ}\n this.onEvent()\n }\n}\n", "import type {Cam, LevelClientLocalXY} from '../graphics/cam.ts'\nimport type {XY, XYZ} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {ContextMenu} from './context-menu.ts'\nimport {Gamepad} from './gamepad.ts'\nimport {Keyboard} from './keyboard.ts'\nimport type {PointType} from './pointer.ts'\nimport {Pointer} from './pointer.ts'\nimport {Wheel} from './wheel.ts'\n\nexport type Chord<Button> = [Button, ...Button[]]\nexport type Combo<Button> = [Chord<Button>, ...Chord<Button>[]]\n\n// biome-ignore format:;\nexport type DefaultButton =\n | 'L' | 'R' | 'U' | 'D' // dpad.\n | 'A' | 'B' | 'C' // primary, secondary, tertiary.\n | 'Click' | 'Click2' | 'ClickMiddle'\n | 'Menu' | 'Back'\n\nexport type Point = LevelClientLocalXY & {\n click: LevelClientLocalXY | undefined\n type: PointType | undefined\n}\n\n/**\n * doesn't consider handled. local and level positions are reevaluated each\n * frame.\n */\ntype PointerState = Point & {\n center: LevelClientLocalXY\n /** false when pinched. */\n drag: {on: boolean; start: boolean; end: boolean}\n /** true if changed since last update. */\n invalid: boolean\n /** may be negative. */\n pinch:\n | {\n client: XY\n /** level / local. */\n xy: XY\n }\n | undefined\n /** secondary points. */\n secondary: Point[]\n}\n\n/** triggered. */\ntype WheelState = {\n delta: {\n client: Readonly<XYZ>\n /** level / local. */\n xy: XY\n }\n}\n\n/**\n * input device abstraction. aggregates devices, records history, and provides\n * a convenient API.\n *\n * devices own as much device-specific detail and as little coordination (time\n * and device) as practical. devices avoid caching state which is the\n * responsibility of Input. devices strive to provide the current state and\n * nothing else.\n *\n * if you miss reporting on a event between long updates, you just miss it.\n * that's the nature of polling. there's no queue.\n *\n * to-do: expose analog state of gamepad. offer direction as a number instead of\n * bool.\n * to-do: multiplayer. possible if devices were requested instead of sought.\n * to-do: expose input source device.\n */\nexport class Input<Button extends string> {\n /** time allowed between combo inputs. */\n comboMaxIntervalMillis: Millis = 300 as Millis\n /**\n * true if any button, key, or click was _ever_ on. doesn't consider handled.\n */\n gestured: boolean = false\n /** clear buttonish inputs for rest of frame. */\n handled: boolean = false\n /** true if _any_ input has changed since previous update. */\n invalid: boolean = false\n /**\n * minimum duration for an input to be considered held. durations are\n * calculated at frame boundaries, not on actual press. devices are treated\n * strictly as polled aggregates.\n */\n minHeldMillis: Millis = 300 as Millis\n readonly #bitByButton: {[btn in Button]?: number} = {}\n readonly #buttonByBit: {[bit: number]: Button} = {}\n #bits: number = 0\n readonly #cam: Readonly<Cam>\n /**\n * sequence of nonzero bits ordered from oldest to latest. combos end only by\n * expiration.\n */\n readonly #combo: number[] = []\n readonly #contextMenu: ContextMenu\n readonly #gamepad: Gamepad\n /** time since buttons changed. */\n #heldMillis: Millis = 0 as Millis\n readonly #keyboard: Keyboard\n readonly #pointer: Pointer\n #pointerState: PointerState | undefined\n /** bits last update. may not be equal to `#combo.at(-1)`. */\n #prevBits: number = 0\n readonly #wheel: Wheel\n #wheelState: Readonly<WheelState> | undefined\n\n constructor(cam: Readonly<Cam>, target: Element) {\n this.#cam = cam\n this.#contextMenu = new ContextMenu(target)\n this.#gamepad = new Gamepad(globalThis)\n this.#keyboard = new Keyboard(target.ownerDocument)\n this.#pointer = new Pointer(target)\n this.#wheel = new Wheel(target)\n }\n\n get anyOn(): boolean {\n return this.#bits !== 0\n }\n\n /** for debugging. */\n get combo(): Button[][] {\n const chords: Button[][] = []\n for (const bits of this.#combo) {\n const chord: Button[] = []\n for (let bit = 1; bit <= bits; bit <<= 1) {\n if ((bit & bits) === bit && this.#buttonByBit[bit])\n chord.push(this.#buttonByBit[bit]!)\n }\n chord.sort()\n chords.push(chord)\n }\n return chords\n }\n\n /**\n * enable when game is paused or in photo mode to allow right clicks and long\n * presses to save canvas.\n */\n get contextMenu(): {enable: boolean} {\n return this.#contextMenu\n }\n\n /** doesn't consider handled. gamepads must be polled. */\n get gamepad(): Readonly<object | undefined> {\n return this.#gamepad.connected ? {} : undefined\n }\n\n /** true if bits hasn't changed for a while. */\n get held(): boolean {\n return !this.handled && this.#heldMillis >= this.minHeldMillis\n }\n\n isAnyOn(...btns: Readonly<Chord<Button>>): boolean {\n return !this.handled && !!(this.#bits & this.#mapBits(btns))\n }\n\n isAnyOnStart(...btns: Readonly<Chord<Button>>): boolean {\n return this.started && this.isAnyOn(...btns)\n }\n\n /**\n * buttons are exact. eg, up won't match up AND down like `isOn('U')` will.\n * combo is exact too. `['A'], ['A']` will match `['A'], ['A']` but not\n * `['A'], ['A'], ['A']`.\n */\n isCombo(...combo: Readonly<Combo<Button>>): boolean {\n return combo.length === this.#combo.length && this.isComboEndsWith(...combo)\n }\n\n /**\n * `['A'], ['A']` will match `['A'], ['A']` and `['B'], ['A'], ['A']`. eg,\n * double-clicks often don't care about any preceding buttons.\n */\n isComboEndsWith(...combo: Readonly<Combo<Button>>): boolean {\n for (const [i, btns] of combo.entries()) {\n const bits = this.#mapBits(btns)\n if (this.#combo.at(-combo.length + i) !== bits) return false\n }\n // #combo is a historical record of buttons. whenever buttons changes, a new\n // entry is pushed. make sure the current entry is the current state.\n return !this.handled && (this.#combo.at(-1) === this.#bits || !this.#bits)\n }\n\n /** like isComboEndsWith() but test if the last button is triggered. */\n isComboEndsWithStart(...combo: Readonly<Combo<Button>>): boolean {\n // isOnStart() can handle zero-length.\n return this.isOnStart(...combo.at(-1)!) && this.isComboEndsWith(...combo)\n }\n\n /** like isCombo() but test if the last button is triggered. */\n isComboStart(...combo: Readonly<Combo<Button>>): boolean {\n return this.isOnStart(...combo.at(-1)!) && this.isCombo(...combo)\n }\n\n /*:\n * true if any button in chord is not on. this is usually what's wanted. eg:\n * ```ts\n * if (isOn('A', 'B')) console.log('on')\n * if (isOff('A', 'B')) console.log('not A+B; A and/or B is off')\n * ```\n */\n isOff(...btns: Readonly<Chord<Button>>): boolean {\n return !this.handled && !this.isOn(...btns)\n }\n\n isOffStart(...btns: Readonly<Chord<Button>>): boolean {\n const bits = this.#mapBits(btns)\n const wasOn = (this.#prevBits & bits) === bits\n // don't test this.#bits === 0 since it might forever miss the off event for\n // the specific bits.\n return wasOn && this.started && this.isOff(...btns)\n }\n\n /**\n * true if all buttons are on inclusively. eg, `isOn('U')` is true when up is\n * pressed or when up and down are pressed.\n */\n isOn(...btns: Readonly<Chord<Button>>): boolean {\n const bits = this.#mapBits(btns)\n return !this.handled && (this.#bits & bits) === bits\n }\n\n isOnStart(...btns: Readonly<Chord<Button>>): boolean {\n return this.started && this.isOn(...btns)\n }\n\n get key(): {invalid: boolean} {\n return {invalid: this.#keyboard.invalid}\n }\n\n mapDefault(): Input<Button | DefaultButton> {\n const input = this as Input<Button | DefaultButton>\n input.mapKeyboardCode('L', 'ArrowLeft')\n input.mapKeyboardCode('R', 'ArrowRight')\n input.mapKeyboardCode('U', 'ArrowUp')\n input.mapKeyboardCode('D', 'ArrowDown')\n input.mapKeyboardCode('C', 'KeyC')\n input.mapKeyboardCode('A', 'KeyX')\n input.mapKeyboardCode('B', 'KeyZ')\n input.mapKeyboardCode('Menu', 'Enter')\n input.mapKeyboardCode('Back', 'Escape')\n\n // https://w3c.github.io/gamepad/#remapping\n input.mapGamepadAxis('L', 'R', 0, 2)\n input.mapGamepadAxis('U', 'D', 1, 3)\n input.mapGamepadButton('L', 14)\n input.mapGamepadButton('R', 15)\n input.mapGamepadButton('U', 12)\n input.mapGamepadButton('D', 13)\n input.mapGamepadButton('C', 2)\n input.mapGamepadButton('B', 0) // to-do: not good from PS perspective.\n input.mapGamepadButton('A', 1) // to-do: not good from PS perspective.\n input.mapGamepadButton('Menu', 9)\n input.mapGamepadButton('Back', 8)\n\n input.mapPointerClick('Click', 1)\n input.mapPointerClick('Click2', 2)\n input.mapPointerClick('ClickMiddle', 4)\n return input\n }\n\n // to-do: support analog values.\n mapGamepadAxis(less: Button, more: Button, ...axes: readonly number[]): void {\n for (const axis of axes) {\n this.#gamepad.bitByAxis[axis] = [\n this.#mapButton(less),\n this.#mapButton(more)\n ]\n }\n }\n\n mapGamepadButton(btn: Button, ...indices: readonly number[]): void {\n for (const index of indices)\n this.#gamepad.bitByButton[index] = this.#mapButton(btn)\n }\n\n /** @arg codes union of KeyboardEvent.code. */\n mapKeyboardCode(btn: Button, ...codes: readonly string[]): void {\n for (const code of codes)\n this.#keyboard.bitByCode[code] = this.#mapButton(btn)\n }\n\n mapPointerClick(btn: Button, ...clicks: readonly number[]): void {\n for (const click of clicks)\n this.#pointer.bitByButton[click] = this.#mapButton(btn)\n }\n\n get on(): Button[] {\n const on: Button[] = []\n for (const btn in this.#bitByButton) if (this.isOn(btn)) on.push(btn)\n return on.sort()\n }\n\n set onEvent(cb: () => void) {\n this.#gamepad.onEvent = cb\n this.#keyboard.onEvent = cb\n this.#pointer.onEvent = cb\n this.#wheel.onEvent = cb\n }\n\n /** doesn't consider handled. */\n get point(): PointerState | undefined {\n return this.#pointerState\n }\n\n get pointer(): {dragMinClient: number} {\n return this.#pointer\n }\n\n register(op: 'add' | 'remove'): this {\n globalThis[`${op}EventListener`]('blur', this.reset) // keyup is lost if window loses focus.\n this.#contextMenu.register(op)\n this.#gamepad.register(op)\n this.#keyboard.register(op)\n this.#pointer.register(op)\n this.#wheel.register(op)\n return this\n }\n\n reset = (): void => {\n this.#bits = 0\n this.#prevBits = 0\n this.handled = false\n this.#heldMillis = 0 as Millis\n this.#combo.length = 0\n this.#gamepad.reset()\n this.#keyboard.reset()\n this.#pointer.reset()\n this.#pointerState = undefined\n this.#wheel.reset()\n this.#wheelState = undefined\n }\n\n /** true if bits has changed. */\n get started(): boolean {\n return !this.handled && this.#bits !== this.#prevBits\n }\n\n /**\n * call on new frame before altering cam. dispatches always occur before an\n * update.\n * @arg millis duration since last update.\n */\n update(millis: Millis): void {\n this.handled = false\n this.#gamepad.update()\n this.#pointer.update()\n\n this.#prevBits = this.#bits\n this.#bits =\n this.#gamepad.bits |\n this.#keyboard.bits |\n (this.#pointer.primary?.bits ?? 0)\n this.invalid =\n this.#bits !== this.#prevBits ||\n this.#pointer.invalid ||\n !!this.#wheel.deltaClient\n this.gestured ||= !!this.#bits\n\n if (\n (millis > this.comboMaxIntervalMillis && this.#bits !== this.#prevBits) ||\n (this.#heldMillis + millis > this.comboMaxIntervalMillis && !this.#bits)\n )\n this.#combo.length = 0\n\n if (this.#bits === this.#prevBits)\n this.#heldMillis = (this.#heldMillis + millis) as Millis\n else this.#heldMillis = millis\n\n if (this.#bits && this.#bits !== this.#prevBits) {\n if (this.#prevBits) this.#combo.length = 0 // new button without release.\n this.#combo.push(this.#bits)\n }\n\n if (this.#pointer.primary) {\n const pinchClient = this.#pointer.pinchClient\n const dragOn =\n this.#pointer.primary.drag &&\n !Object.values(this.#pointer.secondary).length\n const secondary: Point[] = []\n for (const pt of Object.values(this.#pointer.secondary)) {\n secondary.push({\n type: pt.type,\n click: pt.clickClient\n ? {\n client: pt.clickClient,\n local: this.#cam.clientToXYLocal(pt.clickClient),\n ...this.#cam.clientToXY(pt.clickClient)\n }\n : undefined,\n ...this.#cam.clientToXY(pt.xyClient),\n client: pt.xyClient,\n local: this.#cam.clientToXYLocal(pt.xyClient)\n })\n }\n const centerClient = this.#pointer.centerClient!\n const center = {\n client: centerClient,\n local: this.#cam.clientToXYLocal(centerClient),\n ...this.#cam.clientToXY(centerClient)\n }\n this.#pointerState = {\n center,\n click: this.#pointer.primary.clickClient\n ? {\n client: this.#pointer.primary.clickClient,\n local: this.#cam.clientToXYLocal(\n this.#pointer.primary.clickClient\n ),\n ...this.#cam.clientToXY(this.#pointer.primary.clickClient)\n }\n : undefined,\n drag: {\n on: dragOn,\n start: !this.#pointerState?.drag.on && dragOn,\n end: !!this.#pointerState?.drag.on && !dragOn\n },\n invalid: this.#pointer.invalid,\n pinch: pinchClient\n ? {client: pinchClient, xy: this.#cam.clientToXY(pinchClient)}\n : undefined,\n secondary,\n type: this.#pointer.primary.type,\n ...this.#cam.clientToXY(this.#pointer.primary.xyClient),\n client: this.#pointer.primary.xyClient,\n local: this.#cam.clientToXYLocal(this.#pointer.primary.xyClient)\n }\n }\n // secondary should never be set when primary isn't.\n else this.#pointerState = undefined\n\n this.#wheelState = this.#wheel.deltaClient\n ? {\n delta: {\n client: this.#wheel.deltaClient,\n xy: this.#cam.clientToXY(this.#wheel.deltaClient)\n }\n }\n : undefined\n this.#keyboard.postupdate()\n this.#pointer.postupdate()\n this.#wheel.postupdate()\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n /** doesn't consider handled. */\n get wheel(): Readonly<WheelState | undefined> {\n return this.#wheelState\n }\n\n /** get bits for buttons. */\n #mapBits(btns: Readonly<Chord<Button>>): number {\n let bits = 0\n for (const btn of btns) bits |= this.#bitByButton[btn] ?? 0\n return bits\n }\n\n /** assign button to bit. */\n #mapButton(btn: Button): number {\n const bit = (this.#bitByButton[btn] ??=\n 1 << Object.keys(this.#bitByButton).length)\n this.#buttonByBit[bit] = btn\n return bit\n }\n}\n", "import {debug} from '../utils/debug.ts'\n\nexport type PoolOpts<out T extends Block> = {\n alloc(pool: Pool<T>): T\n allocBytes: number\n minPages?: number\n pageBlocks: number\n}\n\nexport type Block = {/** variable pool byte offset. */ i: number}\n\n/**\n * a contiguous resizable TypedArray associated with an array of objects.\n *\n * alternatives:\n * - operating on the array without classes would probably be faster but the DX\n * sucks:\n * this.#sprite = this.#pool.alloc()\n * this.#pool.setX(this.#sprite, this.#pool.getX(this.#sprite) + 1)\n * - sprite classes owning all the data is nice DX but requires a copy on every\n * frame.\n * - ArrayBuffer.resize() is incompatible with WebGL.\n */\nexport class Pool<out T extends Block> {\n /** the next free block is always at size. */\n readonly #blocks: T[]\n readonly #opts: Readonly<Required<PoolOpts<T>>>\n #size: number = 0\n #u8: Uint8Array<ArrayBuffer>\n #view!: DataView<ArrayBuffer>\n\n constructor(opts: Readonly<PoolOpts<T>>) {\n if (opts.allocBytes <= 0) throw Error('byte allocation must be > 0')\n if (opts.pageBlocks <= 0) throw Error('page blocks must be > 0')\n this.#opts = {...opts, minPages: opts.minPages ?? 1}\n const initSize = this.#opts.minPages * opts.pageBlocks\n this.#blocks = new Array(initSize)\n this.#u8 = new Uint8Array()\n this.#resize(initSize, 'Init')\n }\n\n alloc(): T {\n if (this.#size >= this.#currentCapacity)\n this.#resize(this.#currentCapacity + this.#opts.pageBlocks, 'Call')\n const block = this.#blocks[this.#size]!\n block.i = this.#size * this.#opts.allocBytes\n this.#size++\n return block\n }\n\n clear(): void {\n this.#size = 0\n const minCapacity = this.#opts.minPages * this.#opts.pageBlocks\n if (this.#currentCapacity > minCapacity) this.#resize(minCapacity, 'Call')\n }\n\n free(...blocks: readonly T[]): void {\n for (const block of blocks) this.#freeBlock(block)\n }\n\n get size(): number {\n return this.#size\n }\n\n get view(): DataView<ArrayBuffer> {\n return this.#view\n }\n\n toDebugString(): string {\n let str = ''\n for (let i = 0; i < this.#u8.buffer.byteLength; i++) {\n if (i && !(i % this.#opts.allocBytes)) str += ' '\n str += this.#u8[i]!.toString(16).padStart(2, '0')\n }\n return str\n }\n\n get #currentCapacity(): number {\n return this.#u8.buffer.byteLength / this.#opts.allocBytes\n }\n\n #freeBlock(block: T): void {\n if (!this.#size) throw Error('pool underflow')\n\n this.#size--\n const start = this.#size * this.#opts.allocBytes\n this.#u8.copyWithin(block.i, start, start + this.#opts.allocBytes)\n this.#blocks[this.#size]!.i = block.i\n ;[this.#blocks[block.i], this.#blocks[this.#size]] = [\n this.#blocks[this.#size]!,\n this.#blocks[block.i]!\n ]\n\n const free = Math.floor(\n (this.#currentCapacity - this.#size) / this.#opts.pageBlocks\n )\n if (\n free &&\n this.#currentCapacity / this.#opts.pageBlocks - free >=\n this.#opts.minPages\n )\n this.#resize(this.#currentCapacity - free * this.#opts.pageBlocks, 'Call')\n }\n\n #resize(capacity: number, origin: 'Init' | 'Call'): void {\n if (origin === 'Call' && debug?.mem)\n console.debug(\n `[mem] ${capacity < this.#currentCapacity ? 'shrinking' : 'growing'} pool to ${capacity}`\n )\n\n this.#blocks.length = capacity\n for (let i = this.#currentCapacity; i < capacity; i++)\n this.#blocks[i] = this.#opts.alloc(this)\n\n const buffer = new ArrayBuffer(capacity * this.#opts.allocBytes)\n const u8 = new Uint8Array(buffer)\n u8.set(this.#u8.subarray(0, capacity * this.#opts.allocBytes))\n this.#u8 = u8\n this.#view = new DataView(buffer)\n }\n}\n", "export function rgbaHex(rgba: number): `#${string}` {\n return `#${rgba.toString(16).padStart(8, '0')}`\n}\n", "import {rgbaHex} from './color-util.ts'\n\nexport function download(uri: string, filename: string): void {\n const a = document.createElement('a')\n a.href = uri\n a.download = filename\n a.click()\n a.remove()\n}\n\nexport function initBody(\n canvas: Readonly<HTMLCanvasElement>,\n rgba: number\n): void {\n if (canvas.parentNode !== document.body) return\n document.body.style.margin = '0'\n // fill the screen except for UI chrome.\n document.body.style.width = '100dvw'\n document.body.style.height = '100dvh'\n document.body.style.overflow = 'hidden'\n document.body.style.background = rgbaHex(rgba)\n}\n\nexport function initMetaViewport(): void {\n if (document.querySelector('meta[name=\"viewport\"]')) return\n const meta = document.createElement('meta')\n meta.name = 'viewport'\n // don't wait for double-tap scaling on mobile.\n meta.content =\n 'width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no'\n document.head.appendChild(meta)\n}\n", "import {dateToTimestamp} from '../types/time.ts'\nimport {download} from './dom-util.ts'\n\nexport async function downloadScreenshot(\n canvas: HTMLCanvasElement,\n name: string\n): Promise<void> {\n using img = await screenshot(canvas)\n download(img.uri, `${name}-screenshot-${dateToTimestamp(new Date())}.webp`)\n}\n\nexport function initCanvas(\n canvas: HTMLCanvasElement | undefined,\n mode: 'Int' | 'Fraction'\n): HTMLCanvasElement {\n canvas ??= document.createElement('canvas')\n canvas.width = 0 // guarantee Renderer.#resize().\n canvas.style.cursor = 'none'\n canvas.style.display = 'block' // no line height spacing.\n canvas.style.outline = 'none' // disable focus outline.\n canvas.style.cursor = 'none'\n if (mode === 'Int') canvas.style.imageRendering = 'pixelated' // to-do: why doesn't cam mode set this?\n // update on each pointermove *touch* Event like *mouse* Events.\n canvas.style.touchAction = 'none'\n canvas.tabIndex = 0\n canvas.focus()\n if (!canvas.parentNode) document.body.append(canvas)\n return canvas\n}\n\nexport async function requestFullscreen(\n canvas: HTMLCanvasElement\n): Promise<boolean> {\n if (!document.fullscreenEnabled) return false\n\n if (document.fullscreenElement !== canvas)\n try {\n await canvas.requestFullscreen({navigationUI: 'hide'})\n } catch {\n return false\n }\n\n if (!document.pointerLockElement) {\n try {\n await canvas.requestPointerLock({unadjustedMovement: true})\n } catch (err) {\n if (err instanceof Error && err.name === 'NotSupportedError')\n try {\n await canvas.requestPointerLock()\n } catch {}\n }\n }\n\n return true\n}\n\n/** draws a canvas to a blob URI. */\nexport function screenshot(\n canvas: HTMLCanvasElement\n): Promise<Disposable & {uri: string}> {\n return new Promise((fulfil, reject) => {\n canvas.toBlob(blob => {\n if (blob) {\n const img = {\n [Symbol.dispose]() {\n URL.revokeObjectURL(this.uri)\n },\n uri: URL.createObjectURL(blob)\n }\n fulfil(img)\n } else reject(Error('no blob'))\n }, 'image/webp')\n })\n}\n", "export async function fetchAudio(url: string): Promise<ArrayBuffer> {\n const rsp = await fetch(url, {headers: {accept: 'audio/mpeg'}})\n if (!rsp.ok)\n throw Error(`fetch error ${rsp.status}: ${rsp.statusText} for ${url}`)\n const type = rsp.headers.get('Content-Type')\n // to-do: ogg\n if (!type?.startsWith('audio/mpeg'))\n throw Error(`bad fetch response type ${type} for ${url}`)\n return await rsp.arrayBuffer()\n}\n\nexport function fetchImage(url: string): Promise<HTMLImageElement> {\n const img = new Image()\n const promise = loadImage(img)\n img.src = url\n return promise\n}\n\nexport async function loadImage(\n img: HTMLImageElement\n): Promise<HTMLImageElement> {\n const promise = new Promise<HTMLImageElement>((fulfil, reject) => {\n img.onload = () => fulfil(img)\n img.onerror = () => reject(Error(`image load error for ${img.src}`))\n })\n return img.complete ? img : await promise\n}\n", "import {debug} from '../utils/debug.ts'\n\n/** @internal */\nexport type GL2 = WebGL2RenderingContext\n/** @internal */\nexport type GLProgram = WebGLProgram\n/** @internal */\nexport type GLShader = WebGLShader\n/** @internal */\nexport type GLTexture = WebGLTexture\n/** @internal */\nexport type GLUniformLocation = WebGLUniformLocation\n/** @internal */\nexport type GLUniformMap = {[name: string]: GLUniformLocation}\n\n/** @internal */\nexport type Shader = {\n program: GLProgram | null\n buffer: WebGLBuffer | null\n uniform: GLUniformMap\n vao: WebGLVertexArrayObject | null\n textures: GLTexture[]\n}\n\n/** @internal */\nexport function Shader(\n gl: GL2,\n vertGLSL: string,\n fragGLSL: string,\n textures: GLTexture[]\n): Shader {\n const program = loadProgram(gl, vertGLSL, fragGLSL)\n gl.useProgram(program)\n return {\n buffer: gl.createBuffer(),\n program,\n textures,\n uniform: GLUniformMap(gl, program),\n vao: gl.createVertexArray()\n }\n}\n\nfunction GLUniformMap(gl: GL2, pgm: GLProgram | null): GLUniformMap {\n const len = pgm ? gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS) : 0\n const map = debug?.render\n ? new Proxy<GLUniformMap>(\n {},\n {\n get(target, k: string): GLUniformLocation {\n if (target[k] == null) throw Error(`no shader uniform \"${k}\"`)\n return target[k]\n }\n }\n )\n : {}\n for (let i = 0; i < len; ++i) {\n const uniform = gl.getActiveUniform(pgm!, i)\n if (!uniform) throw Error(`no shader uniform at index ${i}`)\n const location = gl.getUniformLocation(pgm!, uniform.name)\n if (!location) throw Error(`no shader uniform \"${uniform.name}\"`)\n const name = uniform.name.replace('[0]', '') // arrays.\n map[name] = location\n }\n return map\n}\n\nfunction loadProgram(\n gl: GL2,\n vertGLSL: string,\n fragGLSL: string\n): GLProgram | null {\n const pgm = gl.createProgram()\n if (!pgm) return null\n\n const vert = compileShader(gl, 'VERTEX_SHADER', vertGLSL)\n const frag = compileShader(gl, 'FRAGMENT_SHADER', fragGLSL)\n if (!vert || !frag) return null\n gl.attachShader(pgm, vert)\n gl.attachShader(pgm, frag)\n gl.linkProgram(pgm)\n\n if (debug?.render && !gl.getProgramParameter(pgm, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(pgm)?.slice(0, -1)\n throw Error(`shader link failure; ${log}`)\n }\n\n gl.detachShader(pgm, frag)\n gl.detachShader(pgm, vert)\n gl.deleteShader(frag)\n gl.deleteShader(vert)\n\n return pgm\n}\n\nfunction compileShader(\n gl: GL2,\n type: 'FRAGMENT_SHADER' | 'VERTEX_SHADER',\n glsl: string\n): GLShader | null {\n const shader = gl.createShader(gl[type])\n if (!shader) return shader\n gl.shaderSource(shader, glsl.trim())\n gl.compileShader(shader)\n\n if (debug?.render && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader)?.slice(0, -1)\n throw Error(`shader compile failure; ${log}`)\n }\n\n return shader\n}\n", "export const spriteFragGLSL: string = `#version 300 es\n#pragma debug(${debug?.render ? 'on' : 'off'}) \n#pragma optimize(${debug?.render ? 'off' : 'on'})\n\nprecision highp int;\nprecision highp float;\nprecision highp usampler2D;\n\nuniform sampler2D uTex;\nuniform uvec2 uTexWH;\n\nflat in uint vStretch;\nflat in ivec4 vTexXYWH;\nflat in int vZ;\nin vec2 vDstWH;\nflat in ivec2 vDstWHFixed;\n\nout vec4 oRGBA;\n\nvoid main() {\n if (vZ == ${Layer.Hidden} || vDstWHFixed.x == 0 || vDstWHFixed.y == 0)\n discard;\n\n vec2 px = vec2(vTexXYWH.xy) + (\n vStretch == 1u ? (vDstWH * vec2(vTexXYWH.zw) / vec2(vDstWHFixed))\n : mod(vDstWH, vec2(vTexXYWH.zw))\n );\n\n oRGBA = texture(uTex, px / vec2(uTexWH));\n if(oRGBA.a < .001) discard;\n}\n`\n\nimport {debug} from '../utils/debug.ts'\nimport {Layer} from './layer.ts'\n", "export const spriteVertGLSL: string = `#version 300 es\n#pragma debug(${debug?.render ? 'on' : 'off'}) \n#pragma optimize(${debug?.render ? 'off' : 'on'})\n\n// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2\nprecision highp int;\nprecision highp float;\nprecision highp usampler2D;\n\nuniform ivec4 uCam;\nuniform usampler2D uCels;\nuniform float uAge;\n\nlayout (location=0) in ivec2 iUV;\nlayout (location=1) in uint iy8_x24;\nlayout (location=2) in uint iw8_sxyz_llll_y16;\nlayout (location=3) in uint ii11_c5_h12_w4;\n\nconst int maxY = 0x20000;\nconst int layers = 16;\nconst int maxDepth = maxY * layers;\n\nflat out uint vStretch;\nflat out ivec4 vTexXYWH;\nflat out int vZ;\nout vec2 vDstWH;\nflat out ivec2 vDstWHFixed;\n\nvoid main() {\n int x = (int((iy8_x24 & 0xffffffu) << 8) >> 8) / 64;\n int y = (int(iy8_x24 >> 24) | (int(iw8_sxyz_llll_y16 & 0xffffu) << 16 >> 8)) / 64;\n int z = int((iw8_sxyz_llll_y16 >> 16) & 0xfu);\n bool zend = bool(iw8_sxyz_llll_y16 & 0x100000u);\n bool flipY = bool(iw8_sxyz_llll_y16 & 0x200000u);\n bool flipX = bool(iw8_sxyz_llll_y16 & 0x400000u);\n bool stretch = bool(iw8_sxyz_llll_y16 & 0x800000u);\n int id = int((ii11_c5_h12_w4 >> 17) & 0x7ff0u); // ignore cel.\n int cel = int((ii11_c5_h12_w4 >> 16) & 0xfu); // ignore the MSB.\n int w = int(((ii11_c5_h12_w4 & 0xfu) << 8) | (iw8_sxyz_llll_y16 >> 24));\n int h = int((ii11_c5_h12_w4 >> 4) & 0xfffu);\n\n // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel\n float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);\n\n ivec2 targetWH = iUV * ivec2(w, h);\n\n vec2 end = vec2(x + targetWH.x, y + targetWH.y);\n // UI layers are always given in screen coordinates.\n // to-do: how to handle non-int mode?\n vec2 camXY = z < ${Layer.A} ? vec2(0, 0) : vec2(uCam.xy);\n vec2 clip = ((-2. * camXY + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);\n gl_Position = vec4(clip, depth, 1);\n\n int frame = (((int(uAge / ${celMillis}) & 0x1f) - cel) + ${animCels}) & 0xf;\n uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);\n vTexXYWH = ivec4(texXYWH);\n vZ = z;\n\n vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));\n vDstWHFixed = ivec2(w, h) * ivec2(flipX ? -1 : 1, flipY ? -1 : 1);\n\n vStretch = stretch ? 1u : 0u;\n}\n`\n\nimport {debug} from '../utils/debug.ts'\nimport {animCels, celMillis} from './atlas.ts'\nimport {Layer} from './layer.ts'\n", "import type {Pool} from '../mem/pool.ts'\nimport {type WH, whEq} from '../types/geo.ts'\nimport type {Millis} from '../types/time.ts'\nimport {debug} from '../utils/debug.ts'\nimport type {Atlas, TagFormat} from './atlas.ts'\nimport type {Cam} from './cam.ts'\nimport {type GL2, Shader} from './gl.ts'\nimport {drawableBytes, type Sprite} from './sprite.ts'\nimport {spriteFragGLSL} from './sprite-frag.glsl.ts'\nimport {spriteVertGLSL} from './sprite-vert.glsl.ts'\n\n/** @internal */\nexport type Context = {gl: GL2; spriteShader: Shader; viewport: WH}\n\nconst uv: Readonly<Int8Array> = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0])\n\nexport class Renderer {\n /** when off, ents should avoid requesting renders. */\n always: boolean = debug?.render === 'always'\n clears: number = 0\n invalid: boolean = false\n loseContext: WEBGL_lose_context | undefined\n readonly #canvas: HTMLCanvasElement\n #clearRGBA: number = 0\n #depth: boolean = true\n #ctx: Context | undefined\n readonly #looper: {readonly age: Millis}\n readonly #preloadAtlas: Readonly<Atlas>\n #preloadAtlasImage: Readonly<HTMLImageElement> | undefined\n\n constructor(\n preloadAtlas: Readonly<Atlas>,\n canvas: HTMLCanvasElement,\n looper: {readonly age: Millis}\n ) {\n this.#preloadAtlas = preloadAtlas\n this.#canvas = canvas\n this.#looper = looper\n }\n\n clear(rgba: number): void {\n if (!this.#ctx) return\n const {gl} = this.#ctx\n if (this.#clearRGBA !== rgba) {\n this.#clearRGBA = rgba\n gl.clearColor(\n ((rgba >>> 24) & 0xff) / 0xff,\n ((rgba >>> 16) & 0xff) / 0xff,\n ((rgba >>> 8) & 0xff) / 0xff,\n ((rgba >>> 0) & 0xff) / 0xff\n )\n }\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)\n this.clears++\n }\n\n draw(pool: Readonly<Pool<Sprite<TagFormat>>>): void {\n if (!this.#preloadAtlasImage || !this.#ctx) return\n const {gl, spriteShader} = this.#ctx\n\n gl.bindBuffer(gl.ARRAY_BUFFER, spriteShader.buffer)\n gl.bufferData(\n gl.ARRAY_BUFFER,\n pool.view,\n gl.DYNAMIC_DRAW,\n 0,\n pool.size * drawableBytes\n )\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindVertexArray(spriteShader.vao)\n gl.drawArraysInstanced(\n gl.TRIANGLE_STRIP,\n 0,\n uv.length / 2, // d\n pool.size\n )\n gl.bindVertexArray(null)\n\n this.invalid = false\n }\n\n get hasContext(): boolean {\n return this.#ctx != null\n }\n\n load(preloadAtlas: Readonly<HTMLImageElement> | undefined): void {\n this.#preloadAtlasImage = preloadAtlas\n this.#ctx = this._Context()\n }\n\n predraw(cam: Readonly<Cam>): void {\n if (!this.#ctx) return\n const {gl, spriteShader, viewport} = this.#ctx\n\n if (!whEq(viewport, cam)) {\n gl.viewport(0, 0, cam.w, cam.h)\n viewport.w = cam.w\n viewport.h = cam.h\n }\n\n gl.useProgram(spriteShader.program)\n\n gl.uniform4i(spriteShader.uniform.uCam!, cam.x, cam.y, cam.w, cam.h)\n gl.uniform1f(spriteShader.uniform.uAge!, this.#looper.age)\n\n for (const [i, tex] of spriteShader.textures.entries()) {\n gl.activeTexture(gl.TEXTURE0 + i)\n gl.bindTexture(gl.TEXTURE_2D, tex)\n }\n }\n\n register(op: 'add' | 'remove'): this {\n this.#canvas[`${op}EventListener`]('webglcontextlost', this.#onContextLost)\n this.#canvas[`${op}EventListener`](\n 'webglcontextrestored',\n this.#onContextRestored\n )\n return this\n }\n\n setDepth(enable: boolean): void {\n this.#depth = enable\n if (!this.#ctx) return\n if (enable) this.#ctx.gl.enable(this.#ctx.gl.DEPTH_TEST)\n else this.#ctx.gl.disable(this.#ctx.gl.DEPTH_TEST)\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n /** @internal */\n _Context(): Context | undefined {\n const gl = this.#ctx?.gl ?? GL2(this.#canvas)\n if (!gl) return\n\n const shader = Shader(gl, spriteVertGLSL, spriteFragGLSL, [\n gl.createTexture(),\n gl.createTexture()\n ])\n\n // allow translucent textures to be layered.\n gl.enable(gl.BLEND)\n gl.blendFuncSeparate(\n gl.SRC_ALPHA,\n gl.ONE_MINUS_SRC_ALPHA,\n gl.ONE,\n gl.ONE_MINUS_SRC_ALPHA\n )\n\n this.setDepth(this.#depth)\n\n // enable z-buffer for [0, 1] ([foreground, background]).\n gl.depthRange(0, 1)\n gl.clearDepth(1)\n gl.depthFunc(gl.LESS)\n\n // disable image colorspace conversions. the default is browser dependent.\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false)\n\n gl.bindVertexArray(shader.vao)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())\n gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW)\n gl.enableVertexAttribArray(0)\n gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, shader.buffer)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, drawableBytes, 0)\n gl.vertexAttribDivisor(1, 1)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, drawableBytes, 4)\n gl.vertexAttribDivisor(2, 1)\n gl.enableVertexAttribArray(3)\n gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, drawableBytes, 8)\n gl.vertexAttribDivisor(3, 1)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindTexture(gl.TEXTURE_2D, shader.textures[0]!)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n if (this.#preloadAtlasImage)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n this.#preloadAtlasImage\n )\n gl.bindTexture(gl.TEXTURE_2D, null)\n\n gl.bindTexture(gl.TEXTURE_2D, shader.textures[1]!)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA16UI, // source XYWH cannot be > 65535.\n 1,\n this.#preloadAtlas.celXYWH.length / 4, // 4 u16s per row\n 0,\n gl.RGBA_INTEGER,\n gl.UNSIGNED_SHORT,\n new Uint16Array(this.#preloadAtlas.celXYWH)\n )\n gl.bindTexture(gl.TEXTURE_2D, null)\n\n gl.bindVertexArray(null)\n\n gl.uniform1i(shader.uniform.uTex!, 0)\n gl.uniform1i(shader.uniform.uCels!, 1)\n if (this.#preloadAtlasImage)\n gl.uniform2ui(\n shader.uniform.uTexWH!,\n this.#preloadAtlasImage.naturalWidth,\n this.#preloadAtlasImage.naturalHeight\n )\n\n if (!this.invalid && debug?.invalid) console.debug('renderer invalid')\n this.invalid = true\n // keep outside of #context so it can be restored.\n this.loseContext = gl.getExtension('WEBGL_lose_context') ?? undefined\n return (this.#ctx = {gl, spriteShader: shader, viewport: {w: 0, h: 0}})\n }\n\n #onContextLost = (ev: Event): void => {\n ev.preventDefault() // required.\n console.debug('[render] WebGL context lost')\n this.#ctx = undefined\n }\n\n #onContextRestored = (): void => {\n console.debug('[render] WebGL context restored')\n this.#ctx = this._Context()\n }\n}\n\nfunction GL2(canvas: HTMLCanvasElement): GL2 | undefined {\n const gl = canvas.getContext('webgl2', {\n // to-do: expose.\n antialias: false,\n powerPreference: 'low-power',\n // avoid flicker caused by clearing the drawing buffer. see\n // https://developer.chrome.com/blog/desynchronized/.\n preserveDrawingBuffer: true,\n ...(!debug?.render && {desynchronized: true})\n })\n if (!gl) {\n console.debug('[render] no GL context')\n return\n }\n\n if (debug?.render && !gl.getContextAttributes()?.desynchronized)\n console.debug('[render] no WebGL DOM desynchronization')\n\n return gl\n}\n", "import type {Millis} from './types/time.ts'\n\n/**\n * frame manager. passes frame requests when not hidden. callers should request\n * frames when an update occurs or a check for an update occurs. eg, gamepads\n * must be polled.\n *\n * when registered, restoring visibility triggers an automatic request.\n */\nexport class Looper {\n /** duration of frames observed. */\n age: Millis = 0 as Millis\n onFrame: ((millis: Millis) => void) | undefined\n #req: number = 0\n #registered: boolean = false\n\n register(op: 'add' | 'remove'): this {\n const fn = `${op}EventListener` as const\n document[fn]('visibilitychange', this.#onVisibility)\n if (op === 'remove') this.#cancel()\n // try to let user drive initial frame since assets may be loading.\n this.#registered = op === 'add'\n return this\n }\n\n requestFrame(): void {\n if (this.#req || document.hidden || !this.#registered) return\n this.#req = requestAnimationFrame(this.#onFrame as FrameRequestCallback)\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n\n #cancel(): void {\n if (this.#req) cancelAnimationFrame(this.#req)\n this.#req = 0\n }\n\n #onFrame = (now: Millis): void => {\n const millis = (now - (this.age || now)) as Millis\n this.age = now\n this.#req = 0\n this.onFrame?.(millis)\n }\n\n #onVisibility = (ev: Event): void => {\n if (!ev.isTrusted) return\n if (document.hidden) this.#cancel()\n else this.requestFrame()\n }\n}\n", "import type {Millis} from '../types/time.ts'\n\nexport class DelayInterval {\n #delay: () => Millis\n #interval: Millis\n #intervalID: number = 0\n #onInterval: () => void\n #timerID: number = 0\n\n constructor(delay: () => Millis, interval: Millis, onInterval: () => void) {\n this.#delay = delay\n this.#interval = interval\n this.#onInterval = onInterval\n }\n\n register(op: 'add' | 'remove'): this {\n if (op === 'add') {\n this.#timerID = setTimeout(() => {\n this.#onInterval()\n this.#intervalID = setInterval(this.#onInterval, this.#interval)\n }, this.#delay())\n } else {\n clearTimeout(this.#timerID)\n clearInterval(this.#intervalID)\n }\n\n return this\n }\n\n [Symbol.dispose](): void {\n this.register('remove')\n }\n}\n", "import {Zoo} from './ents/zoo.ts'\nimport type {Atlas, AtlasJSON, TagFormat} from './graphics/atlas.ts'\nimport {parseAtlas} from './graphics/atlas-parser.ts'\nimport {Cam} from './graphics/cam.ts'\nimport {Renderer} from './graphics/renderer.ts'\nimport {drawableBytes, Sprite} from './graphics/sprite.ts'\nimport {type DefaultButton, Input} from './input/input.ts'\nimport {Looper} from './looper.ts'\nimport {Pool, type PoolOpts} from './mem/pool.ts'\nimport type {WH} from './types/geo.ts'\nimport type {Millis} from './types/time.ts'\nimport {initCanvas} from './utils/canvas-util.ts'\nimport {DelayInterval} from './utils/delay-interval.ts'\nimport {initBody, initMetaViewport} from './utils/dom-util.ts'\nimport {loadImage} from './utils/fetch-util.ts'\n\nexport type VoidOpts<out Tag extends TagFormat> = {\n preloadAtlas?: {image: HTMLImageElement; json: AtlasJSON} | undefined\n backgroundRGBA?: number\n canvas?: HTMLCanvasElement | undefined\n minWH?: WH | undefined\n input?: 'Custom' | 'Default' | undefined\n mode?: 'Int' | 'Fraction' | undefined\n poll?: {delay?: (() => Millis) | undefined; period: Millis} | undefined\n sprites?:\n | Partial<Omit<PoolOpts<Sprite<Tag>>, 'alloc' | 'allocBytes'>>\n | undefined\n}\n\nexport class Void<\n out Tag extends TagFormat,\n Button extends string = DefaultButton\n> {\n readonly cam: Cam = new Cam()\n readonly canvas: HTMLCanvasElement\n readonly input: Input<Button>\n readonly preload: Atlas\n readonly renderer: Renderer\n readonly sprites: Pool<Sprite<Tag>>\n readonly zoo: Zoo<Tag> = new Zoo()\n readonly looper: Looper = new Looper()\n readonly #poll: DelayInterval | undefined\n readonly #preloadAtlasImage: HTMLImageElement | undefined\n // may trigger an initial force update.\n readonly #resizeObserver = new ResizeObserver(() => this.onResize())\n\n constructor(opts: Readonly<VoidOpts<Tag>>) {\n if (opts.poll != null)\n this.#poll = new DelayInterval(\n opts.poll.delay ?? (() => 0 as Millis),\n opts.poll.period,\n () => this.onPoll()\n )\n\n initMetaViewport()\n this.canvas = initCanvas(opts.canvas, opts.mode ?? 'Int')\n initBody(this.canvas, opts.backgroundRGBA ?? 0x000000ff)\n\n if (opts.minWH) this.cam.minWH = opts.minWH\n this.cam.mode = opts.mode ?? 'Int'\n this.cam.update(this.canvas)\n\n this.input = new Input(this.cam, this.canvas)\n if (opts.input !== 'Custom') this.input.mapDefault()\n this.input.onEvent = () => this.onEvent()\n\n if (opts.preloadAtlas) this.#preloadAtlasImage = opts.preloadAtlas.image\n\n this.preload = opts.preloadAtlas\n ? parseAtlas(opts.preloadAtlas.json)\n : {anim: {}, celXYWH: [], tags: []}\n\n this.renderer = new Renderer(this.preload ?? {}, this.canvas, this.looper)\n\n this.sprites = new Pool({\n alloc: pool => this.onAllocSprite(pool),\n allocBytes: drawableBytes,\n minPages: opts.sprites?.minPages ?? 3,\n pageBlocks: opts.sprites?.pageBlocks ?? 1000\n })\n\n this.looper.onFrame = millis => this.onFrame(millis)\n }\n\n onAllocSprite(pool: Pool<Sprite<Tag>>): Sprite<Tag> {\n return new Sprite(pool, 0, this.preload, this.looper)\n }\n\n onEvent(): void {\n this.requestFrame('Force')\n }\n\n /** update input, update canvas, update cam, update world, then render. */\n onFrame(millis: Millis): void {\n if (document.hidden) return\n this.input.update(millis)\n\n this.requestFrame() // request frame before in case loop cancels.\n\n this.onLoop(millis)\n\n this.cam.postupdate()\n }\n\n // biome-ignore lint/correctness/noUnusedFunctionParameters:;\n onLoop(millis: Millis): void {}\n\n onPoll(): void {\n this.requestFrame('Force')\n }\n\n onResize(): void {\n this.requestFrame('Force') // force cam reeval.\n }\n\n async register(op: 'add' | 'remove'): Promise<void> {\n this.input.register(op)\n this.renderer.register(op)\n this.looper.register(op)\n if (!this.canvas.parentElement) throw Error('no canvas parent')\n if (op === 'add') this.#resizeObserver.observe(this.canvas.parentElement)\n else this.#resizeObserver.unobserve(this.canvas.parentElement)\n\n if (op === 'add') this.looper.requestFrame()\n this.#poll?.register(op)\n\n if (this.#preloadAtlasImage) await loadImage(this.#preloadAtlasImage)\n this.renderer.load(this.#preloadAtlasImage)\n }\n\n requestFrame(force?: 'Force' | undefined): void {\n if (force || this.renderer.always || this.input.anyOn || this.input.gamepad)\n this.looper.requestFrame()\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.register('remove')\n }\n}\n", "import {voidVersion} from './types/void-version.ts'\n\nexport {type Font, memProp5x6} from 'mem-font'\nexport * from './ents/button-ent.ts'\nexport * from './ents/cursor-ent.ts'\nexport * from './ents/ent.ts'\nexport * from './ents/follow-cam-ent.ts'\nexport * from './ents/nine-patch-ent.ts'\nexport * from './ents/text-ent.ts'\nexport * from './ents/zoo.ts'\nexport * from './graphics/atlas.ts'\nexport * from './graphics/atlas-parser.ts'\nexport * from './graphics/cam.ts'\nexport * from './graphics/layer.ts'\nexport * from './graphics/sprite.ts'\nexport * from './input/input.ts'\nexport type {PointEvent} from './input/pointer.ts'\nexport * from './mem/pool.ts'\nexport * from './random/random.ts'\nexport * from './storage/local-storage.ts'\nexport * from './text/font.ts'\nexport * from './text/text-layout.ts'\nexport * from './types/geo.ts'\nexport * from './types/json.ts'\nexport * from './types/time.ts'\nexport * from './utils/async-util.ts'\nexport * from './utils/canvas-util.ts'\nexport * from './utils/debug.ts'\nexport * from './utils/dom-util.ts'\nexport * from './utils/fetch-util.ts'\nexport * from './void.ts'\n\nexport const version: string = voidVersion\n ? `${voidVersion.version}+${voidVersion.published}`\n : '?'\n", "{\n \"anim\": {\n \"background--OrangeCheckerboard\": {\"cels\": 1, \"h\": 2, \"id\": 0, \"w\": 2},\n \"background--GreyCheckerboard\": {\"cels\": 1, \"h\": 2, \"id\": 1, \"w\": 2},\n \"background--Kiwi\": {\"cels\": 1, \"h\": 2, \"id\": 2, \"w\": 2},\n \"background--Strawberry\": {\"cels\": 1, \"h\": 2, \"id\": 3, \"w\": 2},\n \"background--Grape\": {\"cels\": 1, \"h\": 2, \"id\": 4, \"w\": 2},\n \"background--Blueberry\": {\"cels\": 1, \"h\": 2, \"id\": 5, \"w\": 2},\n \"background--Bubblegum\": {\"cels\": 1, \"h\": 2, \"id\": 6, \"w\": 2},\n \"background--Transparent\": {\"cels\": 1, \"h\": 2, \"id\": 7, \"w\": 2},\n \"background--Black\": {\"cels\": 1, \"h\": 2, \"id\": 8, \"w\": 2},\n \"backpacker--WalkRight\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 9,\n \"w\": 8\n },\n \"backpacker--WalkDown\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 10,\n \"w\": 8\n },\n \"backpacker--WalkUp\": {\n \"cels\": 16,\n \"h\": 13,\n \"hitbox\": {\"x\": 2, \"y\": 0, \"w\": 4, \"h\": 4},\n \"id\": 11,\n \"w\": 8\n },\n \"cursor--Pointer\": {\n \"cels\": 1,\n \"h\": 14,\n \"hitbox\": {\"x\": 0, \"y\": 0, \"w\": 2, \"h\": 2},\n \"hurtbox\": {\"x\": 0, \"y\": 0, \"w\": 2, \"h\": 2},\n \"id\": 12,\n \"w\": 8\n },\n \"mem-prop-5x6--00\": {\"cels\": 1, \"h\": 6, \"id\": 13, \"w\": 5},\n \"mem-prop-5x6--01\": {\"cels\": 1, \"h\": 6, \"id\": 14, \"w\": 5},\n \"mem-prop-5x6--02\": {\"cels\": 1, \"h\": 6, \"id\": 15, \"w\": 5},\n \"mem-prop-5x6--03\": {\"cels\": 1, \"h\": 6, \"id\": 16, \"w\": 5},\n \"mem-prop-5x6--04\": {\"cels\": 1, \"h\": 6, \"id\": 17, \"w\": 5},\n \"mem-prop-5x6--05\": {\"cels\": 1, \"h\": 6, \"id\": 18, \"w\": 5},\n \"mem-prop-5x6--06\": {\"cels\": 1, \"h\": 6, \"id\": 19, \"w\": 5},\n \"mem-prop-5x6--07\": {\"cels\": 1, \"h\": 6, \"id\": 20, \"w\": 5},\n \"mem-prop-5x6--08\": {\"cels\": 1, \"h\": 6, \"id\": 21, \"w\": 5},\n \"mem-prop-5x6--09\": {\"cels\": 1, \"h\": 6, \"id\": 22, \"w\": 5},\n \"mem-prop-5x6--0a\": {\"cels\": 1, \"h\": 6, \"id\": 23, \"w\": 5},\n \"mem-prop-5x6--0b\": {\"cels\": 1, \"h\": 6, \"id\": 24, \"w\": 5},\n \"mem-prop-5x6--0c\": {\"cels\": 1, \"h\": 6, \"id\": 25, \"w\": 5},\n \"mem-prop-5x6--0d\": {\"cels\": 1, \"h\": 6, \"id\": 26, \"w\": 5},\n \"mem-prop-5x6--0e\": {\"cels\": 1, \"h\": 6, \"id\": 27, \"w\": 5},\n \"mem-prop-5x6--0f\": {\"cels\": 1, \"h\": 6, \"id\": 28, \"w\": 5},\n \"mem-prop-5x6--10\": {\"cels\": 1, \"h\": 6, \"id\": 29, \"w\": 5},\n \"mem-prop-5x6--11\": {\"cels\": 1, \"h\": 6, \"id\": 30, \"w\": 5},\n \"mem-prop-5x6--12\": {\"cels\": 1, \"h\": 6, \"id\": 31, \"w\": 5},\n \"mem-prop-5x6--13\": {\"cels\": 1, \"h\": 6, \"id\": 32, \"w\": 5},\n \"mem-prop-5x6--14\": {\"cels\": 1, \"h\": 6, \"id\": 33, \"w\": 5},\n \"mem-prop-5x6--15\": {\"cels\": 1, \"h\": 6, \"id\": 34, \"w\": 5},\n \"mem-prop-5x6--16\": {\"cels\": 1, \"h\": 6, \"id\": 35, \"w\": 5},\n \"mem-prop-5x6--17\": {\"cels\": 1, \"h\": 6, \"id\": 36, \"w\": 5},\n \"mem-prop-5x6--18\": {\"cels\": 1, \"h\": 6, \"id\": 37, \"w\": 5},\n \"mem-prop-5x6--19\": {\"cels\": 1, \"h\": 6, \"id\": 38, \"w\": 5},\n \"mem-prop-5x6--1a\": {\"cels\": 1, \"h\": 6, \"id\": 39, \"w\": 5},\n \"mem-prop-5x6--1b\": {\"cels\": 1, \"h\": 6, \"id\": 40, \"w\": 5},\n \"mem-prop-5x6--1c\": {\"cels\": 1, \"h\": 6, \"id\": 41, \"w\": 5},\n \"mem-prop-5x6--1d\": {\"cels\": 1, \"h\": 6, \"id\": 42, \"w\": 5},\n \"mem-prop-5x6--1e\": {\"cels\": 1, \"h\": 6, \"id\": 43, \"w\": 5},\n \"mem-prop-5x6--1f\": {\"cels\": 1, \"h\": 6, \"id\": 44, \"w\": 5},\n \"mem-prop-5x6--20\": {\"cels\": 1, \"h\": 6, \"id\": 45, \"w\": 5},\n \"mem-prop-5x6--21\": {\"cels\": 1, \"h\": 6, \"id\": 46, \"w\": 5},\n \"mem-prop-5x6--22\": {\"cels\": 1, \"h\": 6, \"id\": 47, \"w\": 5},\n \"mem-prop-5x6--23\": {\"cels\": 1, \"h\": 6, \"id\": 48, \"w\": 5},\n \"mem-prop-5x6--24\": {\"cels\": 1, \"h\": 6, \"id\": 49, \"w\": 5},\n \"mem-prop-5x6--25\": {\"cels\": 1, \"h\": 6, \"id\": 50, \"w\": 5},\n \"mem-prop-5x6--26\": {\"cels\": 1, \"h\": 6, \"id\": 51, \"w\": 5},\n \"mem-prop-5x6--27\": {\"cels\": 1, \"h\": 6, \"id\": 52, \"w\": 5},\n \"mem-prop-5x6--28\": {\"cels\": 1, \"h\": 6, \"id\": 53, \"w\": 5},\n \"mem-prop-5x6--29\": {\"cels\": 1, \"h\": 6, \"id\": 54, \"w\": 5},\n \"mem-prop-5x6--2a\": {\"cels\": 1, \"h\": 6, \"id\": 55, \"w\": 5},\n \"mem-prop-5x6--2b\": {\"cels\": 1, \"h\": 6, \"id\": 56, \"w\": 5},\n \"mem-prop-5x6--2c\": {\"cels\": 1, \"h\": 6, \"id\": 57, \"w\": 5},\n \"mem-prop-5x6--2d\": {\"cels\": 1, \"h\": 6, \"id\": 58, \"w\": 5},\n \"mem-prop-5x6--2e\": {\"cels\": 1, \"h\": 6, \"id\": 59, \"w\": 5},\n \"mem-prop-5x6--2f\": {\"cels\": 1, \"h\": 6, \"id\": 60, \"w\": 5},\n \"mem-prop-5x6--30\": {\"cels\": 1, \"h\": 6, \"id\": 61, \"w\": 5},\n \"mem-prop-5x6--31\": {\"cels\": 1, \"h\": 6, \"id\": 62, \"w\": 5},\n \"mem-prop-5x6--32\": {\"cels\": 1, \"h\": 6, \"id\": 63, \"w\": 5},\n \"mem-prop-5x6--33\": {\"cels\": 1, \"h\": 6, \"id\": 64, \"w\": 5},\n \"mem-prop-5x6--34\": {\"cels\": 1, \"h\": 6, \"id\": 65, \"w\": 5},\n \"mem-prop-5x6--35\": {\"cels\": 1, \"h\": 6, \"id\": 66, \"w\": 5},\n \"mem-prop-5x6--36\": {\"cels\": 1, \"h\": 6, \"id\": 67, \"w\": 5},\n \"mem-prop-5x6--37\": {\"cels\": 1, \"h\": 6, \"id\": 68, \"w\": 5},\n \"mem-prop-5x6--38\": {\"cels\": 1, \"h\": 6, \"id\": 69, \"w\": 5},\n \"mem-prop-5x6--39\": {\"cels\": 1, \"h\": 6, \"id\": 70, \"w\": 5},\n \"mem-prop-5x6--3a\": {\"cels\": 1, \"h\": 6, \"id\": 71, \"w\": 5},\n \"mem-prop-5x6--3b\": {\"cels\": 1, \"h\": 6, \"id\": 72, \"w\": 5},\n \"mem-prop-5x6--3c\": {\"cels\": 1, \"h\": 6, \"id\": 73, \"w\": 5},\n \"mem-prop-5x6--3d\": {\"cels\": 1, \"h\": 6, \"id\": 74, \"w\": 5},\n \"mem-prop-5x6--3e\": {\"cels\": 1, \"h\": 6, \"id\": 75, \"w\": 5},\n \"mem-prop-5x6--3f\": {\"cels\": 1, \"h\": 6, \"id\": 76, \"w\": 5},\n \"mem-prop-5x6--40\": {\"cels\": 1, \"h\": 6, \"id\": 77, \"w\": 5},\n \"mem-prop-5x6--41\": {\"cels\": 1, \"h\": 6, \"id\": 78, \"w\": 5},\n \"mem-prop-5x6--42\": {\"cels\": 1, \"h\": 6, \"id\": 79, \"w\": 5},\n \"mem-prop-5x6--43\": {\"cels\": 1, \"h\": 6, \"id\": 80, \"w\": 5},\n \"mem-prop-5x6--44\": {\"cels\": 1, \"h\": 6, \"id\": 81, \"w\": 5},\n \"mem-prop-5x6--45\": {\"cels\": 1, \"h\": 6, \"id\": 82, \"w\": 5},\n \"mem-prop-5x6--46\": {\"cels\": 1, \"h\": 6, \"id\": 83, \"w\": 5},\n \"mem-prop-5x6--47\": {\"cels\": 1, \"h\": 6, \"id\": 84, \"w\": 5},\n \"mem-prop-5x6--48\": {\"cels\": 1, \"h\": 6, \"id\": 85, \"w\": 5},\n \"mem-prop-5x6--49\": {\"cels\": 1, \"h\": 6, \"id\": 86, \"w\": 5},\n \"mem-prop-5x6--4a\": {\"cels\": 1, \"h\": 6, \"id\": 87, \"w\": 5},\n \"mem-prop-5x6--4b\": {\"cels\": 1, \"h\": 6, \"id\": 88, \"w\": 5},\n \"mem-prop-5x6--4c\": {\"cels\": 1, \"h\": 6, \"id\": 89, \"w\": 5},\n \"mem-prop-5x6--4d\": {\"cels\": 1, \"h\": 6, \"id\": 90, \"w\": 5},\n \"mem-prop-5x6--4e\": {\"cels\": 1, \"h\": 6, \"id\": 91, \"w\": 5},\n \"mem-prop-5x6--4f\": {\"cels\": 1, \"h\": 6, \"id\": 92, \"w\": 5},\n \"mem-prop-5x6--50\": {\"cels\": 1, \"h\": 6, \"id\": 93, \"w\": 5},\n \"mem-prop-5x6--51\": {\"cels\": 1, \"h\": 6, \"id\": 94, \"w\": 5},\n \"mem-prop-5x6--52\": {\"cels\": 1, \"h\": 6, \"id\": 95, \"w\": 5},\n \"mem-prop-5x6--53\": {\"cels\": 1, \"h\": 6, \"id\": 96, \"w\": 5},\n \"mem-prop-5x6--54\": {\"cels\": 1, \"h\": 6, \"id\": 97, \"w\": 5},\n \"mem-prop-5x6--55\": {\"cels\": 1, \"h\": 6, \"id\": 98, \"w\": 5},\n \"mem-prop-5x6--56\": {\"cels\": 1, \"h\": 6, \"id\": 99, \"w\": 5},\n \"mem-prop-5x6--57\": {\"cels\": 1, \"h\": 6, \"id\": 100, \"w\": 5},\n \"mem-prop-5x6--58\": {\"cels\": 1, \"h\": 6, \"id\": 101, \"w\": 5},\n \"mem-prop-5x6--59\": {\"cels\": 1, \"h\": 6, \"id\": 102, \"w\": 5},\n \"mem-prop-5x6--5a\": {\"cels\": 1, \"h\": 6, \"id\": 103, \"w\": 5},\n \"mem-prop-5x6--5b\": {\"cels\": 1, \"h\": 6, \"id\": 104, \"w\": 5},\n \"mem-prop-5x6--5c\": {\"cels\": 1, \"h\": 6, \"id\": 105, \"w\": 5},\n \"mem-prop-5x6--5d\": {\"cels\": 1, \"h\": 6, \"id\": 106, \"w\": 5},\n \"mem-prop-5x6--5e\": {\"cels\": 1, \"h\": 6, \"id\": 107, \"w\": 5},\n \"mem-prop-5x6--5f\": {\"cels\": 1, \"h\": 6, \"id\": 108, \"w\": 5},\n \"mem-prop-5x6--60\": {\"cels\": 1, \"h\": 6, \"id\": 109, \"w\": 5},\n \"mem-prop-5x6--61\": {\"cels\": 1, \"h\": 6, \"id\": 110, \"w\": 5},\n \"mem-prop-5x6--62\": {\"cels\": 1, \"h\": 6, \"id\": 111, \"w\": 5},\n \"mem-prop-5x6--63\": {\"cels\": 1, \"h\": 6, \"id\": 112, \"w\": 5},\n \"mem-prop-5x6--64\": {\"cels\": 1, \"h\": 6, \"id\": 113, \"w\": 5},\n \"mem-prop-5x6--65\": {\"cels\": 1, \"h\": 6, \"id\": 114, \"w\": 5},\n \"mem-prop-5x6--66\": {\"cels\": 1, \"h\": 6, \"id\": 115, \"w\": 5},\n \"mem-prop-5x6--67\": {\"cels\": 1, \"h\": 6, \"id\": 116, \"w\": 5},\n \"mem-prop-5x6--68\": {\"cels\": 1, \"h\": 6, \"id\": 117, \"w\": 5},\n \"mem-prop-5x6--69\": {\"cels\": 1, \"h\": 6, \"id\": 118, \"w\": 5},\n \"mem-prop-5x6--6a\": {\"cels\": 1, \"h\": 6, \"id\": 119, \"w\": 5},\n \"mem-prop-5x6--6b\": {\"cels\": 1, \"h\": 6, \"id\": 120, \"w\": 5},\n \"mem-prop-5x6--6c\": {\"cels\": 1, \"h\": 6, \"id\": 121, \"w\": 5},\n \"mem-prop-5x6--6d\": {\"cels\": 1, \"h\": 6, \"id\": 122, \"w\": 5},\n \"mem-prop-5x6--6e\": {\"cels\": 1, \"h\": 6, \"id\": 123, \"w\": 5},\n \"mem-prop-5x6--6f\": {\"cels\": 1, \"h\": 6, \"id\": 124, \"w\": 5},\n \"mem-prop-5x6--70\": {\"cels\": 1, \"h\": 6, \"id\": 125, \"w\": 5},\n \"mem-prop-5x6--71\": {\"cels\": 1, \"h\": 6, \"id\": 126, \"w\": 5},\n \"mem-prop-5x6--72\": {\"cels\": 1, \"h\": 6, \"id\": 127, \"w\": 5},\n \"mem-prop-5x6--73\": {\"cels\": 1, \"h\": 6, \"id\": 128, \"w\": 5},\n \"mem-prop-5x6--74\": {\"cels\": 1, \"h\": 6, \"id\": 129, \"w\": 5},\n \"mem-prop-5x6--75\": {\"cels\": 1, \"h\": 6, \"id\": 130, \"w\": 5},\n \"mem-prop-5x6--76\": {\"cels\": 1, \"h\": 6, \"id\": 131, \"w\": 5},\n \"mem-prop-5x6--77\": {\"cels\": 1, \"h\": 6, \"id\": 132, \"w\": 5},\n \"mem-prop-5x6--78\": {\"cels\": 1, \"h\": 6, \"id\": 133, \"w\": 5},\n \"mem-prop-5x6--79\": {\"cels\": 1, \"h\": 6, \"id\": 134, \"w\": 5},\n \"mem-prop-5x6--7a\": {\"cels\": 1, \"h\": 6, \"id\": 135, \"w\": 5},\n \"mem-prop-5x6--7b\": {\"cels\": 1, \"h\": 6, \"id\": 136, \"w\": 5},\n \"mem-prop-5x6--7c\": {\"cels\": 1, \"h\": 6, \"id\": 137, \"w\": 5},\n \"mem-prop-5x6--7d\": {\"cels\": 1, \"h\": 6, \"id\": 138, \"w\": 5},\n \"mem-prop-5x6--7e\": {\"cels\": 1, \"h\": 6, \"id\": 139, \"w\": 5},\n \"mem-prop-5x6--7f\": {\"cels\": 1, \"h\": 6, \"id\": 140, \"w\": 5},\n \"oidoid--Default\": {\"cels\": 1, \"h\": 16, \"id\": 141, \"w\": 16}\n },\n \"celXY\": [\n 22, 37, 21, 27, 21, 29, 21, 31, 20, 33, 22, 33, 20, 35, 22, 35, 20, 37, 24,\n 26, 24, 26, 8, 16, 8, 16, 0, 16, 0, 16, 16, 14, 16, 14, 72, 13, 72, 13, 32,\n 26, 32, 26, 0, 16, 0, 16, 64, 13, 64, 13, 56, 13, 56, 13, 48, 13, 48, 13,\n 40, 13, 40, 13, 32, 13, 32, 13, 56, 13, 56, 13, 24, 13, 24, 13, 72, 0, 72,\n 0, 64, 0, 64, 0, 24, 0, 24, 0, 56, 0, 56, 0, 48, 0, 48, 0, 48, 0, 48, 0, 24,\n 0, 24, 0, 40, 0, 40, 0, 32, 0, 32, 0, 32, 0, 32, 0, 16, 0, 45, 56, 45, 56,\n 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45,\n 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56,\n 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45, 56, 45,\n 56, 45, 56, 45, 56, 40, 56, 10, 53, 5, 53, 0, 53, 35, 51, 30, 51, 25, 51,\n 20, 51, 15, 51, 35, 45, 70, 50, 65, 50, 60, 50, 55, 50, 50, 50, 45, 50, 40,\n 50, 10, 47, 5, 47, 0, 47, 70, 62, 50, 56, 65, 62, 60, 62, 55, 62, 50, 62,\n 45, 62, 40, 62, 10, 59, 5, 59, 0, 59, 35, 57, 70, 32, 30, 57, 25, 57, 20,\n 57, 15, 57, 75, 56, 70, 56, 65, 56, 60, 56, 75, 50, 55, 56, 10, 35, 75, 32,\n 15, 33, 0, 35, 5, 35, 40, 38, 45, 38, 65, 32, 60, 32, 55, 32, 50, 32, 45,\n 32, 40, 26, 50, 26, 55, 26, 60, 26, 65, 26, 70, 26, 75, 26, 16, 27, 0, 29,\n 5, 29, 10, 29, 40, 32, 45, 26, 10, 41, 30, 45, 25, 45, 20, 45, 15, 45, 75,\n 44, 70, 44, 65, 44, 60, 44, 55, 44, 50, 44, 45, 44, 40, 44, 50, 38, 5, 41,\n 0, 41, 35, 39, 30, 39, 25, 39, 20, 39, 15, 39, 75, 38, 70, 38, 65, 38, 60,\n 38, 55, 38, 45, 56, 0, 0\n ]\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\nexport class ClockEnt implements V.Ent<Tag> {\n readonly #time: V.TextEnt = new V.TextEnt()\n\n constructor() {\n this.#time.scale = 3\n this.#time.z = V.Layer.A\n }\n\n free(v: Game): void {\n this.#time.free(v)\n }\n\n update(v: Game): boolean | undefined {\n const now = new Date()\n this.#time.text = timeString(now)\n\n if (this.#time.layout(v) || v.cam.invalid)\n this.#time.xy = v.cam.follow(\n {w: this.#time.wh.w, h: this.#time.wh.h - this.#time.scaledLeading},\n this.#time.z,\n 'N',\n {margin: {h: 8}}\n )\n\n return this.#time.update(v)\n }\n}\n\n/** @internal */\nexport function timeString(time: Readonly<Date>): string {\n const hh = `${time.getHours() % 12 || 12}`.padStart(2, ' ')\n const mm = `${time.getMinutes()}`.padStart(2, '0')\n const ss = `${time.getSeconds()}`.padStart(2, '0')\n return `${hh}:${mm}:${ss}`\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\n// to-do: follow cam sw.\nexport class RenderToggleEnt implements V.Ent<Tag> {\n readonly #toggle: V.ButtonEnt<Tag, V.DefaultButton>\n\n constructor(v: Game) {\n this.#toggle = new V.ButtonEnt(v, {\n button: {\n w: {tag: 'background--Strawberry'},\n nw: {tag: 'background--Transparent'},\n n: {tag: 'background--Bubblegum'},\n e: {tag: 'background--Blueberry'},\n s: {tag: 'background--Kiwi'},\n origin: {tag: 'background--Grape'},\n border: {n: 1},\n margin: {w: 2, h: 2}\n },\n selected: {tag: 'background--OrangeCheckerboard'},\n toggle: true,\n text: {text: 'render', scale: 2},\n w: 64,\n h: 22,\n x: 50,\n y: 25,\n pressed: {tag: 'background--Bubblegum'}\n })\n }\n\n get on(): boolean {\n return this.#toggle.on\n }\n\n set on(on: boolean) {\n this.#toggle.on = on\n }\n\n free(v: Game): void {\n this.#toggle.free(v)\n }\n\n /** always updates but never invalidates. */\n update(v: Game): boolean | undefined {\n return this.#toggle.update(v)\n }\n}\n", "import * as V from '../../index.ts'\nimport type {Game} from '../game.ts'\nimport type {Tag} from '../types/tag.ts'\n\nexport class WorkCounterEnt implements V.Ent<Tag> {\n readonly #text: V.TextEnt = new V.TextEnt()\n #updates: number = 0\n\n constructor() {\n this.#text.z = V.Layer.A\n }\n\n free(v: Game): void {\n this.#text.free(v)\n }\n\n /** always updates but never invalidates. */\n update(v: Game): undefined {\n this.#updates++\n this.#text.text = `${this.#updates} updates\\n${v.renderer.clears + 1} renders`\n this.#text.layout(v)\n this.#text.xy = v.cam.follow(\n {w: this.#text.wh.w, h: this.#text.wh.h - this.#text.scaledLeading},\n this.#text.z,\n 'NE',\n {margin: {w: 8, h: 8}}\n )\n this.#text.update(v)\n }\n}\n", "import * as V from '../index.ts'\nimport preloadAtlasJSON from './assets/preload-atlas.json' with {type: 'json'}\nimport {ClockEnt} from './ents/clock-ent.ts'\nimport {RenderToggleEnt} from './ents/render-toggle-ent.ts'\nimport {WorkCounterEnt} from './ents/work-counter-ent.ts'\nimport type {Tag} from './types/tag.ts'\n\nexport class Game extends V.Void<Tag> {\n #filterSprites: V.Pool<V.Sprite<Tag>>\n #renderToggle: RenderToggleEnt\n #workCounter: WorkCounterEnt\n\n constructor() {\n super({\n preloadAtlas: {\n image: document.querySelector('#preload-atlas')!,\n json: preloadAtlasJSON\n },\n backgroundRGBA: 0xffffb1ff,\n minWH: {w: 320, h: 240},\n poll: {\n delay: () => renderDelayMillis(new Date(), V.debug?.seconds),\n period: ((V.debug?.seconds ? 1 : 60) * 1000) as V.Millis\n }\n })\n this.#filterSprites = new V.Pool<V.Sprite<Tag>>({\n alloc: pool => new V.Sprite(pool, 0, this.preload, this.looper),\n allocBytes: V.drawableBytes,\n pageBlocks: 10\n })\n this.#renderToggle = new RenderToggleEnt(this)\n this.#renderToggle.on = this.renderer.always\n this.#workCounter = new WorkCounterEnt()\n this.#initZoo()\n }\n\n override onLoop(_millis: V.Millis): void {\n if (V.debug?.input) this.#printInput()\n this.renderer.always = this.#renderToggle.on\n\n let render = this.#updateCam()\n this.zoo.update(this)\n\n render ||=\n this.zoo.invalid ||\n this.cam.invalid ||\n this.renderer.invalid ||\n this.renderer.always\n if (render) {\n this.renderer.clear(0xffffb1ff)\n this.renderer.predraw(this.cam)\n this.renderer.setDepth(true)\n this.renderer.draw(this.sprites)\n this.renderer.setDepth(false)\n this.renderer.draw(this.#filterSprites)\n }\n }\n\n #initZoo(): void {\n const border = new V.NinePatchEnt<Tag>(this, {\n n: {tag: 'background--Black'},\n origin: {tag: 'background--Transparent'},\n border: {n: 1},\n z: V.Layer.UIA\n })\n this.zoo.add(border)\n const box = this.cam.follow({w: 0, h: 0}, V.Layer.UIA, 'NW', {fill: 'XY'})\n border.xy = box\n border.wh = box\n\n const backpacker = this.sprites.alloc()\n backpacker.tag = 'backpacker--WalkRight'\n backpacker.x = 7\n backpacker.y = 7\n backpacker.z = V.Layer.C\n backpacker.stretch = true\n backpacker.w *= 5\n backpacker.h *= 5\n\n const oidoid = new V.FollowCamEnt(this, 'oidoid--Default', 'SW')\n oidoid.z = V.Layer.UIG\n oidoid.margin = {w: 4, h: 4}\n\n this.zoo.add(\n new V.CursorEnt(this, 'cursor--Pointer'),\n this.#renderToggle,\n new ClockEnt(),\n this.#workCounter,\n oidoid\n )\n\n const overlay = this.#filterSprites.alloc()\n overlay.tag = 'background--GreyCheckerboard'\n overlay.w = V.drawableMaxWH.w\n overlay.h = V.drawableMaxWH.h\n overlay.z = V.Layer.UIA\n }\n\n #printInput(): void {\n if (this.input.started) {\n const on = !!this.input.on.length\n if (on) console.debug(`[input] buttons on: ${this.input.on.join(' ')}.`)\n else console.debug(`[input] buttons off.`)\n const combo = this.input.combo\n if (combo.length > 1 && on)\n console.debug(\n `[input] combo: ${combo.map(set => set.join('+')).join(' ')}.`\n )\n }\n if (\n this.input.point?.invalid &&\n this.input.point?.click &&\n !this.input.point.pinch\n )\n console.debug(\n `[input] ${this.input.point.drag.on ? 'drag' : 'click'} xy: ${this.input.point.x} ${this.input.point.y}.`\n )\n if (this.input.point?.pinch)\n console.debug(\n `[input] pinch xy: ${this.input.point.pinch.xy.x} ${this.input.point.pinch.xy.y}.`\n )\n if (this.input.wheel)\n console.debug(\n `[input] wheel xy: ${this.input.wheel.delta.xy.x} ${this.input.wheel.delta.xy.y}.`\n )\n }\n\n #updateCam(): boolean {\n let render = this.input.isAnyOn('L', 'R', 'U', 'D')\n\n if (this.input.isAnyOnStart('L', 'R', 'U', 'D')) {\n this.cam.x = Math.trunc(this.cam.x)\n this.cam.y = Math.trunc(this.cam.y)\n }\n\n const d = 1 / 4\n if (this.input.isOn('L')) this.cam.x -= d\n if (this.input.isOn('R')) this.cam.x += d\n if (this.input.isOn('U')) this.cam.y -= d\n if (this.input.isOn('D')) this.cam.y += d\n\n if (this.input.wheel?.delta.xy.y) {\n render = true\n this.cam.zoomOut -= this.input.wheel.delta.client.y * 0.01\n }\n\n this.cam.update(this.canvas)\n\n return render\n }\n}\n\n/**\n * returns [0, 59_999].\n * @internal\n */\nexport function renderDelayMillis(\n time: Readonly<Date>,\n debugSecs: string | undefined\n): V.Millis {\n return (((debugSecs ? 0 : (59 - (time.getSeconds() % 60)) * 1000) +\n 1000 -\n (time.getMilliseconds() % 1000)) %\n (debugSecs ? 1000 : 60_000)) as V.Millis\n}\n", "import * as V from '../index.ts'\nimport {Game} from './game.ts'\n\nconsole.debug(`void v${V.version} \u2500\u2500\u2500oidoid>\u00B0\u2500\u2500`)\n\nconst v = new Game()\nawait v.register('add')\nif (V.debug) (globalThis as unknown as {v: Game}).v = v\n"],
|
|
5
5
|
"mappings": "AAAA,IAAAA,EAAA,CAAC,UAAY,WAAW,QAAU,SAAS,ECWpC,IAAMC,EAA2BC,ECXxC,IAAAC,EAAA,CACI,GAAM,eACN,KAAQ,UACR,UAAa,EACb,WAAc,EACd,QAAW,EACX,WAAc,EACd,SAAY,EACZ,QAAW,CACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,GACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAO,EACP,KAAO,EACP,KAAO,EACP,KAAO,EACP,KAAO,EACP,KAAO,EACP,KAAO,EACP,KAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAQ,EACR,OAAQ,EACR,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,GAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,GACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,GAAM,EACN,GAAM,EACN,GAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,CACV,EACA,eAAkB,EAClB,yBAA4B,GAC5B,iBAAoB,EACpB,UAAa,CACT,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,EAAK,EACL,EAAK,EACL,IAAK,EACL,KAAM,EACN,IAAK,EACL,IAAK,EACL,EAAK,EACL,EAAK,EACL,EAAK,EACL,EAAK,EACL,EAAK,EACL,IAAK,CACT,EACA,iBAAoB,CACxB,ECveO,IAAMC,EAAmBC,ECrFzB,IAAMC,EAAQ,CACnB,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,IAAK,EACL,EAAG,EACH,EAAG,EACH,EAAG,GACH,EAAG,GACH,EAAG,GACH,EAAG,GACH,OAAQ,GACR,OAAQ,EACV,EAIO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AAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,GAAI,EAAK,CAAC,EACxD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACzD,mBAAoB,CAAC,KAAQ,EAAG,EAAK,EAAG,GAAM,IAAK,EAAK,CAAC,EACz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",
|
|
6
6
|
"names": ["define_globalThis_voidVersion_default", "voidVersion", "define_globalThis_voidVersion_default", "mem_prop_5x6_default", "memProp5x6", "mem_prop_5x6_default", "Layer", "layerOffset", "layer", "offset", "boxHits", "l", "r", "rWH", "lXY", "whAssign", "whEq", "xyAdd", "xyAssign", "l", "r", "xyDistance", "from", "to", "xyMagnitude", "xySub", "xyEq", "l", "r", "xyMagnitude", "xy", "xyMax", "xyMin", "xySub", "NinePatchEnt", "#dir", "#margin", "#invalid", "v", "opts", "w", "wh", "whEq", "#setXYRight", "xy", "xyEq", "fontCharToTag", "font", "char", "pt", "fontKerning", "l", "r", "fontCharWidth", "letter", "layoutText", "opts", "chars", "scale", "start", "maxW", "cursor", "w", "i", "char", "layout", "layoutNewline", "layoutSpace", "tracking", "layoutWord", "nextLine", "font", "word", "index", "startX", "x", "y", "span", "fontCharWidth", "curY", "nextCursor", "l", "r", "fontKerning", "TextEnt", "#maxW", "#layout", "#z", "Layer", "#scale", "#sprites", "#str", "#wh", "#xy", "v", "len", "layout", "layoutText", "memProp5x6", "i", "char", "sprite", "fontCharToTag", "w", "scale", "str", "xy", "xyEq", "layer", "ButtonEnt", "#button", "#invalid", "#pressed", "#selected", "#started", "#toggle", "#text", "TextEnt", "#xy", "v", "opts", "buttonZ", "Layer", "NinePatchEnt", "layerOffset", "#moveText", "on", "str", "invalid", "hitsCursor", "xy", "xyEq", "CursorEnt", "#sprite", "#pick", "#point", "v", "point", "pick", "Layer", "coords", "lvl", "hitbox", "box", "boxHits", "FollowCamEnt", "#fill", "#invalid", "#margin", "#modulo", "#pivot", "#sprite", "v", "tag", "pivot", "fill", "h", "margin", "whEq", "whAssign", "modulo", "xyEq", "xyAssign", "follow", "w", "z", "debug", "Debug", "url", "csv", "k", "map", "kv", "target", "voidKeyset", "Zoo", "#cursor", "#ents", "#invalid", "ents", "ent", "CursorEnt", "v", "debug", "parseAtlas", "json", "parseCelXYWH", "cels", "i", "anim", "parseXYWH", "celXY", "xywh", "ii", "iii", "Cam", "#devicePixelRatio", "#h", "#invalid", "#minScale", "#minWH", "#mode", "#scale", "#w", "#whClient", "#x", "#y", "#zoomOut", "xy", "client", "local", "wh", "z", "pivot", "opts", "marginW", "x", "Layer", "marginH", "y", "w", "h", "box", "boxHits", "scale", "#invalidateWH", "mode", "canvas", "clientWidth", "clientHeight", "out", "debug", "phy", "mod", "dividend", "divisor", "drawableBytes", "drawableEpsilon", "drawableMaxWH", "Drawable", "#pool", "pool", "i", "draw", "cel", "iiic_cccc", "box", "boxHits", "flip", "sxyz_llll", "h", "h12_wwww", "id", "i11_c5", "stretch", "w", "hhhh_w12", "x", "y8_x24", "xy", "y", "sxyz_llll_y24", "z", "end", "Sprite", "_Sprite", "#atlas", "#hitbox", "#hurtbox", "#looper", "atlas", "looper", "hitbox", "hurtbox", "mod", "#currentCel", "tag", "anim", "ContextMenu", "#target", "target", "op", "fn", "#onContextMenu", "ev", "Gamepad", "#target", "target", "op", "fn", "pad", "index", "axis", "lessMore", "bit", "btn", "Keyboard", "#on", "#target", "target", "bits", "k", "op", "fn", "ev", "#onKey", "pointTypeByPointerType", "pointEvents", "Pointer", "#pinchStartClient", "#target", "target", "min", "max", "pt", "xyMin", "xyMax", "bounds", "xyAdd", "end", "#newPinchClient", "xySub", "op", "fn", "ev", "#onInput", "#evButtonsToBits", "btns", "bits", "btn", "locked", "prevPt", "xyClient", "scale", "evType", "type", "clickClient", "drag", "xyDistance", "Wheel", "#target", "target", "op", "#onInput", "ev", "Input", "#bitByButton", "#buttonByBit", "#bits", "#cam", "#combo", "#contextMenu", "#gamepad", "#heldMillis", "#keyboard", "#pointer", "#pointerState", "#prevBits", "#wheel", "#wheelState", "cam", "target", "ContextMenu", "Gamepad", "Keyboard", "Pointer", "Wheel", "chords", "bits", "chord", "bit", "btns", "#mapBits", "combo", "i", "input", "less", "more", "axes", "axis", "#mapButton", "btn", "indices", "index", "codes", "code", "clicks", "click", "on", "cb", "op", "millis", "pinchClient", "dragOn", "secondary", "pt", "centerClient", "center", "Pool", "#blocks", "#opts", "#size", "#u8", "#view", "opts", "initSize", "#resize", "#currentCapacity", "block", "minCapacity", "blocks", "#freeBlock", "str", "i", "start", "free", "capacity", "origin", "debug", "buffer", "u8", "rgbaHex", "rgba", "initBody", "canvas", "rgba", "rgbaHex", "initMetaViewport", "meta", "initCanvas", "canvas", "mode", "loadImage", "img", "promise", "fulfil", "reject", "Shader", "gl", "vertGLSL", "fragGLSL", "textures", "program", "loadProgram", "GLUniformMap", "pgm", "len", "map", "debug", "target", "k", "i", "uniform", "location", "name", "vert", "compileShader", "frag", "log", "type", "glsl", "shader", "spriteFragGLSL", "debug", "Layer", "spriteVertGLSL", "debug", "Layer", "uv", "Renderer", "debug", "#canvas", "#clearRGBA", "#depth", "#ctx", "#looper", "#preloadAtlas", "#preloadAtlasImage", "preloadAtlas", "canvas", "looper", "rgba", "gl", "pool", "spriteShader", "drawableBytes", "cam", "viewport", "whEq", "i", "tex", "op", "#onContextLost", "#onContextRestored", "enable", "GL2", "shader", "Shader", "spriteVertGLSL", "spriteFragGLSL", "ev", "Looper", "#req", "#registered", "op", "fn", "#onVisibility", "#cancel", "#onFrame", "now", "millis", "ev", "DelayInterval", "#delay", "#interval", "#intervalID", "#onInterval", "#timerID", "delay", "interval", "onInterval", "op", "Void", "Cam", "Zoo", "Looper", "#poll", "#preloadAtlasImage", "#resizeObserver", "opts", "DelayInterval", "initMetaViewport", "initCanvas", "initBody", "Input", "parseAtlas", "Renderer", "Pool", "pool", "drawableBytes", "millis", "Sprite", "op", "loadImage", "force", "version", "voidVersion", "preload_atlas_default", "ClockEnt", "#time", "TextEnt", "Layer", "v", "now", "timeString", "time", "hh", "mm", "ss", "RenderToggleEnt", "#toggle", "v", "ButtonEnt", "on", "WorkCounterEnt", "#text", "TextEnt", "#updates", "Layer", "v", "Game", "Void", "#filterSprites", "#renderToggle", "#workCounter", "preload_atlas_default", "renderDelayMillis", "debug", "Pool", "pool", "Sprite", "drawableBytes", "RenderToggleEnt", "WorkCounterEnt", "#initZoo", "_millis", "#printInput", "render", "#updateCam", "border", "NinePatchEnt", "Layer", "box", "backpacker", "oidoid", "FollowCamEnt", "CursorEnt", "ClockEnt", "overlay", "drawableMaxWH", "on", "combo", "set", "d", "time", "debugSecs", "version", "v", "Game", "debug"]
|
|
7
7
|
}
|