@oidoid/void 0.1.0-3 → 0.1.0-6

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.
Files changed (295) hide show
  1. package/dist/meta.json +1 -0
  2. package/dist/package.json +66 -0
  3. package/dist/public/favicon/favicon16.png +0 -0
  4. package/dist/public/favicon/favicon192.png +0 -0
  5. package/dist/public/favicon/favicon32.png +0 -0
  6. package/dist/public/favicon/favicon48.png +0 -0
  7. package/dist/public/favicon/favicon512.png +0 -0
  8. package/dist/public/favicon/favicon64.png +0 -0
  9. package/dist/public/index.html +23 -0
  10. package/dist/public/index.js +3844 -0
  11. package/dist/public/index.js.map +7 -0
  12. package/dist/public/manifest.json +1 -0
  13. package/dist/public/preload-atlas.png +0 -0
  14. package/dist/public/void-v0.1.0-4.html +111 -0
  15. package/dist/public/void-v0.1.0-5.html +111 -0
  16. package/dist/public/void-v0.1.0-6.html +111 -0
  17. package/dist/schema/config-file.d.ts +32 -0
  18. package/dist/schema/config-file.js +41 -0
  19. package/dist/schema/config-file.js.map +1 -0
  20. package/dist/schema/config-file.v0.json +68 -0
  21. package/dist/src/audio.d.ts +7 -0
  22. package/dist/src/audio.js +25 -0
  23. package/dist/src/audio.js.map +1 -0
  24. package/dist/src/demo/assets/manifest.json +46 -0
  25. package/dist/src/demo/assets/preload-atlas.json +193 -0
  26. package/dist/src/demo/ents/clock-ent.d.ts +10 -0
  27. package/dist/src/demo/ents/clock-ent.js +26 -0
  28. package/dist/src/demo/ents/clock-ent.js.map +1 -0
  29. package/dist/src/demo/ents/render-toggle-ent.d.ts +10 -0
  30. package/dist/src/demo/ents/render-toggle-ent.js +38 -0
  31. package/dist/src/demo/ents/render-toggle-ent.js.map +1 -0
  32. package/dist/src/demo/ents/work-counter-ent.d.ts +10 -0
  33. package/dist/src/demo/ents/work-counter-ent.js +24 -0
  34. package/dist/src/demo/ents/work-counter-ent.js.map +1 -0
  35. package/dist/src/demo/game.d.ts +13 -0
  36. package/dist/src/demo/game.js +155 -0
  37. package/dist/src/demo/game.js.map +1 -0
  38. package/dist/src/demo/index.d.ts +1 -0
  39. package/dist/src/demo/index.js +8 -0
  40. package/dist/src/demo/index.js.map +1 -0
  41. package/dist/src/demo/tsconfig.json +15 -0
  42. package/dist/src/demo/types/tag.d.ts +2 -0
  43. package/dist/src/demo/types/tag.js +2 -0
  44. package/dist/src/demo/types/tag.js.map +1 -0
  45. package/dist/src/demo/void.json +11 -0
  46. package/dist/src/ents/button-ent.d.ts +38 -0
  47. package/dist/src/ents/button-ent.js +124 -0
  48. package/dist/src/ents/button-ent.js.map +1 -0
  49. package/dist/src/ents/cursor-ent.d.ts +18 -0
  50. package/dist/src/ents/cursor-ent.js +58 -0
  51. package/dist/src/ents/cursor-ent.js.map +1 -0
  52. package/dist/src/ents/ent.d.ts +7 -0
  53. package/dist/src/ents/ent.js +2 -0
  54. package/dist/src/ents/ent.js.map +1 -0
  55. package/dist/src/ents/follow-cam-ent.d.ts +25 -0
  56. package/dist/src/ents/follow-cam-ent.js +87 -0
  57. package/dist/src/ents/follow-cam-ent.js.map +1 -0
  58. package/dist/src/ents/nine-patch-ent.d.ts +43 -0
  59. package/dist/src/ents/nine-patch-ent.js +143 -0
  60. package/dist/src/ents/nine-patch-ent.js.map +1 -0
  61. package/dist/src/ents/text-ent.d.ts +23 -0
  62. package/dist/src/ents/text-ent.js +109 -0
  63. package/dist/src/ents/text-ent.js.map +1 -0
  64. package/dist/src/ents/zoo.d.ts +16 -0
  65. package/dist/src/ents/zoo.js +38 -0
  66. package/dist/src/ents/zoo.js.map +1 -0
  67. package/dist/src/graphics/atlas-parser.d.ts +4 -0
  68. package/dist/src/graphics/atlas-parser.js +27 -0
  69. package/dist/src/graphics/atlas-parser.js.map +1 -0
  70. package/dist/src/graphics/atlas.d.ts +49 -0
  71. package/dist/src/graphics/atlas.js +7 -0
  72. package/dist/src/graphics/atlas.js.map +1 -0
  73. package/dist/src/graphics/cam.d.ts +89 -0
  74. package/dist/src/graphics/cam.js +211 -0
  75. package/dist/src/graphics/cam.js.map +1 -0
  76. package/dist/src/graphics/gl.d.ts +24 -0
  77. package/dist/src/graphics/gl.js +70 -0
  78. package/dist/src/graphics/gl.js.map +1 -0
  79. package/dist/src/graphics/layer.d.ts +21 -0
  80. package/dist/src/graphics/layer.js +23 -0
  81. package/dist/src/graphics/layer.js.map +1 -0
  82. package/dist/src/graphics/renderer.d.ts +22 -0
  83. package/dist/src/graphics/renderer.js +168 -0
  84. package/dist/src/graphics/renderer.js.map +1 -0
  85. package/dist/src/graphics/sprite-frag.glsl.d.ts +1 -0
  86. package/dist/src/graphics/sprite-frag.glsl.js +35 -0
  87. package/dist/src/graphics/sprite-frag.glsl.js.map +1 -0
  88. package/dist/src/graphics/sprite-vert.glsl.d.ts +1 -0
  89. package/dist/src/graphics/sprite-vert.glsl.js +68 -0
  90. package/dist/src/graphics/sprite-vert.glsl.js.map +1 -0
  91. package/dist/src/graphics/sprite.d.ts +108 -0
  92. package/dist/src/graphics/sprite.js +301 -0
  93. package/dist/src/graphics/sprite.js.map +1 -0
  94. package/dist/src/index.d.ts +30 -0
  95. package/dist/src/index.js +33 -0
  96. package/dist/src/index.js.map +1 -0
  97. package/dist/src/input/context-menu.d.ts +8 -0
  98. package/dist/src/input/context-menu.js +25 -0
  99. package/dist/src/input/context-menu.js.map +1 -0
  100. package/dist/src/input/gamepad.d.ts +18 -0
  101. package/dist/src/input/gamepad.js +49 -0
  102. package/dist/src/input/gamepad.js.map +1 -0
  103. package/dist/src/input/input.d.ts +148 -0
  104. package/dist/src/input/input.js +383 -0
  105. package/dist/src/input/input.js.map +1 -0
  106. package/dist/src/input/keyboard.d.ts +17 -0
  107. package/dist/src/input/keyboard.js +46 -0
  108. package/dist/src/input/keyboard.js.map +1 -0
  109. package/dist/src/input/pointer.d.ts +53 -0
  110. package/dist/src/input/pointer.js +162 -0
  111. package/dist/src/input/pointer.js.map +1 -0
  112. package/dist/src/input/wheel.d.ts +12 -0
  113. package/dist/src/input/wheel.js +30 -0
  114. package/dist/src/input/wheel.js.map +1 -0
  115. package/dist/src/looper.d.ts +15 -0
  116. package/dist/src/looper.js +48 -0
  117. package/dist/src/looper.js.map +1 -0
  118. package/dist/src/mem/pool.d.ts +31 -0
  119. package/dist/src/mem/pool.js +98 -0
  120. package/dist/src/mem/pool.js.map +1 -0
  121. package/dist/src/pixel-ratio-observer.d.ts +10 -0
  122. package/dist/src/pixel-ratio-observer.js +26 -0
  123. package/dist/src/pixel-ratio-observer.js.map +1 -0
  124. package/dist/src/random/random.d.ts +8 -0
  125. package/dist/src/random/random.js +23 -0
  126. package/dist/src/random/random.js.map +1 -0
  127. package/dist/src/storage/local-storage.d.ts +3 -0
  128. package/dist/src/storage/local-storage.js +11 -0
  129. package/dist/src/storage/local-storage.js.map +1 -0
  130. package/dist/src/text/font.d.ts +6 -0
  131. package/dist/src/text/font.js +20 -0
  132. package/dist/src/text/font.js.map +1 -0
  133. package/dist/src/text/mem-prop-5x6.json +573 -0
  134. package/dist/src/text/text-layout.d.ts +19 -0
  135. package/dist/src/text/text-layout.js +85 -0
  136. package/dist/src/text/text-layout.js.map +1 -0
  137. package/dist/src/tsconfig.json +15 -0
  138. package/dist/src/types/geo.d.ts +38 -0
  139. package/dist/src/types/geo.js +61 -0
  140. package/dist/src/types/geo.js.map +1 -0
  141. package/dist/src/types/json.d.ts +31 -0
  142. package/dist/src/types/json.js +2 -0
  143. package/dist/src/types/json.js.map +1 -0
  144. package/dist/src/types/time.d.ts +19 -0
  145. package/dist/src/types/time.js +10 -0
  146. package/dist/src/types/time.js.map +1 -0
  147. package/dist/src/types/void-version.d.ts +9 -0
  148. package/dist/src/types/void-version.js +2 -0
  149. package/dist/src/types/void-version.js.map +1 -0
  150. package/dist/src/utils/async-util.d.ts +11 -0
  151. package/dist/src/utils/async-util.js +36 -0
  152. package/dist/src/utils/async-util.js.map +1 -0
  153. package/dist/src/utils/canvas-util.d.ts +7 -0
  154. package/dist/src/utils/canvas-util.js +128 -0
  155. package/dist/src/utils/canvas-util.js.map +1 -0
  156. package/dist/src/utils/color-util.d.ts +1 -0
  157. package/dist/src/utils/color-util.js +4 -0
  158. package/dist/src/utils/color-util.js.map +1 -0
  159. package/dist/src/utils/debug.d.ts +17 -0
  160. package/dist/src/utils/debug.js +34 -0
  161. package/dist/src/utils/debug.js.map +1 -0
  162. package/dist/src/utils/dom-util.d.ts +3 -0
  163. package/dist/src/utils/dom-util.js +29 -0
  164. package/dist/src/utils/dom-util.js.map +1 -0
  165. package/dist/src/utils/fetch-util.d.ts +3 -0
  166. package/dist/src/utils/fetch-util.js +24 -0
  167. package/dist/src/utils/fetch-util.js.map +1 -0
  168. package/dist/src/utils/math.d.ts +6 -0
  169. package/dist/src/utils/math.js +18 -0
  170. package/dist/src/utils/math.js.map +1 -0
  171. package/dist/src/utils/vibrate.d.ts +1 -0
  172. package/dist/src/utils/vibrate.js +4 -0
  173. package/dist/src/utils/vibrate.js.map +1 -0
  174. package/dist/src/void.d.ts +43 -0
  175. package/dist/src/void.js +95 -0
  176. package/dist/src/void.js.map +1 -0
  177. package/dist/tools/atlas-pack/aseprite.d.ts +58 -0
  178. package/dist/tools/atlas-pack/aseprite.js +16 -0
  179. package/dist/tools/atlas-pack/aseprite.js.map +1 -0
  180. package/dist/tools/atlas-pack/atlas-json-parser.d.ts +21 -0
  181. package/dist/tools/atlas-pack/atlas-json-parser.js +116 -0
  182. package/dist/tools/atlas-pack/atlas-json-parser.js.map +1 -0
  183. package/dist/tools/atlas-pack/atlas-pack.d.ts +2 -0
  184. package/dist/tools/atlas-pack/atlas-pack.js +17 -0
  185. package/dist/tools/atlas-pack/atlas-pack.js.map +1 -0
  186. package/dist/tools/bundle/bundle.d.ts +3 -0
  187. package/dist/tools/bundle/bundle.js +48 -0
  188. package/dist/tools/bundle/bundle.js.map +1 -0
  189. package/dist/tools/bundle/html-plugin.d.ts +3 -0
  190. package/dist/tools/bundle/html-plugin.js +88 -0
  191. package/dist/tools/bundle/html-plugin.js.map +1 -0
  192. package/dist/tools/tsconfig-base.json +45 -0
  193. package/dist/tools/tsconfig.json +21 -0
  194. package/dist/tools/types/config.d.ts +20 -0
  195. package/dist/tools/types/config.js +22 -0
  196. package/dist/tools/types/config.js.map +1 -0
  197. package/dist/tools/utils/argv.d.ts +12 -0
  198. package/dist/tools/utils/argv.js +19 -0
  199. package/dist/tools/utils/argv.js.map +1 -0
  200. package/dist/tools/utils/exec.d.ts +3 -0
  201. package/dist/tools/utils/exec.js +15 -0
  202. package/dist/tools/utils/exec.js.map +1 -0
  203. package/dist/tools/utils/file-util.d.ts +1 -0
  204. package/dist/tools/utils/file-util.js +13 -0
  205. package/dist/tools/utils/file-util.js.map +1 -0
  206. package/dist/tools/utils/html-parser.d.ts +1 -0
  207. package/dist/tools/utils/html-parser.js +10 -0
  208. package/dist/tools/utils/html-parser.js.map +1 -0
  209. package/dist/tools/void.d.ts +17 -0
  210. package/dist/tools/void.js +30 -0
  211. package/dist/tools/void.js.map +1 -0
  212. package/package.json +33 -39
  213. package/readme.md +1 -1
  214. package/schema/config-file.test.ts +55 -0
  215. package/schema/config-file.ts +69 -0
  216. package/schema/config-file.v0.json +68 -0
  217. package/tools/atlas-pack/aseprite.ts +60 -0
  218. package/tools/atlas-pack/atlas-json-parser.test.ts +780 -0
  219. package/tools/atlas-pack/atlas-json-parser.ts +159 -0
  220. package/tools/atlas-pack/atlas-pack.ts +38 -0
  221. package/tools/bundle/bundle.ts +65 -0
  222. package/tools/bundle/html-plugin.ts +135 -0
  223. package/tools/types/config.ts +43 -0
  224. package/tools/utils/argv.test.ts +41 -0
  225. package/tools/utils/argv.ts +29 -0
  226. package/tools/utils/exec.ts +22 -0
  227. package/tools/utils/file-util.ts +11 -0
  228. package/tools/utils/html-parser.ts +9 -0
  229. package/tools/void.ts +54 -0
  230. package/dist/atlas/aseprite.d.ts +0 -37
  231. package/dist/atlas/aseprite.js +0 -2
  232. package/dist/atlas/aseprite.js.map +0 -1
  233. package/dist/atlas/atlas-parser.d.ts +0 -52
  234. package/dist/atlas/atlas-parser.js +0 -109
  235. package/dist/atlas/atlas-parser.js.map +0 -1
  236. package/dist/atlas/atlas.d.ts +0 -12
  237. package/dist/atlas/atlas.js +0 -2
  238. package/dist/atlas/atlas.js.map +0 -1
  239. package/dist/audio/synth.d.ts +0 -4
  240. package/dist/audio/synth.js +0 -21
  241. package/dist/audio/synth.js.map +0 -1
  242. package/dist/graphics/bitmap.d.ts +0 -14
  243. package/dist/graphics/bitmap.js +0 -14
  244. package/dist/graphics/bitmap.js.map +0 -1
  245. package/dist/graphics/cam.d.ts +0 -16
  246. package/dist/graphics/cam.js +0 -42
  247. package/dist/graphics/cam.js.map +0 -1
  248. package/dist/graphics/frag.glsl.d.ts +0 -1
  249. package/dist/graphics/frag.glsl.js +0 -15
  250. package/dist/graphics/frag.glsl.js.map +0 -1
  251. package/dist/graphics/frame-listener.d.ts +0 -16
  252. package/dist/graphics/frame-listener.js +0 -83
  253. package/dist/graphics/frame-listener.js.map +0 -1
  254. package/dist/graphics/renderer.d.ts +0 -12
  255. package/dist/graphics/renderer.js +0 -185
  256. package/dist/graphics/renderer.js.map +0 -1
  257. package/dist/graphics/vert.glsl.d.ts +0 -1
  258. package/dist/graphics/vert.glsl.js +0 -46
  259. package/dist/graphics/vert.glsl.js.map +0 -1
  260. package/dist/index.d.ts +0 -31
  261. package/dist/index.js +0 -79
  262. package/dist/index.js.map +0 -1
  263. package/dist/input/gamepad-poller.d.ts +0 -8
  264. package/dist/input/gamepad-poller.js +0 -38
  265. package/dist/input/gamepad-poller.js.map +0 -1
  266. package/dist/input/input.d.ts +0 -44
  267. package/dist/input/input.js +0 -175
  268. package/dist/input/input.js.map +0 -1
  269. package/dist/input/keyboard-poller.d.ts +0 -7
  270. package/dist/input/keyboard-poller.js +0 -30
  271. package/dist/input/keyboard-poller.js.map +0 -1
  272. package/dist/input/pointer-poller.d.ts +0 -12
  273. package/dist/input/pointer-poller.js +0 -67
  274. package/dist/input/pointer-poller.js.map +0 -1
  275. package/dist/sprite/sprite.d.ts +0 -51
  276. package/dist/sprite/sprite.js +0 -161
  277. package/dist/sprite/sprite.js.map +0 -1
  278. package/dist/storage/json-storage.d.ts +0 -4
  279. package/dist/storage/json-storage.js +0 -13
  280. package/dist/storage/json-storage.js.map +0 -1
  281. package/dist/test/tsconfig.json +0 -14
  282. package/dist/text/font.d.ts +0 -6
  283. package/dist/text/font.js +0 -18
  284. package/dist/text/font.js.map +0 -1
  285. package/dist/text/text-layout.d.ts +0 -11
  286. package/dist/text/text-layout.js +0 -73
  287. package/dist/text/text-layout.js.map +0 -1
  288. package/dist/tsconfig.json +0 -13
  289. package/dist/types/2d.d.ts +0 -9
  290. package/dist/types/2d.js +0 -2
  291. package/dist/types/2d.js.map +0 -1
  292. package/dist/void.js +0 -60
  293. package/dist/void.js.map +0 -7
  294. package/dist/void.meta.json +0 -299
  295. package/tools/void.js +0 -143
@@ -0,0 +1,3844 @@
1
+ new EventSource('/esbuild').addEventListener('change', () => location.reload());
2
+
3
+ // <define:globalThis.voidVersion>
4
+ var define_globalThis_voidVersion_default = { hash: "2eb97a3", published: "20250824", version: "0.1.0-4" };
5
+
6
+ // src/types/void-version.ts
7
+ var voidVersion = define_globalThis_voidVersion_default;
8
+
9
+ // node_modules/mem-font/dist/mem-prop-5x6.json
10
+ var mem_prop_5x6_default = {
11
+ id: "mem-prop-5x6",
12
+ name: "mem 5x6",
13
+ cellWidth: 5,
14
+ cellHeight: 6,
15
+ leading: 1,
16
+ lineHeight: 7,
17
+ baseline: 1,
18
+ kerning: {
19
+ " 0": 0,
20
+ " 1": 0,
21
+ " 2": 0,
22
+ " 3": 0,
23
+ " 4": 0,
24
+ " 5": 0,
25
+ " 6": 0,
26
+ " 7": 0,
27
+ " 8": 0,
28
+ " 9": 0,
29
+ "##": -1,
30
+ "#_": 0,
31
+ "',": 0,
32
+ "'.": 0,
33
+ "'/": 0,
34
+ "'J": 0,
35
+ "'S": 0,
36
+ "'_": 0,
37
+ "'j": 0,
38
+ "'s": 0,
39
+ "(+": 0,
40
+ "(-": 0,
41
+ "(<": 0,
42
+ "(f": 0,
43
+ "({": 0,
44
+ "(~": 0,
45
+ ")_": 0,
46
+ "*,": 0,
47
+ "*.": 0,
48
+ "*/": 0,
49
+ "*S": 0,
50
+ "*_": 0,
51
+ "*j": 0,
52
+ "*s": 0,
53
+ "+)": 0,
54
+ "+,": 0,
55
+ "+.": 0,
56
+ "+/": 0,
57
+ "+>": 0,
58
+ "+?": 0,
59
+ "+I": 0,
60
+ "+S": 0,
61
+ "+T": 0,
62
+ "+Z": 0,
63
+ "+]": 0,
64
+ "+_": 0,
65
+ "+`": 0,
66
+ "+j": 0,
67
+ "+s": 0,
68
+ "+}": 0,
69
+ ",'": 0,
70
+ ",*": 0,
71
+ ",+": 0,
72
+ ",-": 0,
73
+ ",<": 0,
74
+ ",?": 0,
75
+ ",T": 0,
76
+ ",Y": 0,
77
+ ",Z": 0,
78
+ ',"': 0,
79
+ ",\\": 0,
80
+ ",^": 0,
81
+ ",`": 0,
82
+ ",f": 0,
83
+ ",t": 0,
84
+ ",z": 0,
85
+ ",{": 0,
86
+ ",~": 0,
87
+ "-)": 0,
88
+ "-,": 0,
89
+ "--": 0,
90
+ "-.": 0,
91
+ "-/": 0,
92
+ "->": 0,
93
+ "-?": 0,
94
+ "-I": 0,
95
+ "-S": 0,
96
+ "-T": 0,
97
+ "-Z": 0,
98
+ "-]": 0,
99
+ "-_": 0,
100
+ "-`": 0,
101
+ "-j": 0,
102
+ "-s": 0,
103
+ "-}": 0,
104
+ ".'": 0,
105
+ ".*": 0,
106
+ ".+": 0,
107
+ ".-": 0,
108
+ ".<": 0,
109
+ ".?": 0,
110
+ ".T": 0,
111
+ ".Y": 0,
112
+ ".Z": 0,
113
+ '."': 0,
114
+ ".\\": 0,
115
+ ".^": 0,
116
+ ".`": 0,
117
+ ".f": 0,
118
+ ".t": 0,
119
+ ".z": 0,
120
+ ".{": 0,
121
+ ".~": 0,
122
+ "/,": 0,
123
+ "/.": 0,
124
+ "//": 0,
125
+ "/J": 0,
126
+ "/S": 0,
127
+ "/_": 0,
128
+ "/j": 0,
129
+ "/s": 0,
130
+ "0 ": 0,
131
+ "1 ": 0,
132
+ "1T": 0,
133
+ "1Y": 0,
134
+ "1Z": 0,
135
+ "1f": 0,
136
+ "1t": 0,
137
+ "1z": 0,
138
+ "2 ": 0,
139
+ "3 ": 0,
140
+ "4 ": 0,
141
+ "5 ": 0,
142
+ "6 ": 0,
143
+ "7 ": 0,
144
+ "8 ": 0,
145
+ "9 ": 0,
146
+ ":?": 0,
147
+ ":T": 0,
148
+ ":Z": 0,
149
+ ":`": 0,
150
+ ";?": 0,
151
+ ";T": 0,
152
+ ";Z": 0,
153
+ "<+": 0,
154
+ "<-": 0,
155
+ "<<": 0,
156
+ "<f": 0,
157
+ "<{": 0,
158
+ "<~": 0,
159
+ "==": 0,
160
+ "=_": 0,
161
+ ">)": 0,
162
+ ">,": 0,
163
+ ">.": 0,
164
+ ">/": 0,
165
+ ">>": 0,
166
+ ">?": 0,
167
+ ">I": 0,
168
+ ">S": 0,
169
+ ">T": 0,
170
+ ">Z": 0,
171
+ ">]": 0,
172
+ ">_": 0,
173
+ ">`": 0,
174
+ ">j": 0,
175
+ ">s": 0,
176
+ ">}": 0,
177
+ "?,": 0,
178
+ "?.": 0,
179
+ "?/": 0,
180
+ "?S": 0,
181
+ "?_": 0,
182
+ "?j": 0,
183
+ "?s": 0,
184
+ "@_": 0,
185
+ "C+": 0,
186
+ "C-": 0,
187
+ "C<": 0,
188
+ Cf: 0,
189
+ "C{": 0,
190
+ "C~": 0,
191
+ D_: 0,
192
+ "E+": 0,
193
+ "E-": 0,
194
+ "E<": 0,
195
+ Ef: 0,
196
+ "E{": 0,
197
+ "E~": 0,
198
+ "F&": 0,
199
+ "F+": 0,
200
+ "F,": 0,
201
+ "F-": 0,
202
+ "F.": 0,
203
+ "F/": 0,
204
+ "F:": 0,
205
+ "F;": 0,
206
+ "F<": 0,
207
+ FJ: 0,
208
+ FS: 0,
209
+ F_: 0,
210
+ Fa: 0,
211
+ Fe: 0,
212
+ Ff: 0,
213
+ Fg: 0,
214
+ Fj: 0,
215
+ Fq: 0,
216
+ Fs: 0,
217
+ "F{": 0,
218
+ "F~": 0,
219
+ "I+": 0,
220
+ "I-": 0,
221
+ "I<": 0,
222
+ If: 0,
223
+ "I{": 0,
224
+ "I~": 0,
225
+ "L'": 0,
226
+ "L*": 0,
227
+ "L+": 0,
228
+ "L-": 0,
229
+ L4: 0,
230
+ L7: 0,
231
+ "L<": 0,
232
+ "L?": 0,
233
+ LT: 0,
234
+ LY: 0,
235
+ LZ: 0,
236
+ 'L"': 0,
237
+ "L\\": 0,
238
+ "L^": 0,
239
+ "L`": 0,
240
+ Lf: 0,
241
+ Lt: 0,
242
+ Lz: 0,
243
+ "L{": 0,
244
+ "L~": 0,
245
+ "P,": 0,
246
+ "P.": 0,
247
+ "P/": 0,
248
+ PS: 0,
249
+ P_: 0,
250
+ Pj: 0,
251
+ Ps: 0,
252
+ "S&": 0,
253
+ "S+": 0,
254
+ "S,": 0,
255
+ "S-": 0,
256
+ "S.": 0,
257
+ "S/": 0,
258
+ "S:": 0,
259
+ "S;": 0,
260
+ "S<": 0,
261
+ SJ: 0,
262
+ SS: 0,
263
+ S_: 0,
264
+ Sa: 0,
265
+ Se: 0,
266
+ Sf: 0,
267
+ Sg: 0,
268
+ Sj: 0,
269
+ Sq: 0,
270
+ Ss: 0,
271
+ "S{": 0,
272
+ "S~": 0,
273
+ "T&": 0,
274
+ "T+": 0,
275
+ "T,": 0,
276
+ "T-": 0,
277
+ "T.": 0,
278
+ "T/": 0,
279
+ "T:": 0,
280
+ "T;": 0,
281
+ "T<": 0,
282
+ TJ: 0,
283
+ TS: 0,
284
+ T_: 0,
285
+ Ta: 0,
286
+ Te: 0,
287
+ Tf: 0,
288
+ Tg: 0,
289
+ Tj: 0,
290
+ Tq: 0,
291
+ Ts: 0,
292
+ "T{": 0,
293
+ "T~": 0,
294
+ V_: 0,
295
+ "Y,": 0,
296
+ "Y.": 0,
297
+ "Y/": 0,
298
+ YS: 0,
299
+ Y_: 0,
300
+ Yj: 0,
301
+ Ys: 0,
302
+ "Z'": 0,
303
+ "Z*": 0,
304
+ "Z+": 0,
305
+ "Z-": 0,
306
+ Z4: 0,
307
+ Z7: 0,
308
+ "Z<": 0,
309
+ "Z?": 0,
310
+ ZT: 0,
311
+ ZY: 0,
312
+ ZZ: 0,
313
+ 'Z"': 0,
314
+ "Z\\": 0,
315
+ "Z^": 0,
316
+ "Z`": 0,
317
+ Zf: 0,
318
+ Zt: 0,
319
+ Zz: 0,
320
+ "Z{": 0,
321
+ "Z~": 0,
322
+ "[+": 0,
323
+ "[-": 0,
324
+ "[<": 0,
325
+ "[f": 0,
326
+ "[{": 0,
327
+ "[~": 0,
328
+ '",': 0,
329
+ '".': 0,
330
+ '"/': 0,
331
+ '"J': 0,
332
+ '"S': 0,
333
+ '"_': 0,
334
+ '"j': 0,
335
+ '"s': 0,
336
+ "\\'": 0,
337
+ "\\*": 0,
338
+ "\\+": 0,
339
+ "\\-": 0,
340
+ "\\<": 0,
341
+ "\\?": 0,
342
+ "\\T": 0,
343
+ "\\Y": 0,
344
+ "\\Z": 0,
345
+ '\\"': 0,
346
+ "\\\\": 0,
347
+ "\\^": 0,
348
+ "\\`": 0,
349
+ "\\f": 0,
350
+ "\\t": 0,
351
+ "\\z": 0,
352
+ "\\{": 0,
353
+ "\\~": 0,
354
+ "^,": 0,
355
+ "^.": 0,
356
+ "^/": 0,
357
+ "^J": 0,
358
+ "^S": 0,
359
+ "^_": 0,
360
+ "^j": 0,
361
+ "^s": 0,
362
+ "_#": 0,
363
+ "_%": 0,
364
+ "_'": 0,
365
+ "_(": 0,
366
+ "_*": 0,
367
+ "_+": 0,
368
+ "_-": 0,
369
+ "_<": 0,
370
+ "_=": 0,
371
+ "_?": 0,
372
+ "_@": 0,
373
+ _T: 0,
374
+ _V: 0,
375
+ _Y: 0,
376
+ _Z: 0,
377
+ '_"': 0,
378
+ "_\\": 0,
379
+ "_^": 0,
380
+ __: 0,
381
+ "_`": 0,
382
+ _a: 0,
383
+ _e: 0,
384
+ _f: 0,
385
+ _t: 0,
386
+ _v: 0,
387
+ _z: 0,
388
+ "_{": 0,
389
+ "_~": 0,
390
+ "`,": 0,
391
+ "`.": 0,
392
+ "`/": 0,
393
+ "`J": 0,
394
+ "`S": 0,
395
+ "`_": 0,
396
+ "`j": 0,
397
+ "`s": 0,
398
+ "f,": 0,
399
+ "f.": 0,
400
+ "f/": 0,
401
+ fS: 0,
402
+ f_: 0,
403
+ fj: 0,
404
+ fs: 0,
405
+ "q#": 0,
406
+ q$: 0,
407
+ "q%": 0,
408
+ "q&": 0,
409
+ "q'": 0,
410
+ "q(": 0,
411
+ "q*": 0,
412
+ "q+": 0,
413
+ "q-": 0,
414
+ q0: 0,
415
+ q1: 0,
416
+ q2: 0,
417
+ q3: 0,
418
+ q4: 0,
419
+ q5: 0,
420
+ q6: 0,
421
+ q7: 0,
422
+ q8: 0,
423
+ q9: 0,
424
+ "q<": 0,
425
+ "q=": 0,
426
+ "q?": 0,
427
+ "q@": 0,
428
+ qA: 0,
429
+ qB: 0,
430
+ qC: 0,
431
+ qD: 0,
432
+ qE: 0,
433
+ qF: 0,
434
+ qG: 0,
435
+ qH: 0,
436
+ qI: 0,
437
+ qJ: 0,
438
+ qK: 0,
439
+ qL: 0,
440
+ qM: 0,
441
+ qN: 0,
442
+ qO: 0,
443
+ qP: 0,
444
+ qQ: 0,
445
+ qR: 0,
446
+ qS: 0,
447
+ qT: 0,
448
+ qU: 0,
449
+ qV: 0,
450
+ qW: 0,
451
+ qX: 0,
452
+ qY: 0,
453
+ qZ: 0,
454
+ "q[": 0,
455
+ 'q"': 0,
456
+ "q\\": 0,
457
+ "q]": 0,
458
+ "q^": 0,
459
+ "q`": 0,
460
+ qa: 0,
461
+ qb: 0,
462
+ qc: 0,
463
+ qd: 0,
464
+ qe: 0,
465
+ qf: 0,
466
+ qh: 0,
467
+ qk: 0,
468
+ qm: 0,
469
+ qn: 0,
470
+ qo: 0,
471
+ qq: 0,
472
+ qr: 0,
473
+ qs: 0,
474
+ qt: 0,
475
+ qu: 0,
476
+ qv: 0,
477
+ qw: 0,
478
+ qx: 0,
479
+ qz: 0,
480
+ "q{": 0,
481
+ "q}": 0,
482
+ "q~": 0,
483
+ "r,": 0,
484
+ "r.": 0,
485
+ "r/": 0,
486
+ rS: 0,
487
+ r_: 0,
488
+ rj: -1,
489
+ rs: 0,
490
+ "s,": 0,
491
+ "s.": 0,
492
+ "s/": 0,
493
+ sJ: 0,
494
+ sS: 0,
495
+ s_: 0,
496
+ sj: 0,
497
+ ss: 0,
498
+ "z'": 0,
499
+ "z*": 0,
500
+ "z+": 0,
501
+ "z-": 0,
502
+ z4: 0,
503
+ z7: 0,
504
+ "z<": 0,
505
+ "z?": 0,
506
+ zT: 0,
507
+ zY: 0,
508
+ zZ: 0,
509
+ 'z"': 0,
510
+ "z\\": 0,
511
+ "z^": 0,
512
+ "z`": 0,
513
+ zf: 0,
514
+ zt: 0,
515
+ zz: 0,
516
+ "z{": 0,
517
+ "z~": 0,
518
+ "{+": 0,
519
+ "{-": 0,
520
+ "{<": 0,
521
+ "{f": 0,
522
+ "{{": 0,
523
+ "{~": 0,
524
+ "})": 0,
525
+ "},": 0,
526
+ "}.": 0,
527
+ "}/": 0,
528
+ "}>": 0,
529
+ "}?": 0,
530
+ "}I": 0,
531
+ "}S": 0,
532
+ "}T": 0,
533
+ "}Z": 0,
534
+ "}]": 0,
535
+ "}_": 0,
536
+ "}`": 0,
537
+ "}j": 0,
538
+ "}s": 0,
539
+ "}}": 0,
540
+ "~'": 0,
541
+ "~?": 0,
542
+ "~T": 0,
543
+ "~Z": 0,
544
+ '~"': 0,
545
+ "~\\": 0,
546
+ "~^": 0,
547
+ "~_": 0,
548
+ "~`": 0,
549
+ "~t": 0,
550
+ "~z": 0
551
+ },
552
+ defaultKerning: 1,
553
+ defaultWhitespaceKerning: -1,
554
+ endOfLineKerning: 0,
555
+ charWidth: {
556
+ " ": 4,
557
+ "!": 1,
558
+ "#": 5,
559
+ "&": 4,
560
+ "'": 1,
561
+ "(": 2,
562
+ ")": 2,
563
+ ",": 1,
564
+ ".": 1,
565
+ ":": 1,
566
+ ";": 1,
567
+ "@": 5,
568
+ M: 5,
569
+ W: 5,
570
+ "[": 2,
571
+ "\n": 0,
572
+ "]": 2,
573
+ "`": 2,
574
+ i: 1,
575
+ l: 1,
576
+ m: 5,
577
+ q: 4,
578
+ w: 5,
579
+ "|": 1
580
+ },
581
+ defaultCharWidth: 3
582
+ };
583
+
584
+ // node_modules/mem-font/dist/index.js
585
+ var memProp5x6 = mem_prop_5x6_default;
586
+
587
+ // src/graphics/layer.ts
588
+ var Layer = {
589
+ Top: 0,
590
+ UIA: 1,
591
+ UIB: 2,
592
+ UIC: 3,
593
+ UID: 4,
594
+ UIE: 5,
595
+ UIF: 6,
596
+ UIG: 7,
597
+ A: 8,
598
+ B: 9,
599
+ C: 10,
600
+ D: 11,
601
+ E: 12,
602
+ F: 13,
603
+ Bottom: 14,
604
+ Hidden: 15
605
+ };
606
+ function layerOffset(layer, offset) {
607
+ return Math.max(Layer.Top, Math.min(Layer.Bottom, layer + offset));
608
+ }
609
+
610
+ // src/types/geo.ts
611
+ function boxHits(l, r) {
612
+ const rWH = { w: r.w ?? 1, h: r.h ?? 1 };
613
+ if (!l.w || !l.h || !rWH.w || !rWH.h) return false;
614
+ const lXY = { x: l.x ?? 0, y: l.y ?? 0 };
615
+ return lXY.x < r.x + rWH.w && lXY.x + l.w > r.x && lXY.y < r.y + rWH.h && lXY.y + l.h > r.y;
616
+ }
617
+ function whAssign(l, r) {
618
+ l.w = r.w;
619
+ l.h = r.h;
620
+ }
621
+ function whEq(l, r) {
622
+ return l.w === r.w && l.h === r.h;
623
+ }
624
+ function xyAdd(l, r) {
625
+ return { x: l.x + r.x, y: l.y + r.y };
626
+ }
627
+ function xyAssign(l, r) {
628
+ l.x = r.x;
629
+ l.y = r.y;
630
+ }
631
+ function xyDistance(from, to) {
632
+ return xyMagnitude(xySub(from, to));
633
+ }
634
+ function xyEq(l, r) {
635
+ return l.x === r.x && l.y === r.y;
636
+ }
637
+ function xyMagnitude(xy) {
638
+ return Math.hypot(xy.x, xy.y);
639
+ }
640
+ function xyMax(l, r) {
641
+ return { x: Math.max(l.x, r.x), y: Math.max(l.y, r.y) };
642
+ }
643
+ function xyMin(l, r) {
644
+ return { x: Math.min(l.x, r.x), y: Math.min(l.y, r.y) };
645
+ }
646
+ function xySub(l, r) {
647
+ return { x: l.x - r.x, y: l.y - r.y };
648
+ }
649
+
650
+ // src/ents/nine-patch-ent.ts
651
+ var NinePatchEnt = class {
652
+ #dir;
653
+ #margin;
654
+ #invalid = true;
655
+ constructor(v2, opts) {
656
+ this.#dir = {
657
+ w: v2.sprites.alloc(),
658
+ nw: v2.sprites.alloc(),
659
+ n: v2.sprites.alloc(),
660
+ ne: v2.sprites.alloc(),
661
+ e: v2.sprites.alloc(),
662
+ se: v2.sprites.alloc(),
663
+ s: v2.sprites.alloc(),
664
+ sw: v2.sprites.alloc(),
665
+ origin: v2.sprites.alloc()
666
+ };
667
+ this.#dir.w.tag = opts.w?.tag ?? opts.e?.tag ?? opts.n.tag;
668
+ this.#dir.n.tag = opts.n.tag;
669
+ this.#dir.e.tag = opts.e?.tag ?? this.#dir.w.tag;
670
+ this.#dir.s.tag = opts.s?.tag ?? this.#dir.n.tag;
671
+ this.#dir.nw.tag = opts.nw?.tag ?? opts.se?.tag ?? opts.n.tag;
672
+ this.#dir.ne.tag = opts.ne?.tag ?? opts.sw?.tag ?? opts.nw?.tag ?? opts.n.tag;
673
+ this.#dir.se.tag = opts.se?.tag ?? this.#dir.nw.tag;
674
+ this.#dir.sw.tag = opts.sw?.tag ?? this.#dir.ne.tag;
675
+ this.#dir.origin.tag = opts.origin.tag;
676
+ this.#dir.w.z = this.#dir.nw.z = this.#dir.n.z = this.#dir.ne.z = this.#dir.e.z = this.#dir.se.z = this.#dir.s.z = this.#dir.sw.z = this.#dir.origin.z = opts.z ?? 0;
677
+ this.#dir.w.stretch = opts.w?.stretch ?? opts.e?.stretch ?? false;
678
+ this.#dir.n.stretch = opts.n.stretch ?? opts.s?.stretch ?? false;
679
+ this.#dir.e.stretch = opts.e?.stretch ?? this.#dir.w.stretch;
680
+ this.#dir.s.stretch = opts.s?.stretch ?? this.#dir.n.stretch;
681
+ this.#dir.nw.stretch = opts.nw?.stretch ?? opts.se?.stretch ?? false;
682
+ this.#dir.ne.stretch = opts.ne?.stretch ?? opts.sw?.stretch ?? false;
683
+ this.#dir.se.stretch = opts.se?.stretch ?? this.#dir.nw.stretch;
684
+ this.#dir.sw.stretch = opts.sw?.stretch ?? this.#dir.ne.stretch;
685
+ this.#dir.origin.stretch = opts.origin.stretch ?? false;
686
+ this.#dir.w.flipX = opts.w?.flip?.x ?? !opts.e?.flip?.x;
687
+ this.#dir.w.flipY = opts.w?.flip?.y ?? !!opts.e?.flip?.y;
688
+ this.#dir.n.flipX = opts.n.flip?.x ?? !!opts.s?.flip?.x;
689
+ this.#dir.n.flipY = opts.n.flip?.y ?? !opts.s?.flip?.y;
690
+ this.#dir.e.flipX = opts.e?.flip?.x ?? !this.#dir.w.flipX;
691
+ this.#dir.e.flipY = opts.e?.flip?.y ?? this.#dir.w.flipY;
692
+ this.#dir.s.flipX = opts.s?.flip?.x ?? this.#dir.n.flipX;
693
+ this.#dir.s.flipY = opts.s?.flip?.y ?? !this.#dir.n.flipY;
694
+ this.#dir.origin.flipX = !!opts.origin.flip?.x;
695
+ this.#dir.origin.flipY = !!opts.origin.flip?.y;
696
+ this.#dir.n.h = opts.border?.n ?? opts.border?.s ?? this.#dir.n.h;
697
+ this.#dir.w.w = opts.border?.w ?? opts.border?.e ?? this.#dir.n.h;
698
+ this.#dir.e.w = opts.border?.e ?? this.#dir.w.w;
699
+ this.#dir.s.h = opts.border?.s ?? this.#dir.n.h;
700
+ this.#dir.nw.w = this.#dir.w.w;
701
+ this.#dir.nw.h = this.#dir.n.h;
702
+ this.#dir.ne.w = this.#dir.e.w;
703
+ this.#dir.ne.h = this.#dir.n.h;
704
+ this.#dir.se.w = this.#dir.e.w;
705
+ this.#dir.se.h = this.#dir.s.h;
706
+ this.#dir.sw.w = this.#dir.w.w;
707
+ this.#dir.sw.h = this.#dir.s.h;
708
+ this.#margin = { w: opts.margin?.w ?? 0, h: opts.margin?.h ?? 0 };
709
+ const w = opts.wh?.w == null ? this.#dir.w.w + this.#dir.n.w + this.#dir.e.w : opts.wh.w;
710
+ this.#dir.n.w = w - 1;
711
+ this.wh = {
712
+ w,
713
+ h: opts.wh?.h == null ? this.#dir.n.h + this.#dir.e.h + this.#dir.s.h : opts.wh.h
714
+ };
715
+ this.#dir.nw.x = (opts.x ?? 0) - 1;
716
+ this.xy = { x: opts.x ?? 0, y: opts.y ?? 0 };
717
+ }
718
+ free(v2) {
719
+ v2.sprites.free(
720
+ this.#dir.w,
721
+ this.#dir.nw,
722
+ this.#dir.n,
723
+ this.#dir.ne,
724
+ this.#dir.e,
725
+ this.#dir.se,
726
+ this.#dir.s,
727
+ this.#dir.sw,
728
+ this.#dir.origin
729
+ );
730
+ }
731
+ update() {
732
+ if (!this.#invalid) return;
733
+ this.#invalid = false;
734
+ return true;
735
+ }
736
+ get wh() {
737
+ return {
738
+ w: this.#dir.w.w + this.#dir.n.w + this.#dir.e.w + this.#margin.w,
739
+ h: this.#dir.n.h + this.#dir.w.h + this.#dir.s.h + this.#margin.h
740
+ };
741
+ }
742
+ set wh(wh) {
743
+ if (whEq(wh, this.wh)) return;
744
+ this.#dir.w.h = wh.h - this.#dir.n.h - this.#dir.s.h - this.#margin.h;
745
+ this.#dir.n.w = wh.w - this.#dir.w.w - this.#dir.e.w - this.#margin.w;
746
+ this.#dir.s.w = this.#dir.n.w;
747
+ this.#dir.e.h = this.#dir.w.h;
748
+ this.#dir.origin.w = this.#dir.n.w;
749
+ this.#dir.origin.h = this.#dir.e.h;
750
+ this.#setXYRight();
751
+ this.#invalid = true;
752
+ }
753
+ get xy() {
754
+ return {
755
+ x: this.#dir.nw.x - this.#margin.w / 2,
756
+ y: this.#dir.nw.y - this.#margin.h / 2
757
+ };
758
+ }
759
+ set xy(xy) {
760
+ if (xyEq(xy, this.xy)) return;
761
+ this.#dir.nw.x = xy.x + this.#margin.w / 2;
762
+ this.#dir.nw.y = xy.y + this.#margin.h / 2;
763
+ this.#dir.w.x = this.#dir.nw.x;
764
+ this.#dir.w.y = this.#dir.nw.y + this.#dir.nw.h;
765
+ this.#dir.n.x = this.#dir.nw.x + this.#dir.nw.w;
766
+ this.#dir.n.y = this.#dir.nw.y;
767
+ this.#dir.origin.x = this.#dir.n.x;
768
+ this.#dir.origin.y = this.#dir.nw.y + this.#dir.ne.h;
769
+ this.#setXYRight();
770
+ this.#invalid = true;
771
+ }
772
+ #setXYRight() {
773
+ this.#dir.ne.x = this.#dir.n.x + this.#dir.n.w;
774
+ this.#dir.ne.y = this.#dir.nw.y;
775
+ this.#dir.e.x = this.#dir.ne.x;
776
+ this.#dir.e.y = this.#dir.nw.y + this.#dir.ne.h;
777
+ this.#dir.se.x = this.#dir.e.x;
778
+ this.#dir.se.y = this.#dir.e.y + this.#dir.e.h;
779
+ this.#dir.s.x = this.#dir.n.x;
780
+ this.#dir.s.y = this.#dir.se.y;
781
+ this.#dir.sw.x = this.#dir.nw.x;
782
+ this.#dir.sw.y = this.#dir.se.y;
783
+ }
784
+ };
785
+
786
+ // src/text/font.ts
787
+ function fontCharToTag(font, char) {
788
+ let pt = char.codePointAt(0);
789
+ if (pt == null || pt > 255) pt = 63;
790
+ return `${font.id}--${pt.toString(16).padStart(2, "0")}`;
791
+ }
792
+ function fontKerning(font, l, r) {
793
+ if (r == null) return font.endOfLineKerning;
794
+ if (font.kerning[l + r] != null) return font.kerning[l + r];
795
+ if (/^\s?$/.test(l) || /^\s?$/.test(r)) return font.defaultWhitespaceKerning;
796
+ return font.defaultKerning;
797
+ }
798
+ function fontCharWidth(font, letter) {
799
+ return font.charWidth[letter] ?? font.defaultCharWidth;
800
+ }
801
+
802
+ // src/text/text-layout.ts
803
+ function layoutText(opts) {
804
+ const chars = [];
805
+ const scale = opts.scale ?? 1;
806
+ const start = opts.start ?? { x: 0, y: 0 };
807
+ const maxW = opts.maxW ?? Infinity;
808
+ let cursor = { x: start.x, y: start.y };
809
+ let w = 0;
810
+ while (chars.length < opts.str.length) {
811
+ const i = chars.length;
812
+ const char = opts.str[i];
813
+ let layout;
814
+ if (char === "\n") layout = layoutNewline(opts.font, cursor, start.x, scale);
815
+ else if (/^\s*$/.test(char)) {
816
+ layout = layoutSpace(
817
+ opts.font,
818
+ cursor,
819
+ maxW,
820
+ tracking(opts.font, char, opts.str[i + 1], scale),
821
+ start.x,
822
+ scale
823
+ );
824
+ } else {
825
+ layout = layoutWord(opts.font, cursor, maxW, opts.str, i, start.x, scale);
826
+ if (cursor.x > 0 && layout.cursor.y === nextLine(opts.font, start.x, cursor.y, scale).y) {
827
+ const wordW = maxW - cursor.x + layout.cursor.x;
828
+ if (wordW <= maxW) {
829
+ cursor = nextLine(opts.font, start.x, cursor.y, scale);
830
+ layout = layoutWord(
831
+ opts.font,
832
+ cursor,
833
+ maxW,
834
+ opts.str,
835
+ i,
836
+ start.x,
837
+ scale
838
+ );
839
+ }
840
+ }
841
+ }
842
+ chars.push(...layout.chars);
843
+ cursor.x = layout.cursor.x;
844
+ cursor.y = layout.cursor.y;
845
+ w = Math.max(w, layout.cursor.x - start.x);
846
+ }
847
+ return {
848
+ chars,
849
+ cursor,
850
+ wh: { w, h: nextLine(opts.font, start.x, cursor.y, scale).y - start.y }
851
+ };
852
+ }
853
+ function layoutWord(font, cursor, maxW, word, index, startX, scale) {
854
+ const chars = [];
855
+ let { x, y } = cursor;
856
+ for (; ; index++) {
857
+ const char = word[index];
858
+ if (!char || /^\s*$/.test(char)) break;
859
+ const span = tracking(font, char, word[index + 1], scale);
860
+ if (x > startX && x + span > startX + maxW)
861
+ ({ x, y } = nextLine(font, startX, y, scale));
862
+ chars.push({ x, y, w: fontCharWidth(font, char), h: font.cellHeight });
863
+ x += span;
864
+ }
865
+ return { chars, cursor: { x, y } };
866
+ }
867
+ function nextLine(font, startX, curY, scale) {
868
+ return { x: startX, y: curY + font.lineHeight * scale };
869
+ }
870
+ function layoutNewline(font, cursor, startX, scale) {
871
+ return { chars: [void 0], cursor: nextLine(font, startX, cursor.y, scale) };
872
+ }
873
+ function layoutSpace(font, cursor, w, span, startX, scale) {
874
+ const nextCursor = cursor.x > 0 && cursor.x + span >= w ? nextLine(font, startX, cursor.y, scale) : { x: cursor.x + span, y: cursor.y };
875
+ return { chars: [void 0], cursor: nextCursor };
876
+ }
877
+ function tracking(font, l, r, scale) {
878
+ return scale * (fontCharWidth(font, l) + fontKerning(font, l, r));
879
+ }
880
+
881
+ // src/ents/text-ent.ts
882
+ var TextEnt = class {
883
+ #maxW = Infinity;
884
+ #layout = "Outdated";
885
+ #z = Layer.UIA;
886
+ #scale = 1;
887
+ #sprites = [];
888
+ #str = "";
889
+ #wh = { w: 0, h: 0 };
890
+ #xy = { x: 0, y: 0 };
891
+ free(v2) {
892
+ v2.sprites.free(...this.#sprites);
893
+ }
894
+ layout(v2) {
895
+ if (this.#layout !== "Outdated") return false;
896
+ let len = 0;
897
+ const layout = layoutText({
898
+ font: memProp5x6,
899
+ maxW: this.#maxW,
900
+ scale: this.#scale,
901
+ start: this.#xy,
902
+ str: this.#str
903
+ });
904
+ this.#wh = { w: layout.wh.w, h: layout.wh.h };
905
+ for (const [i, char] of layout.chars.entries()) {
906
+ if (char == null) continue;
907
+ const sprite = this.#sprites[len] ??= v2.sprites.alloc();
908
+ sprite.x = char.x;
909
+ sprite.y = char.y;
910
+ sprite.tag = fontCharToTag(memProp5x6, this.#str[i]);
911
+ sprite.stretch = true;
912
+ sprite.w *= this.#scale;
913
+ sprite.h *= this.#scale;
914
+ sprite.z = this.#z;
915
+ len++;
916
+ }
917
+ while (this.#sprites.length > len) v2.sprites.free(this.#sprites.pop());
918
+ this.#layout = "Updated";
919
+ return true;
920
+ }
921
+ get maxW() {
922
+ return this.#maxW;
923
+ }
924
+ set maxW(w) {
925
+ if (w === this.#maxW) return;
926
+ this.#maxW = w;
927
+ this.#layout = "Outdated";
928
+ }
929
+ get scale() {
930
+ return this.#scale;
931
+ }
932
+ set scale(scale) {
933
+ if (scale === this.#scale) return;
934
+ this.#scale = scale;
935
+ this.#layout = "Outdated";
936
+ }
937
+ get text() {
938
+ return this.#str;
939
+ }
940
+ set text(str) {
941
+ if (str === this.#str) return;
942
+ this.#str = str;
943
+ this.#layout = "Outdated";
944
+ }
945
+ update(v2) {
946
+ if (this.#layout === "Rendered") return;
947
+ if (this.#layout === "Outdated") this.layout(v2);
948
+ this.#layout = "Rendered";
949
+ return true;
950
+ }
951
+ get scaledLeading() {
952
+ return memProp5x6.leading * this.#scale;
953
+ }
954
+ get wh() {
955
+ return this.#wh;
956
+ }
957
+ get xy() {
958
+ return this.#xy;
959
+ }
960
+ set xy(xy) {
961
+ if (xyEq(xy, this.#xy)) return;
962
+ this.#xy.x = xy.x;
963
+ this.#xy.y = xy.y;
964
+ this.#layout = "Outdated";
965
+ }
966
+ get z() {
967
+ return this.#z;
968
+ }
969
+ set z(layer) {
970
+ if (layer === this.#z) return;
971
+ this.#z = layer;
972
+ this.#layout = "Outdated";
973
+ }
974
+ };
975
+
976
+ // src/ents/button-ent.ts
977
+ var ButtonEnt = class {
978
+ #button;
979
+ #invalid = true;
980
+ #pressed;
981
+ #selected;
982
+ #started = false;
983
+ #toggle = false;
984
+ #text = new TextEnt();
985
+ #xy = { x: 0, y: 0 };
986
+ constructor(v2, opts) {
987
+ const buttonZ = opts.button.z ?? Layer.UID;
988
+ this.#button = new NinePatchEnt(v2, {
989
+ ...opts.button,
990
+ x: opts.x,
991
+ y: opts.y,
992
+ z: buttonZ,
993
+ wh: { w: opts.w, h: opts.h }
994
+ });
995
+ this.#pressed = {
996
+ sprite: v2.sprites.alloc(),
997
+ z: opts.pressed.z ?? layerOffset(buttonZ, 2)
998
+ };
999
+ this.#selected = {
1000
+ sprite: v2.sprites.alloc(),
1001
+ z: opts.selected.z ?? layerOffset(this.#pressed.z, -1)
1002
+ };
1003
+ this.#pressed.sprite.tag = opts.pressed.tag;
1004
+ this.#pressed.sprite.x = opts.x ?? 0;
1005
+ this.#pressed.sprite.y = opts.y ?? 0;
1006
+ this.#pressed.sprite.w = opts.w ?? this.#button.wh.w;
1007
+ this.#pressed.sprite.h = opts.h ?? this.#button.wh.h;
1008
+ this.#pressed.sprite.z = Layer.Hidden;
1009
+ this.#selected.sprite.tag = opts.selected.tag;
1010
+ this.#selected.sprite.x = opts.x ?? 0;
1011
+ this.#selected.sprite.y = opts.y ?? 0;
1012
+ this.#selected.sprite.w = opts.w ?? this.#button.wh.w;
1013
+ this.#selected.sprite.h = opts.h ?? this.#button.wh.h;
1014
+ this.#selected.sprite.z = Layer.Hidden;
1015
+ this.#text.text = opts.text?.text ?? "";
1016
+ this.#text.scale = opts.text?.scale ?? 1;
1017
+ this.#text.layout(v2);
1018
+ this.#moveText(v2);
1019
+ this.#text.maxW = opts.w ?? this.#button.wh.w;
1020
+ this.#text.z = opts.text?.z ?? layerOffset(buttonZ, -1);
1021
+ this.#toggle = opts.toggle ?? false;
1022
+ }
1023
+ get selected() {
1024
+ return this.#selected.z !== Layer.Hidden;
1025
+ }
1026
+ free(v2) {
1027
+ this.#button.free(v2);
1028
+ this.#text.free(v2);
1029
+ v2.sprites.free(this.#selected.sprite, this.#pressed.sprite);
1030
+ }
1031
+ get on() {
1032
+ return this.#pressed.sprite.z !== Layer.Hidden;
1033
+ }
1034
+ // to-do: offStart() for pointer up listen? would need a boundary check too.
1035
+ get onStart() {
1036
+ return this.on && this.#started;
1037
+ }
1038
+ set text(str) {
1039
+ this.#text.text = str;
1040
+ }
1041
+ update(v2) {
1042
+ let invalid = this.#invalid;
1043
+ if (this.#button.update()) invalid = true;
1044
+ if (this.#text.update(v2)) invalid = true;
1045
+ const hitsCursor = !v2.input.handled && !!v2.zoo.cursor?.hits(v2, this.#selected.sprite, "UI");
1046
+ const clickStarted = hitsCursor && v2.input.isOnStart("Click") || v2.zoo.cursor?.keyboard && v2.input.isOnStart("A");
1047
+ const on = clickStarted ? this.#toggle ? !this.on : true : this.#toggle ? this.on : v2.input.isOn("Click") || v2.zoo.cursor?.keyboard && v2.input.isOn("A");
1048
+ this.#started = this.on !== on;
1049
+ if (this.#started) {
1050
+ this.#pressed.sprite.z = on ? this.#pressed.z : Layer.Hidden;
1051
+ invalid = true;
1052
+ }
1053
+ if (hitsCursor && (v2.input.point?.click || v2.input.point?.type === "Mouse")) {
1054
+ invalid ||= this.#selected.sprite.z !== this.#selected.z;
1055
+ this.#selected.sprite.z = this.#selected.z;
1056
+ } else {
1057
+ invalid ||= this.#selected.z !== Layer.Hidden;
1058
+ this.#selected.sprite.z = Layer.Hidden;
1059
+ }
1060
+ v2.input.handled ||= hitsCursor;
1061
+ this.#invalid = false;
1062
+ return invalid;
1063
+ }
1064
+ setXY(v2, xy) {
1065
+ if (xyEq(xy, this.#xy)) return;
1066
+ this.#xy.x = xy.x;
1067
+ this.#xy.y = xy.y;
1068
+ this.#button.xy = xy;
1069
+ this.#moveText(v2);
1070
+ this.#pressed.sprite.xy = xy;
1071
+ this.#selected.sprite.xy = xy;
1072
+ this.#invalid = true;
1073
+ }
1074
+ #moveText(v2) {
1075
+ this.#text.layout(v2);
1076
+ this.#text.xy = {
1077
+ x: this.#button.xy.x + this.#button.wh.w / 2 - this.#text.wh.w / 2,
1078
+ y: this.#button.xy.y + this.#button.wh.h / 2 - (this.#text.wh.h - this.#text.scaledLeading) / 2
1079
+ };
1080
+ }
1081
+ };
1082
+
1083
+ // src/ents/cursor-ent.ts
1084
+ var CursorEnt = class {
1085
+ keyboard = false;
1086
+ #sprite;
1087
+ constructor(v2, tag) {
1088
+ this.#sprite = v2.sprites.alloc();
1089
+ this.#sprite.tag = tag;
1090
+ this.#sprite.z = Layer.Hidden;
1091
+ }
1092
+ free(v2) {
1093
+ v2.sprites.free(this.#sprite);
1094
+ }
1095
+ hitbox(v2, coords) {
1096
+ const lvl = coords === "Level";
1097
+ const hitbox = this.#sprite.hitbox;
1098
+ if (!hitbox) throw Error("cursor has no hitbox");
1099
+ return {
1100
+ x: (lvl ? v2.cam.x : 0) + hitbox.x,
1101
+ y: (lvl ? v2.cam.y : 0) + hitbox.y,
1102
+ w: hitbox.w,
1103
+ h: hitbox.h
1104
+ };
1105
+ }
1106
+ hits(v2, box, coords) {
1107
+ return this.visible && boxHits(this.hitbox(v2, coords), box);
1108
+ }
1109
+ update(v2) {
1110
+ if (v2.input.point?.invalid) {
1111
+ this.#sprite.xy = v2.input.point.local;
1112
+ this.#sprite.z = v2.input.point?.type === "Mouse" ? Layer.Top : Layer.Hidden;
1113
+ return true;
1114
+ }
1115
+ if (this.keyboard && v2.input.isAnyOn("L", "R", "U", "D")) {
1116
+ const epsilon = 1;
1117
+ if (v2.input.isOn("L")) this.#sprite.x -= epsilon;
1118
+ if (v2.input.isOn("R")) this.#sprite.x += epsilon;
1119
+ if (v2.input.isOn("U")) this.#sprite.y -= epsilon;
1120
+ if (v2.input.isOn("D")) this.#sprite.y += epsilon;
1121
+ this.#sprite.z = Layer.Top;
1122
+ return true;
1123
+ }
1124
+ }
1125
+ get visible() {
1126
+ return this.#sprite.z !== Layer.Hidden;
1127
+ }
1128
+ };
1129
+
1130
+ // src/ents/follow-cam-ent.ts
1131
+ var FollowCamEnt = class {
1132
+ #fill;
1133
+ #invalid = true;
1134
+ #margin = { w: 0, h: 0 };
1135
+ #modulo = { x: 0, y: 0 };
1136
+ #pivot;
1137
+ #sprite;
1138
+ constructor(v2, tag, pivot) {
1139
+ this.#sprite = v2.sprites.alloc();
1140
+ this.#sprite.tag = tag;
1141
+ this.#pivot = pivot;
1142
+ }
1143
+ get fill() {
1144
+ return this.#fill;
1145
+ }
1146
+ set fill(fill) {
1147
+ if (this.#fill === fill) return;
1148
+ this.#fill = fill;
1149
+ this.#invalid = true;
1150
+ }
1151
+ free(v2) {
1152
+ v2.sprites.free(this.#sprite);
1153
+ }
1154
+ get h() {
1155
+ return this.#sprite.h;
1156
+ }
1157
+ set h(h) {
1158
+ if (this.#sprite.h === h) return;
1159
+ this.#sprite.h = h;
1160
+ this.#invalid = true;
1161
+ }
1162
+ get margin() {
1163
+ return this.#margin;
1164
+ }
1165
+ set margin(margin) {
1166
+ if (whEq(margin, this.#margin)) return;
1167
+ whAssign(this.#margin, margin);
1168
+ this.#invalid = true;
1169
+ }
1170
+ get modulo() {
1171
+ return this.#modulo;
1172
+ }
1173
+ set modulo(modulo) {
1174
+ if (xyEq(modulo, this.#modulo)) return;
1175
+ xyAssign(this.#modulo, modulo);
1176
+ this.#invalid = true;
1177
+ }
1178
+ get pivot() {
1179
+ return this.#pivot;
1180
+ }
1181
+ set pivot(pivot) {
1182
+ if (this.#pivot === pivot) return;
1183
+ this.#pivot = pivot;
1184
+ this.#invalid = true;
1185
+ }
1186
+ update(v2) {
1187
+ if (!this.#invalid && !v2.cam.invalid) return;
1188
+ const follow = v2.cam.follow(
1189
+ { w: this.#sprite.w, h: this.#sprite.h },
1190
+ this.#sprite.z,
1191
+ this.#pivot,
1192
+ { fill: this.#fill, modulo: this.#modulo, margin: this.#margin }
1193
+ );
1194
+ this.#sprite.x = follow.x;
1195
+ this.#sprite.y = follow.y;
1196
+ this.#invalid = false;
1197
+ return true;
1198
+ }
1199
+ get w() {
1200
+ return this.#sprite.w;
1201
+ }
1202
+ set w(w) {
1203
+ if (this.#sprite.w === w) return;
1204
+ this.#sprite.w = w;
1205
+ this.#invalid = true;
1206
+ }
1207
+ get z() {
1208
+ return this.#sprite.z;
1209
+ }
1210
+ set z(z) {
1211
+ this.#sprite.z = z;
1212
+ }
1213
+ };
1214
+
1215
+ // src/ents/zoo.ts
1216
+ var Zoo = class {
1217
+ #cursor;
1218
+ #ents = /* @__PURE__ */ new Set();
1219
+ add(...ents) {
1220
+ for (const ent of ents) {
1221
+ this.#ents.add(ent);
1222
+ if (ent instanceof CursorEnt) this.#cursor = ent;
1223
+ }
1224
+ }
1225
+ clear() {
1226
+ this.#cursor = void 0;
1227
+ this.#ents.clear();
1228
+ }
1229
+ get cursor() {
1230
+ return this.#cursor;
1231
+ }
1232
+ remove(...ents) {
1233
+ for (const ent of ents) {
1234
+ this.#ents.delete(ent);
1235
+ if (ent === this.#cursor) this.#cursor = void 0;
1236
+ }
1237
+ }
1238
+ update(v2) {
1239
+ let invalid = false;
1240
+ for (const ent of this.#ents) if (ent.update?.(v2)) invalid = true;
1241
+ return invalid;
1242
+ }
1243
+ };
1244
+
1245
+ // src/graphics/atlas.ts
1246
+ var animCels = 16;
1247
+ var animMillis = 1e3;
1248
+ var celMillis = animMillis / animCels;
1249
+
1250
+ // src/graphics/atlas-parser.ts
1251
+ function parseAtlas(json) {
1252
+ return {
1253
+ anim: json.anim,
1254
+ celXYWH: parseCelXYWH(json),
1255
+ tags: Object.keys(json.anim)
1256
+ };
1257
+ }
1258
+ function parseCelXYWH(json) {
1259
+ const cels = [];
1260
+ let i = 0;
1261
+ for (const anim of Object.values(json.anim)) {
1262
+ cels.push(...parseXYWH(anim, json.celXY, i));
1263
+ i += anim.cels * 2;
1264
+ }
1265
+ return cels;
1266
+ }
1267
+ function parseXYWH(anim, celXY, i) {
1268
+ const xywh = [];
1269
+ for (let ii = 0; ii < animCels; ii++) {
1270
+ const iii = i + 2 * (ii % anim.cels);
1271
+ xywh.push(celXY[iii], celXY[iii + 1], anim.w, anim.h);
1272
+ }
1273
+ return xywh;
1274
+ }
1275
+
1276
+ // src/graphics/cam.ts
1277
+ var Cam = class {
1278
+ #h = 1;
1279
+ #invalid = true;
1280
+ #minScale = 1;
1281
+ #minWH = { w: Infinity, h: Infinity };
1282
+ #mode = "Int";
1283
+ #scale = 1;
1284
+ #w = 1;
1285
+ #whClient = { w: 1, h: 1 };
1286
+ #x = 0;
1287
+ #y = 0;
1288
+ #zoomOut = 0;
1289
+ center(xy) {
1290
+ this.x = Math.floor(xy.x - this.w / 2);
1291
+ this.y = Math.floor(xy.y - this.h / 2);
1292
+ }
1293
+ /** position in fractional level coordinates. */
1294
+ clientToXY(client) {
1295
+ const local = this.clientToXYLocal(client);
1296
+ return { x: this.#x + local.x, y: this.#y + local.y };
1297
+ }
1298
+ /**
1299
+ * position relative canvas top-left in level scale (like level xy but no cam
1300
+ * offset). often used for UI that is fixed within the cam.
1301
+ */
1302
+ clientToXYLocal(client) {
1303
+ return {
1304
+ x: client.x / this.#whClient.w * this.#w,
1305
+ y: client.y / this.#whClient.h * this.#h
1306
+ };
1307
+ }
1308
+ follow(wh, z, pivot, opts) {
1309
+ const marginW = opts?.margin?.w ?? 0;
1310
+ let x = z > Layer.UIG ? Math.trunc(this.x) : 0;
1311
+ switch (pivot) {
1312
+ case "SW":
1313
+ case "W":
1314
+ case "NW":
1315
+ x += marginW;
1316
+ break;
1317
+ case "SE":
1318
+ case "E":
1319
+ case "NE":
1320
+ x += this.w - (wh.w + marginW);
1321
+ break;
1322
+ case "N":
1323
+ case "S":
1324
+ case "Origin":
1325
+ x += Math.trunc(this.w / 2) - Math.trunc(wh.w / 2);
1326
+ break;
1327
+ }
1328
+ x -= x % ((opts?.modulo?.x ?? x) || 1);
1329
+ const marginH = opts?.margin?.h ?? 0;
1330
+ let y = z > Layer.UIG ? Math.trunc(this.y) : 0;
1331
+ switch (pivot) {
1332
+ case "N":
1333
+ case "NE":
1334
+ case "NW":
1335
+ y += marginH;
1336
+ break;
1337
+ case "SE":
1338
+ case "S":
1339
+ case "SW":
1340
+ y += this.h - (wh.h + marginH);
1341
+ break;
1342
+ case "E":
1343
+ case "W":
1344
+ case "Origin":
1345
+ y += Math.trunc(this.h / 2) - Math.trunc(wh.h / 2);
1346
+ break;
1347
+ }
1348
+ y -= y % ((opts?.modulo?.y ?? y) || 1);
1349
+ const w = opts?.fill === "X" || opts?.fill === "XY" ? this.w - 2 * marginW : wh.w;
1350
+ const h = opts?.fill === "Y" || opts?.fill === "XY" ? this.h - 2 * marginH : wh.h;
1351
+ return { x, y, w, h };
1352
+ }
1353
+ /** positive int in level px. */
1354
+ get h() {
1355
+ return this.#h;
1356
+ }
1357
+ isVisible(box) {
1358
+ return boxHits(this, box);
1359
+ }
1360
+ /** true if cam moved or resized since last update. */
1361
+ get invalid() {
1362
+ return this.#invalid;
1363
+ }
1364
+ /** positive int or fraction depending on mode. */
1365
+ get minScale() {
1366
+ return this.#minScale;
1367
+ }
1368
+ set minScale(scale) {
1369
+ if (this.#scale === scale) return;
1370
+ this.#scale = scale;
1371
+ this.#invalidateWH();
1372
+ }
1373
+ /**
1374
+ * positive int or infinite min dimensions. set to
1375
+ * `{w: Infinity, h: Infinity}` to always use min scale.
1376
+ */
1377
+ get minWH() {
1378
+ return this.#minWH;
1379
+ }
1380
+ set minWH(wh) {
1381
+ if (this.#minWH.w === wh.w && this.#minWH.h === wh.h) return;
1382
+ this.#minWH.w = wh.w;
1383
+ this.#minWH.h = wh.h;
1384
+ this.#invalidateWH();
1385
+ }
1386
+ get mode() {
1387
+ return this.#mode;
1388
+ }
1389
+ set mode(mode) {
1390
+ if (this.#mode === mode) return;
1391
+ this.#mode = mode;
1392
+ this.#invalidateWH();
1393
+ }
1394
+ get portrait() {
1395
+ return this.h > this.w;
1396
+ }
1397
+ postupdate() {
1398
+ this.#invalid = false;
1399
+ }
1400
+ /** positive int or fraction depending on mode. */
1401
+ get scale() {
1402
+ return this.#scale;
1403
+ }
1404
+ toString() {
1405
+ return `Cam{(${this.x} ${this.y}) ${this.w}\xD7${this.h}}`;
1406
+ }
1407
+ /**
1408
+ * call after input processing but before ent processing. ents that move the
1409
+ * camera should be called immediately after update so that the invalid state
1410
+ * can be considered.
1411
+ */
1412
+ update(canvas) {
1413
+ if (!canvas.parentElement) throw Error("canvas has no parent");
1414
+ const { clientWidth, clientHeight } = canvas.parentElement;
1415
+ this.#invalid ||= this.#whClient.w !== clientWidth || this.#whClient.h !== clientHeight;
1416
+ if (!this.#invalid) return;
1417
+ this.#whClient.w = clientWidth;
1418
+ this.#whClient.h = clientHeight;
1419
+ this.#invalidateWH();
1420
+ canvas.width = this.#w;
1421
+ canvas.height = this.#h;
1422
+ canvas.style.width = `${this.#w * this.#scale / devicePixelRatio}px`;
1423
+ canvas.style.height = `${this.#h * this.#scale / devicePixelRatio}px`;
1424
+ }
1425
+ /** positive int in level px. */
1426
+ get w() {
1427
+ return this.#w;
1428
+ }
1429
+ /**
1430
+ * positive int dimensions in client px of canvas (often
1431
+ * `canvas.parentElement.clientWidth/Height` since the canvas is resized)
1432
+ * which is assumed to be max WH.
1433
+ */
1434
+ get whClient() {
1435
+ return this.#whClient;
1436
+ }
1437
+ /** fractional. */
1438
+ get x() {
1439
+ return this.#x;
1440
+ }
1441
+ set x(x) {
1442
+ this.#invalid ||= this.x !== x;
1443
+ this.#x = x;
1444
+ }
1445
+ /** fractional. */
1446
+ get y() {
1447
+ return this.#y;
1448
+ }
1449
+ set y(y) {
1450
+ this.#invalid ||= this.y !== y;
1451
+ this.#y = y;
1452
+ }
1453
+ /** nonnegative int or fraction depending on mode. */
1454
+ get zoomOut() {
1455
+ return this.#zoomOut;
1456
+ }
1457
+ set zoomOut(out) {
1458
+ out = Math.max(0, out);
1459
+ if (this.#zoomOut === out) return;
1460
+ this.#zoomOut = out;
1461
+ this.#invalidateWH();
1462
+ }
1463
+ #invalidateWH() {
1464
+ this.#invalid = true;
1465
+ const phy = {
1466
+ w: this.#whClient.w * devicePixelRatio,
1467
+ h: this.#whClient.h * devicePixelRatio
1468
+ };
1469
+ const scale = Math.max(
1470
+ this.#minScale,
1471
+ Math.min(phy.w / this.#minWH.w, phy.h / this.#minWH.h) - (this.#mode === "Int" ? Math.trunc(this.#zoomOut) : this.#zoomOut)
1472
+ );
1473
+ this.#scale = this.#mode === "Int" ? Math.trunc(scale) : scale;
1474
+ this.#w = Math.ceil(phy.w / this.#scale);
1475
+ this.#h = Math.ceil(phy.h / this.#scale);
1476
+ }
1477
+ };
1478
+
1479
+ // src/utils/math.ts
1480
+ function mod(dividend, divisor) {
1481
+ return (dividend % divisor + divisor) % divisor;
1482
+ }
1483
+
1484
+ // src/graphics/sprite.ts
1485
+ var drawableBytes = 12;
1486
+ var drawableEpsilon = 1 / 64;
1487
+ var drawableMaxWH = { w: 4095, h: 4095 };
1488
+ var Drawable = class {
1489
+ i;
1490
+ #pool;
1491
+ constructor(pool, i) {
1492
+ this.#pool = pool;
1493
+ this.i = i;
1494
+ }
1495
+ above(draw) {
1496
+ const compare = this.z === draw.z ? (draw.zend ? draw.y + draw.h : draw.y) - (this.zend ? this.y + this.h : this.y) : this.z - draw.z;
1497
+ return compare < 0;
1498
+ }
1499
+ get cel() {
1500
+ const iiic_cccc = this.#pool.view.getUint8(this.i + 10);
1501
+ return iiic_cccc & 31;
1502
+ }
1503
+ /**
1504
+ * [0, 31]. rendered cel offset. call reset() to play animation from start.
1505
+ */
1506
+ set cel(cel) {
1507
+ const iiic_cccc = this.#pool.view.getUint8(this.i + 10);
1508
+ this.#pool.view.setUint8(this.i + 10, iiic_cccc & ~31 | cel & 31);
1509
+ }
1510
+ /** test if render area overlaps box or sprite render area. */
1511
+ clips(box) {
1512
+ return boxHits(this, box);
1513
+ }
1514
+ get flipX() {
1515
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1516
+ return !!(sxyz_llll & 64);
1517
+ }
1518
+ set flipX(flip) {
1519
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1520
+ this.#pool.view.setUint8(this.i + 6, sxyz_llll & ~64 | -flip & 64);
1521
+ }
1522
+ get flipY() {
1523
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1524
+ return !!(sxyz_llll & 32);
1525
+ }
1526
+ set flipY(flip) {
1527
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1528
+ this.#pool.view.setUint8(this.i + 6, sxyz_llll & ~32 | -flip & 32);
1529
+ }
1530
+ get h() {
1531
+ const h12_wwww = this.#pool.view.getUint16(this.i + 8, true);
1532
+ return h12_wwww >>> 4;
1533
+ }
1534
+ /** [0, 4095]. */
1535
+ set h(h) {
1536
+ const h12_wwww = this.#pool.view.getUint16(this.i + 8, true);
1537
+ this.#pool.view.setUint16(
1538
+ this.i + 8,
1539
+ h12_wwww & ~(4095 << 4) | (h & 4095) << 4,
1540
+ true
1541
+ );
1542
+ }
1543
+ get id() {
1544
+ const i11_c5 = this.#pool.view.getUint16(this.i + 10, true);
1545
+ return i11_c5 >>> 5 & 2047;
1546
+ }
1547
+ /** [0, 2047]. */
1548
+ set id(id) {
1549
+ const i11_c5 = this.#pool.view.getUint16(this.i + 10, true);
1550
+ this.#pool.view.setUint16(
1551
+ this.i + 10,
1552
+ i11_c5 & ~(2047 << 5) | (id & 2047) << 5,
1553
+ true
1554
+ );
1555
+ }
1556
+ get stretch() {
1557
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1558
+ return !!(sxyz_llll & 128);
1559
+ }
1560
+ /** wrap texture (default) or stretch to width and height. */
1561
+ set stretch(stretch) {
1562
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1563
+ this.#pool.view.setUint8(
1564
+ this.i + 6,
1565
+ sxyz_llll & ~128 | -stretch & 128
1566
+ );
1567
+ }
1568
+ get w() {
1569
+ const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true);
1570
+ return hhhh_w12 & 4095;
1571
+ }
1572
+ /** [0, 4095]. */
1573
+ set w(w) {
1574
+ const hhhh_w12 = this.#pool.view.getUint16(this.i + 7, true);
1575
+ this.#pool.view.setUint16(
1576
+ this.i + 7,
1577
+ hhhh_w12 & ~4095 | w & 4095,
1578
+ true
1579
+ );
1580
+ }
1581
+ get x() {
1582
+ const y8_x24 = this.#pool.view.getUint32(this.i + 0, true);
1583
+ return (y8_x24 << 8 >> 8) / 64;
1584
+ }
1585
+ /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */
1586
+ set x(x) {
1587
+ const y8_x24 = this.#pool.view.getUint32(this.i + 0, true);
1588
+ this.#pool.view.setUint32(
1589
+ this.i + 0,
1590
+ y8_x24 & ~16777215 | x * 64 & 16777215,
1591
+ true
1592
+ );
1593
+ }
1594
+ get xy() {
1595
+ return { x: this.x, y: this.y };
1596
+ }
1597
+ set xy(xy) {
1598
+ this.x = xy.x;
1599
+ this.y = xy.y;
1600
+ }
1601
+ get y() {
1602
+ const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true);
1603
+ return (sxyz_llll_y24 << 8 >> 8) / 64;
1604
+ }
1605
+ /** [-131072, 131071.984375] with 1/64th (0.015625) granularity. */
1606
+ set y(y) {
1607
+ const sxyz_llll_y24 = this.#pool.view.getUint32(this.i + 3, true);
1608
+ this.#pool.view.setUint32(
1609
+ this.i + 3,
1610
+ sxyz_llll_y24 & ~16777215 | y * 64 & 16777215,
1611
+ true
1612
+ );
1613
+ }
1614
+ get z() {
1615
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1616
+ return sxyz_llll & 15;
1617
+ }
1618
+ /** layer [0 (closest), 14 (furthest)]; 15 is hidden. */
1619
+ set z(z) {
1620
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1621
+ this.#pool.view.setUint8(this.i + 6, sxyz_llll & ~15 | z & 15);
1622
+ }
1623
+ get zend() {
1624
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1625
+ return !!(sxyz_llll & 16);
1626
+ }
1627
+ /** z-order by top (default) or bottom of box. */
1628
+ set zend(end) {
1629
+ const sxyz_llll = this.#pool.view.getUint8(this.i + 6);
1630
+ this.#pool.view.setUint8(this.i + 6, sxyz_llll & ~16 | -end & 16);
1631
+ }
1632
+ };
1633
+ var Sprite = class _Sprite extends Drawable {
1634
+ #atlas;
1635
+ #framer;
1636
+ #hitbox;
1637
+ #hurtbox;
1638
+ constructor(pool, i, atlas, framer) {
1639
+ super(pool, i);
1640
+ this.#atlas = atlas;
1641
+ this.#framer = framer;
1642
+ }
1643
+ get anim() {
1644
+ return this.#atlas.anim[this.tag];
1645
+ }
1646
+ get flipX() {
1647
+ return super.flipX;
1648
+ }
1649
+ set flipX(flip) {
1650
+ if (this.flipX === flip) return;
1651
+ super.flipX = flip;
1652
+ this.#hitbox = void 0;
1653
+ this.#hurtbox = void 0;
1654
+ }
1655
+ get flipY() {
1656
+ return super.flipY;
1657
+ }
1658
+ set flipY(flip) {
1659
+ if (this.flipY === flip) return;
1660
+ super.flipY = flip;
1661
+ this.#hitbox = void 0;
1662
+ this.#hurtbox = void 0;
1663
+ }
1664
+ get h() {
1665
+ return super.h;
1666
+ }
1667
+ set h(h) {
1668
+ if (this.h === h) return;
1669
+ super.h = h;
1670
+ this.#hitbox = void 0;
1671
+ this.#hurtbox = void 0;
1672
+ }
1673
+ get hitbox() {
1674
+ if (this.#hitbox) return this.#hitbox;
1675
+ const { hitbox } = this.anim;
1676
+ if (!hitbox) return;
1677
+ return this.#hitbox ??= {
1678
+ x: this.x + (this.flipX ? this.w - hitbox.w - hitbox.x : hitbox.x),
1679
+ y: this.y + (this.flipY ? this.h - hitbox.h - hitbox.y : hitbox.y),
1680
+ w: hitbox.w,
1681
+ h: hitbox.h
1682
+ };
1683
+ }
1684
+ hits(box) {
1685
+ const hitbox = this.hitbox;
1686
+ if (!hitbox) return false;
1687
+ const hurtbox = box instanceof _Sprite ? box.hurtbox : box;
1688
+ return !!hurtbox && boxHits(hitbox, hurtbox);
1689
+ }
1690
+ get hurtbox() {
1691
+ if (this.#hurtbox) return this.#hurtbox;
1692
+ const { hurtbox } = this.anim;
1693
+ if (!hurtbox) return;
1694
+ return this.#hurtbox ??= {
1695
+ x: this.x + (this.flipX ? this.w - hurtbox.w - hurtbox.x : hurtbox.x),
1696
+ y: this.y + (this.flipY ? this.h - hurtbox.h - hurtbox.y : hurtbox.y),
1697
+ w: hurtbox.w,
1698
+ h: hurtbox.h
1699
+ };
1700
+ }
1701
+ get id() {
1702
+ return super.id;
1703
+ }
1704
+ set id(id) {
1705
+ if (this.id === id) return;
1706
+ super.id = id;
1707
+ this.#hitbox = void 0;
1708
+ this.#hurtbox = void 0;
1709
+ }
1710
+ /** true if animation has played once. */
1711
+ get looped() {
1712
+ return mod(this.#currentCel - this.cel, animCels * 2) >= this.anim.cels;
1713
+ }
1714
+ /** sets cel to animation start. */
1715
+ reset() {
1716
+ this.cel = this.#currentCel;
1717
+ }
1718
+ // to-do: unit test and catch up on unit tests elsewhere.
1719
+ get tag() {
1720
+ return this.#atlas.tags[this.id];
1721
+ }
1722
+ /** sets animation, resets cel, dimensions, hitbox, and hurtbox. */
1723
+ set tag(tag) {
1724
+ const anim = this.#atlas.anim[tag];
1725
+ this.w = anim.w;
1726
+ this.h = anim.h;
1727
+ this.id = anim.id;
1728
+ this.reset();
1729
+ }
1730
+ toString() {
1731
+ return `Sprite{${this.tag} (${this.x} ${this.y} ${this.z}) ${this.w}\xD7${this.h}}`;
1732
+ }
1733
+ get w() {
1734
+ return super.w;
1735
+ }
1736
+ set w(w) {
1737
+ if (this.w === w) return;
1738
+ super.w = w;
1739
+ this.#hitbox = void 0;
1740
+ this.#hurtbox = void 0;
1741
+ }
1742
+ get x() {
1743
+ return super.x;
1744
+ }
1745
+ set x(x) {
1746
+ if (this.x === x) return;
1747
+ super.x = x;
1748
+ this.#hitbox = void 0;
1749
+ this.#hurtbox = void 0;
1750
+ }
1751
+ get y() {
1752
+ return super.y;
1753
+ }
1754
+ set y(y) {
1755
+ if (this.y === y) return;
1756
+ super.y = y;
1757
+ this.#hitbox = void 0;
1758
+ this.#hurtbox = void 0;
1759
+ }
1760
+ /** current fractional cel in [0, 2 * anim.cels). */
1761
+ get #currentCel() {
1762
+ const cel = this.#framer.age / celMillis;
1763
+ return cel % (this.anim.cels * 2);
1764
+ }
1765
+ };
1766
+
1767
+ // src/input/context-menu.ts
1768
+ var ContextMenu = class {
1769
+ enable = false;
1770
+ #target;
1771
+ constructor(target) {
1772
+ this.#target = target;
1773
+ }
1774
+ register(op) {
1775
+ const fn = this.#target[`${op}EventListener`].bind(this.#target);
1776
+ fn("contextmenu", this.#onContextMenu);
1777
+ fn("touchstart", this.#onContextMenu, { passive: false });
1778
+ return this;
1779
+ }
1780
+ [Symbol.dispose]() {
1781
+ this.register("remove");
1782
+ }
1783
+ #onContextMenu = (ev) => {
1784
+ if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return;
1785
+ if (!this.enable) ev.preventDefault();
1786
+ };
1787
+ };
1788
+
1789
+ // src/input/gamepad.ts
1790
+ var Gamepad = class {
1791
+ bits = 0;
1792
+ // to-do: support analog button values, expose connected status and vibration,
1793
+ // and distinct devices. would be nice if vibration could merge with
1794
+ // navigator.vibrate().
1795
+ bitByAxis = {};
1796
+ bitByButton = {};
1797
+ onEvent = () => {
1798
+ };
1799
+ #target;
1800
+ constructor(target) {
1801
+ this.#target = target;
1802
+ }
1803
+ get connected() {
1804
+ return isSecureContext && navigator.getGamepads().filter(Boolean).length > 0;
1805
+ }
1806
+ register(op) {
1807
+ const fn = this.#target[`${op}EventListener`].bind(this.#target);
1808
+ fn("gamepadconnected", this.onEvent);
1809
+ fn("gamepaddisconnected", this.onEvent);
1810
+ return this;
1811
+ }
1812
+ reset() {
1813
+ this.bits = 0;
1814
+ }
1815
+ [Symbol.dispose]() {
1816
+ this.register("remove");
1817
+ }
1818
+ update() {
1819
+ if (!isSecureContext) return;
1820
+ for (const pad of navigator.getGamepads()) {
1821
+ for (const [index, axis] of pad?.axes.entries() ?? []) {
1822
+ const lessMore = this.bitByAxis[index];
1823
+ if (!lessMore) continue;
1824
+ const bit = axis < 0 ? lessMore[0] : axis === 0 ? 0 : lessMore[1];
1825
+ this.bits |= Math.abs(axis) >= 0.5 ? bit : 0;
1826
+ }
1827
+ for (const [index, btn] of pad?.buttons.entries() ?? []) {
1828
+ const bit = this.bitByButton[index];
1829
+ if (bit == null) continue;
1830
+ this.bits |= btn.pressed ? bit : 0;
1831
+ }
1832
+ }
1833
+ }
1834
+ };
1835
+
1836
+ // src/input/keyboard.ts
1837
+ var Keyboard = class {
1838
+ /** KeyboardEvent.code to bit. */
1839
+ bitByCode = {};
1840
+ invalid = false;
1841
+ /** KeyboardEvent.code to state. Multiple keys may map to the same bit. */
1842
+ onEvent = () => {
1843
+ };
1844
+ #on = {};
1845
+ #target;
1846
+ constructor(target) {
1847
+ this.#target = target;
1848
+ }
1849
+ get bits() {
1850
+ let bits = 0;
1851
+ for (const k in this.bitByCode) bits |= this.#on[k] ? this.bitByCode[k] : 0;
1852
+ return bits;
1853
+ }
1854
+ postupdate() {
1855
+ this.invalid = false;
1856
+ }
1857
+ register(op) {
1858
+ const fn = this.#target[`${op}EventListener`].bind(this.#target);
1859
+ for (const ev of ["keydown", "keyup"]) fn(ev, this.#onKey);
1860
+ return this;
1861
+ }
1862
+ reset() {
1863
+ this.invalid = false;
1864
+ this.#on = {};
1865
+ }
1866
+ [Symbol.dispose]() {
1867
+ this.register("remove");
1868
+ }
1869
+ #onKey = (ev) => {
1870
+ if (!ev.isTrusted || this.bitByCode[ev.code] == null) return;
1871
+ if (ev.type === "keydown" && (ev.metaKey || ev.altKey || ev.ctrlKey)) return;
1872
+ this.invalid = true;
1873
+ this.#on[ev.code] = ev.type === "keydown";
1874
+ ev.preventDefault();
1875
+ this.onEvent();
1876
+ };
1877
+ };
1878
+
1879
+ // src/input/pointer.ts
1880
+ var pointTypeByPointerType = {
1881
+ mouse: "Mouse",
1882
+ pen: "Pen",
1883
+ touch: "Touch"
1884
+ };
1885
+ var pointEvents = [
1886
+ "pointercancel",
1887
+ "pointerdown",
1888
+ "pointermove",
1889
+ "pointerup"
1890
+ ];
1891
+ var Pointer = class {
1892
+ bitByButton = {};
1893
+ dragMinClient = 5;
1894
+ invalid = false;
1895
+ onEvent = () => {
1896
+ };
1897
+ /** primary may be on or off. */
1898
+ primary;
1899
+ /**
1900
+ * secondaries are deleted when buttons are off. secondaries are only present
1901
+ * when primary is defined.
1902
+ */
1903
+ secondary = {};
1904
+ /** nonnegative. */
1905
+ #pinchStartClient;
1906
+ #target;
1907
+ constructor(target) {
1908
+ this.#target = target;
1909
+ }
1910
+ get boundsClient() {
1911
+ if (!this.primary?.bits && !Object.keys(this.secondary).length) return;
1912
+ let min = { x: Infinity, y: Infinity };
1913
+ let max = { x: -Infinity, y: -Infinity };
1914
+ for (const pt of [this.primary, ...Object.values(this.secondary)]) {
1915
+ if (!pt?.bits) continue;
1916
+ min = xyMin(min, pt.xyClient);
1917
+ max = xyMax(max, pt.xyClient);
1918
+ }
1919
+ return { x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y };
1920
+ }
1921
+ get centerClient() {
1922
+ const bounds = this.boundsClient;
1923
+ if (!bounds) return this.primary?.xyClient;
1924
+ return xyAdd(bounds, { x: bounds.w / 2, y: bounds.h / 2 });
1925
+ }
1926
+ get locked() {
1927
+ return this.#target.ownerDocument.pointerLockElement === this.#target;
1928
+ }
1929
+ get pinchClient() {
1930
+ if (!this.#pinchStartClient) return;
1931
+ const end = this.#newPinchClient;
1932
+ return end ? xySub(end, this.#pinchStartClient) : void 0;
1933
+ }
1934
+ postupdate() {
1935
+ this.invalid = false;
1936
+ }
1937
+ register(op) {
1938
+ const fn = this.#target[`${op}EventListener`].bind(this.#target);
1939
+ for (const ev of pointEvents) fn(ev, this.#onInput);
1940
+ return this;
1941
+ }
1942
+ reset() {
1943
+ this.invalid = false;
1944
+ this.primary = void 0;
1945
+ for (const pt in this.secondary) delete this.secondary[pt];
1946
+ this.#pinchStartClient = void 0;
1947
+ }
1948
+ update() {
1949
+ const on = (this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length;
1950
+ if (on < 2 || !this.#pinchStartClient)
1951
+ this.#pinchStartClient = this.#newPinchClient;
1952
+ }
1953
+ [Symbol.dispose]() {
1954
+ this.register("remove");
1955
+ }
1956
+ #evButtonsToBits(btns) {
1957
+ let bits = 0;
1958
+ for (let btn = 1; btn <= btns; btn <<= 1)
1959
+ if ((btn & btns) === btn) bits |= this.bitByButton[btn] ?? 0;
1960
+ return bits;
1961
+ }
1962
+ #onInput = (ev) => {
1963
+ if (!ev.isTrusted) return;
1964
+ this.invalid = true;
1965
+ const bits = ev.metaKey || ev.altKey || ev.ctrlKey ? 0 : this.#evButtonsToBits(ev.buttons);
1966
+ if (bits) ev.preventDefault();
1967
+ const locked = this.locked;
1968
+ if (ev.type === "pointerdown" && !locked)
1969
+ try {
1970
+ this.#target.setPointerCapture(ev.pointerId);
1971
+ } catch {
1972
+ }
1973
+ const prevPt = ev.isPrimary ? this.primary : this.secondary[ev.pointerId];
1974
+ let xyClient;
1975
+ if (locked) {
1976
+ const scale = 1 / devicePixelRatio;
1977
+ xyClient = {
1978
+ x: Math.min(
1979
+ Math.max(
1980
+ 0,
1981
+ (prevPt?.xyClient.x ?? ev.offsetX) + ev.movementX * scale
1982
+ ),
1983
+ this.#target.clientWidth
1984
+ ),
1985
+ y: Math.min(
1986
+ Math.max(
1987
+ 0,
1988
+ (prevPt?.xyClient.y ?? ev.offsetY) + ev.movementY * scale
1989
+ ),
1990
+ this.#target.clientHeight
1991
+ )
1992
+ };
1993
+ } else xyClient = { x: ev.offsetX, y: ev.offsetY };
1994
+ const evType = ev.type;
1995
+ const type = pointTypeByPointerType[ev.pointerType];
1996
+ let clickClient;
1997
+ if (ev.type === "pointerdown") clickClient = { x: xyClient.x, y: xyClient.y };
1998
+ else if (ev.type === "pointermove") clickClient = prevPt?.clickClient;
1999
+ const drag = !!bits && (prevPt?.drag || !!clickClient && xyDistance(clickClient, xyClient) >= this.dragMinClient);
2000
+ const pt = {
2001
+ clickClient,
2002
+ bits,
2003
+ drag,
2004
+ ev: evType,
2005
+ id: ev.pointerId,
2006
+ primary: ev.isPrimary,
2007
+ type,
2008
+ xyClient
2009
+ };
2010
+ if (ev.isPrimary) this.primary = pt;
2011
+ else if (!bits) delete this.secondary[ev.pointerId];
2012
+ else this.secondary[ev.pointerId] = pt;
2013
+ this.onEvent();
2014
+ };
2015
+ get #newPinchClient() {
2016
+ if ((this.primary?.bits ? 1 : 0) + Object.values(this.secondary).length < 2)
2017
+ return;
2018
+ const bounds = this.boundsClient;
2019
+ return bounds ? { x: bounds.w, y: bounds.h } : void 0;
2020
+ }
2021
+ };
2022
+
2023
+ // src/input/wheel.ts
2024
+ var Wheel = class {
2025
+ deltaClient;
2026
+ onEvent = () => {
2027
+ };
2028
+ #target;
2029
+ constructor(target) {
2030
+ this.#target = target;
2031
+ }
2032
+ postupdate() {
2033
+ this.deltaClient = void 0;
2034
+ }
2035
+ register(op) {
2036
+ const fn = this.#target[`${op}EventListener`].bind(this.#target);
2037
+ fn("wheel", this.#onInput, { passive: true });
2038
+ return this;
2039
+ }
2040
+ reset() {
2041
+ this.deltaClient = void 0;
2042
+ }
2043
+ [Symbol.dispose]() {
2044
+ this.register("remove");
2045
+ }
2046
+ #onInput = (ev) => {
2047
+ if (!ev.isTrusted || ev.metaKey || ev.altKey || ev.ctrlKey) return;
2048
+ this.deltaClient = { x: ev.deltaX, y: ev.deltaY, z: ev.deltaZ };
2049
+ this.onEvent();
2050
+ };
2051
+ };
2052
+
2053
+ // src/input/input.ts
2054
+ var Input = class {
2055
+ /** time allowed between combo inputs. */
2056
+ comboMaxIntervalMillis = 300;
2057
+ /**
2058
+ * true if any button, key, or click was _ever_ on. doesn't consider handled.
2059
+ */
2060
+ gestured = false;
2061
+ /** clear buttonish inputs for rest of frame. */
2062
+ handled = false;
2063
+ /** true if _any_ input has changed since previous update. */
2064
+ invalid = false;
2065
+ /**
2066
+ * minimum duration for an input to be considered held. durations are
2067
+ * calculated at frame boundaries, not on actual press. devices are treated
2068
+ * strictly as polled aggregates.
2069
+ */
2070
+ minHeldMillis = 300;
2071
+ #bitByButton = {};
2072
+ #buttonByBit = {};
2073
+ #bits = 0;
2074
+ #cam;
2075
+ /**
2076
+ * sequence of nonzero bits ordered from oldest to latest. combos end only by
2077
+ * expiration.
2078
+ */
2079
+ #combo = [];
2080
+ #contextMenu;
2081
+ #gamepad;
2082
+ /** time since buttons changed. */
2083
+ #heldMillis = 0;
2084
+ #keyboard;
2085
+ #pointer;
2086
+ #pointerState;
2087
+ /** bits last update. may not be equal to `#combo.at(-1)`. */
2088
+ #prevBits = 0;
2089
+ #wheel;
2090
+ #wheelState;
2091
+ constructor(cam, target) {
2092
+ this.#cam = cam;
2093
+ this.#contextMenu = new ContextMenu(target);
2094
+ this.#gamepad = new Gamepad(globalThis);
2095
+ this.#keyboard = new Keyboard(target.ownerDocument);
2096
+ this.#pointer = new Pointer(target);
2097
+ this.#wheel = new Wheel(target);
2098
+ }
2099
+ get anyOn() {
2100
+ return this.#bits !== 0;
2101
+ }
2102
+ /** for debugging. */
2103
+ get combo() {
2104
+ const chords = [];
2105
+ for (const bits of this.#combo) {
2106
+ const chord = [];
2107
+ for (let bit = 1; bit <= bits; bit <<= 1) {
2108
+ if ((bit & bits) === bit && this.#buttonByBit[bit])
2109
+ chord.push(this.#buttonByBit[bit]);
2110
+ }
2111
+ chord.sort();
2112
+ chords.push(chord);
2113
+ }
2114
+ return chords;
2115
+ }
2116
+ /**
2117
+ * enable when game is paused or in photo mode to allow right clicks and long
2118
+ * presses to save canvas.
2119
+ */
2120
+ get contextMenu() {
2121
+ return this.#contextMenu;
2122
+ }
2123
+ /** doesn't consider handled. gamepads must be polled. */
2124
+ get gamepad() {
2125
+ return this.#gamepad.connected ? {} : void 0;
2126
+ }
2127
+ /** true if bits hasn't changed for a while. */
2128
+ get held() {
2129
+ return !this.handled && this.#heldMillis >= this.minHeldMillis;
2130
+ }
2131
+ isAnyOn(...btns) {
2132
+ return !this.handled && !!(this.#bits & this.#mapBits(btns));
2133
+ }
2134
+ isAnyOnStart(...btns) {
2135
+ return this.started && this.isAnyOn(...btns);
2136
+ }
2137
+ /**
2138
+ * buttons are exact. eg, up won't match up AND down like `isOn('U')` will.
2139
+ * combo is exact too. `['A'], ['A']` will match `['A'], ['A']` but not
2140
+ * `['A'], ['A'], ['A']`.
2141
+ */
2142
+ isCombo(...combo) {
2143
+ return combo.length === this.#combo.length && this.isComboEndsWith(...combo);
2144
+ }
2145
+ /**
2146
+ * `['A'], ['A']` will match `['A'], ['A']` and `['B'], ['A'], ['A']`. eg,
2147
+ * double-clicks often don't care about any preceding buttons.
2148
+ */
2149
+ isComboEndsWith(...combo) {
2150
+ for (const [i, btns] of combo.entries()) {
2151
+ const bits = this.#mapBits(btns);
2152
+ if (this.#combo.at(-combo.length + i) !== bits) return false;
2153
+ }
2154
+ return !this.handled && (this.#combo.at(-1) === this.#bits || !this.#bits);
2155
+ }
2156
+ /** like isComboEndsWith() but test if the last button is triggered. */
2157
+ isComboEndsWithStart(...combo) {
2158
+ return this.isOnStart(...combo.at(-1)) && this.isComboEndsWith(...combo);
2159
+ }
2160
+ /** like isCombo() but test if the last button is triggered. */
2161
+ isComboStart(...combo) {
2162
+ return this.isOnStart(...combo.at(-1)) && this.isCombo(...combo);
2163
+ }
2164
+ /*:
2165
+ * true if any button in chord is not on. this is usually what's wanted. eg:
2166
+ * ```ts
2167
+ * if (isOn('A', 'B')) console.log('on')
2168
+ * if (isOff('A', 'B')) console.log('not A+B; A and/or B is off')
2169
+ * ```
2170
+ */
2171
+ isOff(...btns) {
2172
+ return !this.handled && !this.isOn(...btns);
2173
+ }
2174
+ isOffStart(...btns) {
2175
+ const bits = this.#mapBits(btns);
2176
+ const wasOn = (this.#prevBits & bits) === bits;
2177
+ return wasOn && this.started && this.isOff(...btns);
2178
+ }
2179
+ /**
2180
+ * true if all buttons are on inclusively. eg, `isOn('U')` is true when up is
2181
+ * pressed or when up and down are pressed.
2182
+ */
2183
+ isOn(...btns) {
2184
+ const bits = this.#mapBits(btns);
2185
+ return !this.handled && (this.#bits & bits) === bits;
2186
+ }
2187
+ isOnStart(...btns) {
2188
+ return this.started && this.isOn(...btns);
2189
+ }
2190
+ get key() {
2191
+ return { invalid: this.#keyboard.invalid };
2192
+ }
2193
+ mapDefault() {
2194
+ const input = this;
2195
+ input.mapKeyboardCode("L", "ArrowLeft");
2196
+ input.mapKeyboardCode("R", "ArrowRight");
2197
+ input.mapKeyboardCode("U", "ArrowUp");
2198
+ input.mapKeyboardCode("D", "ArrowDown");
2199
+ input.mapKeyboardCode("C", "KeyC");
2200
+ input.mapKeyboardCode("A", "KeyX");
2201
+ input.mapKeyboardCode("B", "KeyZ");
2202
+ input.mapKeyboardCode("Menu", "Enter");
2203
+ input.mapKeyboardCode("Back", "Escape");
2204
+ input.mapGamepadAxis("L", "R", 0, 2);
2205
+ input.mapGamepadAxis("U", "D", 1, 3);
2206
+ input.mapGamepadButton("L", 14);
2207
+ input.mapGamepadButton("R", 15);
2208
+ input.mapGamepadButton("U", 12);
2209
+ input.mapGamepadButton("D", 13);
2210
+ input.mapGamepadButton("C", 2);
2211
+ input.mapGamepadButton("B", 0);
2212
+ input.mapGamepadButton("A", 1);
2213
+ input.mapGamepadButton("Menu", 9);
2214
+ input.mapGamepadButton("Back", 8);
2215
+ input.mapPointerClick("Click", 1);
2216
+ input.mapPointerClick("Click2", 2);
2217
+ input.mapPointerClick("ClickMiddle", 4);
2218
+ return input;
2219
+ }
2220
+ // to-do: support analog values.
2221
+ mapGamepadAxis(less, more, ...axes) {
2222
+ for (const axis of axes) {
2223
+ this.#gamepad.bitByAxis[axis] = [
2224
+ this.#mapButton(less),
2225
+ this.#mapButton(more)
2226
+ ];
2227
+ }
2228
+ }
2229
+ mapGamepadButton(btn, ...indices) {
2230
+ for (const index of indices)
2231
+ this.#gamepad.bitByButton[index] = this.#mapButton(btn);
2232
+ }
2233
+ /** @arg codes union of KeyboardEvent.code. */
2234
+ mapKeyboardCode(btn, ...codes) {
2235
+ for (const code of codes)
2236
+ this.#keyboard.bitByCode[code] = this.#mapButton(btn);
2237
+ }
2238
+ mapPointerClick(btn, ...clicks) {
2239
+ for (const click of clicks)
2240
+ this.#pointer.bitByButton[click] = this.#mapButton(btn);
2241
+ }
2242
+ get on() {
2243
+ const on = [];
2244
+ for (const btn in this.#bitByButton) if (this.isOn(btn)) on.push(btn);
2245
+ return on.sort();
2246
+ }
2247
+ set onEvent(cb) {
2248
+ this.#gamepad.onEvent = cb;
2249
+ this.#keyboard.onEvent = cb;
2250
+ this.#pointer.onEvent = cb;
2251
+ this.#wheel.onEvent = cb;
2252
+ }
2253
+ /** doesn't consider handled. */
2254
+ get point() {
2255
+ return this.#pointerState;
2256
+ }
2257
+ get pointer() {
2258
+ return this.#pointer;
2259
+ }
2260
+ register(op) {
2261
+ globalThis[`${op}EventListener`]("blur", this.reset);
2262
+ this.#contextMenu.register(op);
2263
+ this.#gamepad.register(op);
2264
+ this.#keyboard.register(op);
2265
+ this.#pointer.register(op);
2266
+ this.#wheel.register(op);
2267
+ return this;
2268
+ }
2269
+ reset = () => {
2270
+ this.#bits = 0;
2271
+ this.#prevBits = 0;
2272
+ this.handled = false;
2273
+ this.#heldMillis = 0;
2274
+ this.#combo.length = 0;
2275
+ this.#gamepad.reset();
2276
+ this.#keyboard.reset();
2277
+ this.#pointer.reset();
2278
+ this.#pointerState = void 0;
2279
+ this.#wheel.reset();
2280
+ this.#wheelState = void 0;
2281
+ };
2282
+ /** true if bits has changed. */
2283
+ get started() {
2284
+ return !this.handled && this.#bits !== this.#prevBits;
2285
+ }
2286
+ /**
2287
+ * call on new frame before altering cam. dispatches always occur before an
2288
+ * update.
2289
+ * @arg millis duration since last update.
2290
+ */
2291
+ update(millis) {
2292
+ this.handled = false;
2293
+ this.#gamepad.update();
2294
+ this.#pointer.update();
2295
+ this.#prevBits = this.#bits;
2296
+ this.#bits = this.#gamepad.bits | this.#keyboard.bits | (this.#pointer.primary?.bits ?? 0);
2297
+ this.invalid = this.#bits !== this.#prevBits || this.#pointer.invalid || !!this.#wheel.deltaClient;
2298
+ this.gestured ||= !!this.#bits;
2299
+ if (millis > this.comboMaxIntervalMillis && this.#bits !== this.#prevBits || this.#heldMillis + millis > this.comboMaxIntervalMillis && !this.#bits)
2300
+ this.#combo.length = 0;
2301
+ if (this.#bits === this.#prevBits)
2302
+ this.#heldMillis = this.#heldMillis + millis;
2303
+ else this.#heldMillis = millis;
2304
+ if (this.#bits && this.#bits !== this.#prevBits) {
2305
+ if (this.#prevBits) this.#combo.length = 0;
2306
+ this.#combo.push(this.#bits);
2307
+ }
2308
+ if (this.#pointer.primary) {
2309
+ const pinchClient = this.#pointer.pinchClient;
2310
+ const dragOn = this.#pointer.primary.drag && !Object.values(this.#pointer.secondary).length;
2311
+ const secondary = [];
2312
+ for (const pt of Object.values(this.#pointer.secondary)) {
2313
+ secondary.push({
2314
+ type: pt.type,
2315
+ click: pt.clickClient ? {
2316
+ client: pt.clickClient,
2317
+ local: this.#cam.clientToXYLocal(pt.clickClient),
2318
+ ...this.#cam.clientToXY(pt.clickClient)
2319
+ } : void 0,
2320
+ ...this.#cam.clientToXY(pt.xyClient),
2321
+ client: pt.xyClient,
2322
+ local: this.#cam.clientToXYLocal(pt.xyClient)
2323
+ });
2324
+ }
2325
+ const centerClient = this.#pointer.centerClient;
2326
+ const center = {
2327
+ client: centerClient,
2328
+ local: this.#cam.clientToXYLocal(centerClient),
2329
+ ...this.#cam.clientToXY(centerClient)
2330
+ };
2331
+ this.#pointerState = {
2332
+ center,
2333
+ click: this.#pointer.primary.clickClient ? {
2334
+ client: this.#pointer.primary.clickClient,
2335
+ local: this.#cam.clientToXYLocal(
2336
+ this.#pointer.primary.clickClient
2337
+ ),
2338
+ ...this.#cam.clientToXY(this.#pointer.primary.clickClient)
2339
+ } : void 0,
2340
+ drag: {
2341
+ on: dragOn,
2342
+ start: !this.#pointerState?.drag.on && dragOn,
2343
+ end: !!this.#pointerState?.drag.on && !dragOn
2344
+ },
2345
+ invalid: this.#pointer.invalid,
2346
+ pinch: pinchClient ? { client: pinchClient, xy: this.#cam.clientToXY(pinchClient) } : void 0,
2347
+ secondary,
2348
+ type: this.#pointer.primary.type,
2349
+ ...this.#cam.clientToXY(this.#pointer.primary.xyClient),
2350
+ client: this.#pointer.primary.xyClient,
2351
+ local: this.#cam.clientToXYLocal(this.#pointer.primary.xyClient)
2352
+ };
2353
+ } else this.#pointerState = void 0;
2354
+ this.#wheelState = this.#wheel.deltaClient ? {
2355
+ delta: {
2356
+ client: this.#wheel.deltaClient,
2357
+ xy: this.#cam.clientToXY(this.#wheel.deltaClient)
2358
+ }
2359
+ } : void 0;
2360
+ this.#keyboard.postupdate();
2361
+ this.#pointer.postupdate();
2362
+ this.#wheel.postupdate();
2363
+ }
2364
+ [Symbol.dispose]() {
2365
+ this.register("remove");
2366
+ }
2367
+ /** doesn't consider handled. */
2368
+ get wheel() {
2369
+ return this.#wheelState;
2370
+ }
2371
+ /** get bits for buttons. */
2372
+ #mapBits(btns) {
2373
+ let bits = 0;
2374
+ for (const btn of btns) bits |= this.#bitByButton[btn] ?? 0;
2375
+ return bits;
2376
+ }
2377
+ /** assign button to bit. */
2378
+ #mapButton(btn) {
2379
+ const bit = this.#bitByButton[btn] ??= 1 << Object.keys(this.#bitByButton).length;
2380
+ this.#buttonByBit[bit] = btn;
2381
+ return bit;
2382
+ }
2383
+ };
2384
+
2385
+ // src/utils/debug.ts
2386
+ var debug = Debug(
2387
+ globalThis.location?.href
2388
+ );
2389
+ function Debug(url) {
2390
+ if (!url) return;
2391
+ const csv = [...new URL(url).searchParams].find(
2392
+ ([k]) => k.toLowerCase() === "debug"
2393
+ )?.[1];
2394
+ if (csv == null) return;
2395
+ const map = Object.fromEntries(
2396
+ csv.split(",").filter(Boolean).map((kv) => kv.split("="))
2397
+ // split each pair.
2398
+ );
2399
+ const target = {};
2400
+ for (const k in map) target[k.toLowerCase()] = map[k] || "true";
2401
+ const voidKeyset = {
2402
+ cam: void 0,
2403
+ input: void 0,
2404
+ mem: void 0,
2405
+ render: void 0
2406
+ };
2407
+ return new Proxy(target, {
2408
+ get(target2, k) {
2409
+ if (typeof k !== "string") return target2[k];
2410
+ k = k.toLowerCase();
2411
+ return !csv || "all" in map || k in voidKeyset && "void" in map ? target2[k] || "true" : target2[k];
2412
+ }
2413
+ });
2414
+ }
2415
+
2416
+ // src/mem/pool.ts
2417
+ var Pool = class {
2418
+ /** the next free block is always at size. */
2419
+ #blocks;
2420
+ #opts;
2421
+ #size = 0;
2422
+ #u8;
2423
+ #view;
2424
+ constructor(opts) {
2425
+ if (opts.allocBytes <= 0) throw Error("byte allocation must be > 0");
2426
+ if (opts.pageBlocks <= 0) throw Error("page blocks must be > 0");
2427
+ this.#opts = { ...opts, minPages: opts.minPages ?? 1 };
2428
+ const initSize = this.#opts.minPages * opts.pageBlocks;
2429
+ this.#blocks = new Array(initSize);
2430
+ this.#u8 = new Uint8Array();
2431
+ this.#resize(initSize, "Init");
2432
+ }
2433
+ alloc() {
2434
+ if (this.#size >= this.#currentCapacity)
2435
+ this.#resize(this.#currentCapacity + this.#opts.pageBlocks, "Call");
2436
+ const block = this.#blocks[this.#size];
2437
+ block.i = this.#size * this.#opts.allocBytes;
2438
+ this.#size++;
2439
+ return block;
2440
+ }
2441
+ clear() {
2442
+ this.#size = 0;
2443
+ const minCapacity = this.#opts.minPages * this.#opts.pageBlocks;
2444
+ if (this.#currentCapacity > minCapacity) this.#resize(minCapacity, "Call");
2445
+ }
2446
+ free(...blocks) {
2447
+ for (const block of blocks) this.#freeBlock(block);
2448
+ }
2449
+ get size() {
2450
+ return this.#size;
2451
+ }
2452
+ get view() {
2453
+ return this.#view;
2454
+ }
2455
+ toDebugString() {
2456
+ let str = "";
2457
+ for (let i = 0; i < this.#u8.buffer.byteLength; i++) {
2458
+ if (i && !(i % this.#opts.allocBytes)) str += " ";
2459
+ str += this.#u8[i].toString(16).padStart(2, "0");
2460
+ }
2461
+ return str;
2462
+ }
2463
+ get #currentCapacity() {
2464
+ return this.#u8.buffer.byteLength / this.#opts.allocBytes;
2465
+ }
2466
+ #freeBlock(block) {
2467
+ if (!this.#size) throw Error("pool underflow");
2468
+ this.#size--;
2469
+ const start = this.#size * this.#opts.allocBytes;
2470
+ this.#u8.copyWithin(block.i, start, start + this.#opts.allocBytes);
2471
+ this.#blocks[this.#size].i = block.i;
2472
+ [this.#blocks[block.i], this.#blocks[this.#size]] = [
2473
+ this.#blocks[this.#size],
2474
+ this.#blocks[block.i]
2475
+ ];
2476
+ const free = Math.floor(
2477
+ (this.#currentCapacity - this.#size) / this.#opts.pageBlocks
2478
+ );
2479
+ if (free && this.#currentCapacity / this.#opts.pageBlocks - free >= this.#opts.minPages)
2480
+ this.#resize(this.#currentCapacity - free * this.#opts.pageBlocks, "Call");
2481
+ }
2482
+ #resize(capacity, origin) {
2483
+ if (origin === "Call" && debug?.mem)
2484
+ console.debug(
2485
+ `[mem] ${capacity < this.#currentCapacity ? "shrinking" : "growing"} pool to ${capacity}`
2486
+ );
2487
+ this.#blocks.length = capacity;
2488
+ for (let i = this.#currentCapacity; i < capacity; i++)
2489
+ this.#blocks[i] = this.#opts.alloc(this);
2490
+ const buffer = new ArrayBuffer(capacity * this.#opts.allocBytes);
2491
+ const u8 = new Uint8Array(buffer);
2492
+ u8.set(this.#u8.subarray(0, capacity * this.#opts.allocBytes));
2493
+ this.#u8 = u8;
2494
+ this.#view = new DataView(buffer);
2495
+ }
2496
+ };
2497
+
2498
+ // src/utils/color-util.ts
2499
+ function rgbaHex(rgba) {
2500
+ return `#${rgba.toString(16).padStart(8, "0")}`;
2501
+ }
2502
+
2503
+ // src/utils/dom-util.ts
2504
+ function initMetaViewport() {
2505
+ if (document.querySelector('meta[name="viewport"]')) return;
2506
+ const meta = document.createElement("meta");
2507
+ meta.name = "viewport";
2508
+ meta.content = "width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no";
2509
+ document.head.appendChild(meta);
2510
+ }
2511
+ function initBody(canvas, rgba) {
2512
+ if (canvas.parentNode !== document.body) return;
2513
+ document.body.style.margin = "0";
2514
+ document.body.style.width = "100dvw";
2515
+ document.body.style.height = "100dvh";
2516
+ document.body.style.overflow = "hidden";
2517
+ document.body.style.background = rgbaHex(rgba);
2518
+ }
2519
+
2520
+ // src/utils/canvas-util.ts
2521
+ function initCanvas(canvas, mode) {
2522
+ canvas ??= document.createElement("canvas");
2523
+ canvas.width = 0;
2524
+ canvas.style.cursor = "none";
2525
+ canvas.style.display = "block";
2526
+ canvas.style.outline = "none";
2527
+ canvas.style.cursor = "none";
2528
+ if (mode === "Int") canvas.style.imageRendering = "pixelated";
2529
+ canvas.style.touchAction = "none";
2530
+ canvas.tabIndex = 0;
2531
+ canvas.focus();
2532
+ if (!canvas.parentNode) document.body.append(canvas);
2533
+ return canvas;
2534
+ }
2535
+
2536
+ // src/utils/fetch-util.ts
2537
+ async function loadImage(img) {
2538
+ const promise = new Promise((fulfil, reject) => {
2539
+ img.onload = () => fulfil(img);
2540
+ img.onerror = () => reject(Error(`image load error for ${img.src}`));
2541
+ });
2542
+ return img.complete ? img : await promise;
2543
+ }
2544
+
2545
+ // src/graphics/gl.ts
2546
+ function Shader(gl, vertGLSL, fragGLSL, textures) {
2547
+ const program = loadProgram(gl, vertGLSL, fragGLSL);
2548
+ gl.useProgram(program);
2549
+ return {
2550
+ buffer: gl.createBuffer(),
2551
+ program,
2552
+ textures,
2553
+ uniform: GLUniformMap(gl, program),
2554
+ vao: gl.createVertexArray()
2555
+ };
2556
+ }
2557
+ function GLUniformMap(gl, pgm) {
2558
+ const len = pgm ? gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS) : 0;
2559
+ const map = debug?.render ? new Proxy(
2560
+ {},
2561
+ {
2562
+ get(target, k) {
2563
+ if (target[k] == null) throw Error(`no shader uniform "${k}"`);
2564
+ return target[k];
2565
+ }
2566
+ }
2567
+ ) : {};
2568
+ for (let i = 0; i < len; ++i) {
2569
+ const uniform = gl.getActiveUniform(pgm, i);
2570
+ if (!uniform) throw Error(`no shader uniform at index ${i}`);
2571
+ const location = gl.getUniformLocation(pgm, uniform.name);
2572
+ if (!location) throw Error(`no shader uniform "${uniform.name}"`);
2573
+ const name = uniform.name.replace("[0]", "");
2574
+ map[name] = location;
2575
+ }
2576
+ return map;
2577
+ }
2578
+ function loadProgram(gl, vertGLSL, fragGLSL) {
2579
+ const pgm = gl.createProgram();
2580
+ if (!pgm) return null;
2581
+ const vert = compileShader(gl, "VERTEX_SHADER", vertGLSL);
2582
+ const frag = compileShader(gl, "FRAGMENT_SHADER", fragGLSL);
2583
+ if (!vert || !frag) return null;
2584
+ gl.attachShader(pgm, vert);
2585
+ gl.attachShader(pgm, frag);
2586
+ gl.linkProgram(pgm);
2587
+ if (debug?.render && !gl.getProgramParameter(pgm, gl.LINK_STATUS)) {
2588
+ const log = gl.getProgramInfoLog(pgm)?.slice(0, -1);
2589
+ throw Error(`shader link failure; ${log}`);
2590
+ }
2591
+ gl.detachShader(pgm, frag);
2592
+ gl.detachShader(pgm, vert);
2593
+ gl.deleteShader(frag);
2594
+ gl.deleteShader(vert);
2595
+ return pgm;
2596
+ }
2597
+ function compileShader(gl, type, glsl) {
2598
+ const shader = gl.createShader(gl[type]);
2599
+ if (!shader) return shader;
2600
+ gl.shaderSource(shader, glsl.trim());
2601
+ gl.compileShader(shader);
2602
+ if (debug?.render && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
2603
+ const log = gl.getShaderInfoLog(shader)?.slice(0, -1);
2604
+ throw Error(`shader compile failure; ${log}`);
2605
+ }
2606
+ return shader;
2607
+ }
2608
+
2609
+ // src/graphics/sprite-frag.glsl.ts
2610
+ var spriteFragGLSL = `#version 300 es
2611
+ #pragma debug(${debug?.render ? "on" : "off"})
2612
+ #pragma optimize(${debug?.render ? "off" : "on"})
2613
+
2614
+ precision highp int;
2615
+ precision highp float;
2616
+ precision highp usampler2D;
2617
+
2618
+ uniform sampler2D uTex;
2619
+ uniform uvec2 uTexWH;
2620
+
2621
+ flat in uint vStretch;
2622
+ flat in ivec4 vTexXYWH;
2623
+ flat in int vZ;
2624
+ in vec2 vDstWH;
2625
+ flat in ivec2 vDstWHFixed;
2626
+
2627
+ out vec4 oRGBA;
2628
+
2629
+ void main() {
2630
+ if (vZ == ${Layer.Hidden} || vDstWHFixed.x == 0 || vDstWHFixed.y == 0)
2631
+ discard;
2632
+
2633
+ vec2 px = vec2(vTexXYWH.xy) + (
2634
+ vStretch == 1u ? (vDstWH * vec2(vTexXYWH.zw) / vec2(vDstWHFixed))
2635
+ : mod(vDstWH, vec2(vTexXYWH.zw))
2636
+ );
2637
+
2638
+ oRGBA = texture(uTex, px / vec2(uTexWH));
2639
+ if(oRGBA.a < .001) discard;
2640
+ }
2641
+ `;
2642
+
2643
+ // src/graphics/sprite-vert.glsl.ts
2644
+ var spriteVertGLSL = `#version 300 es
2645
+ #pragma debug(${debug?.render ? "on" : "off"})
2646
+ #pragma optimize(${debug?.render ? "off" : "on"})
2647
+
2648
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2
2649
+ precision highp int;
2650
+ precision highp float;
2651
+ precision highp usampler2D;
2652
+
2653
+ uniform ivec4 uCam;
2654
+ uniform usampler2D uCels;
2655
+ uniform float uAge;
2656
+
2657
+ layout (location=0) in ivec2 iUV;
2658
+ layout (location=1) in uint iy8_x24;
2659
+ layout (location=2) in uint iw8_sxyz_llll_y16;
2660
+ layout (location=3) in uint ii11_c5_h12_w4;
2661
+
2662
+ const int maxY = 0x20000;
2663
+ const int layers = 16;
2664
+ const int maxDepth = maxY * layers;
2665
+
2666
+ flat out uint vStretch;
2667
+ flat out ivec4 vTexXYWH;
2668
+ flat out int vZ;
2669
+ out vec2 vDstWH;
2670
+ flat out ivec2 vDstWHFixed;
2671
+
2672
+ void main() {
2673
+ int x = (int((iy8_x24 & 0xffffffu) << 8) >> 8) / 64;
2674
+ int y = (int(iy8_x24 >> 24) | (int(iw8_sxyz_llll_y16 & 0xffffu) << 16 >> 8)) / 64;
2675
+ int z = int((iw8_sxyz_llll_y16 >> 16) & 0xfu);
2676
+ bool zend = bool(iw8_sxyz_llll_y16 & 0x100000u);
2677
+ bool flipY = bool(iw8_sxyz_llll_y16 & 0x200000u);
2678
+ bool flipX = bool(iw8_sxyz_llll_y16 & 0x400000u);
2679
+ bool stretch = bool(iw8_sxyz_llll_y16 & 0x800000u);
2680
+ int id = int((ii11_c5_h12_w4 >> 17) & 0x7ff0u); // ignore cel.
2681
+ int cel = int((ii11_c5_h12_w4 >> 16) & 0xfu); // ignore the MSB.
2682
+ int w = int(((ii11_c5_h12_w4 & 0xfu) << 8) | (iw8_sxyz_llll_y16 >> 24));
2683
+ int h = int((ii11_c5_h12_w4 >> 4) & 0xfffu);
2684
+
2685
+ // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel
2686
+ float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);
2687
+
2688
+ ivec2 targetWH = iUV * ivec2(w, h);
2689
+
2690
+ vec2 end = vec2(x + targetWH.x, y + targetWH.y);
2691
+ // UI layers are always given in screen coordinates.
2692
+ // to-do: how to handle non-int mode?
2693
+ vec2 camXY = z < ${Layer.A} ? vec2(0, 0) : vec2(uCam.xy);
2694
+ vec2 clip = ((-2. * camXY + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);
2695
+ gl_Position = vec4(clip, depth, 1);
2696
+
2697
+ int frame = (((int(uAge / ${celMillis}) & 0x1f) - cel) + ${animCels}) & 0xf;
2698
+ uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);
2699
+ vTexXYWH = ivec4(texXYWH);
2700
+ vZ = z;
2701
+
2702
+ vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));
2703
+ vDstWHFixed = ivec2(w, h) * ivec2(flipX ? -1 : 1, flipY ? -1 : 1);
2704
+
2705
+ vStretch = stretch ? 1u : 0u;
2706
+ }
2707
+ `;
2708
+
2709
+ // src/graphics/renderer.ts
2710
+ var uv = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0]);
2711
+ var Renderer = class {
2712
+ /** when off, ents should avoid requesting renders. */
2713
+ always = false;
2714
+ invalid = false;
2715
+ loseContext;
2716
+ #canvas;
2717
+ #clearRGBA = 0;
2718
+ #ctx;
2719
+ #preloadAtlas;
2720
+ #preloadAtlasImage;
2721
+ constructor(preloadAtlas, canvas) {
2722
+ this.#preloadAtlas = preloadAtlas;
2723
+ this.#canvas = canvas;
2724
+ this.#ctx = this.#Context();
2725
+ }
2726
+ clear(rgba) {
2727
+ if (!this.#ctx) return;
2728
+ const { gl } = this.#ctx;
2729
+ if (this.#clearRGBA !== rgba) {
2730
+ this.#clearRGBA = rgba;
2731
+ gl.clearColor(
2732
+ (rgba >>> 24 & 255) / 255,
2733
+ (rgba >>> 16 & 255) / 255,
2734
+ (rgba >>> 8 & 255) / 255,
2735
+ (rgba >>> 0 & 255) / 255
2736
+ );
2737
+ }
2738
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
2739
+ }
2740
+ draw(pool) {
2741
+ if (!this.#preloadAtlasImage || !this.#ctx) return;
2742
+ const { gl, spriteShader } = this.#ctx;
2743
+ gl.bindBuffer(gl.ARRAY_BUFFER, spriteShader.buffer);
2744
+ gl.bufferData(
2745
+ gl.ARRAY_BUFFER,
2746
+ pool.view,
2747
+ gl.DYNAMIC_DRAW,
2748
+ 0,
2749
+ pool.size * drawableBytes
2750
+ );
2751
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
2752
+ gl.bindVertexArray(spriteShader.vao);
2753
+ gl.drawArraysInstanced(
2754
+ gl.TRIANGLE_STRIP,
2755
+ 0,
2756
+ uv.length / 2,
2757
+ // d
2758
+ pool.size
2759
+ );
2760
+ gl.bindVertexArray(null);
2761
+ this.invalid = false;
2762
+ }
2763
+ load(preloadAtlas) {
2764
+ this.#preloadAtlasImage = preloadAtlas;
2765
+ this.#ctx = this.#Context();
2766
+ }
2767
+ predraw(cam, framer) {
2768
+ if (!this.#ctx) return;
2769
+ const { gl, spriteShader, viewport } = this.#ctx;
2770
+ if (!whEq(viewport, cam)) {
2771
+ gl.viewport(0, 0, cam.w, cam.h);
2772
+ viewport.w = cam.w;
2773
+ viewport.h = cam.h;
2774
+ }
2775
+ gl.useProgram(spriteShader.program);
2776
+ gl.uniform4i(spriteShader.uniform.uCam, cam.x, cam.y, cam.w, cam.h);
2777
+ gl.uniform1f(spriteShader.uniform.uAge, framer.age);
2778
+ for (const [i, tex] of spriteShader.textures.entries()) {
2779
+ gl.activeTexture(gl.TEXTURE0 + i);
2780
+ gl.bindTexture(gl.TEXTURE_2D, tex);
2781
+ }
2782
+ }
2783
+ register(op) {
2784
+ this.#canvas[`${op}EventListener`]("webglcontextlost", this.#onContextLost);
2785
+ this.#canvas[`${op}EventListener`](
2786
+ "webglcontextrestored",
2787
+ this.#onContextRestored
2788
+ );
2789
+ return this;
2790
+ }
2791
+ setDepth(enable) {
2792
+ if (!this.#ctx) return;
2793
+ if (enable) this.#ctx.gl.enable(this.#ctx.gl.DEPTH_TEST);
2794
+ else this.#ctx.gl.disable(this.#ctx.gl.DEPTH_TEST);
2795
+ }
2796
+ [Symbol.dispose]() {
2797
+ this.register("remove");
2798
+ }
2799
+ #Context() {
2800
+ const gl = this.#ctx?.gl ?? GL2(this.#canvas);
2801
+ if (!gl) return;
2802
+ const shader = Shader(gl, spriteVertGLSL, spriteFragGLSL, [
2803
+ gl.createTexture(),
2804
+ gl.createTexture()
2805
+ ]);
2806
+ gl.enable(gl.BLEND);
2807
+ gl.blendFuncSeparate(
2808
+ gl.SRC_ALPHA,
2809
+ gl.ONE_MINUS_SRC_ALPHA,
2810
+ gl.ONE,
2811
+ gl.ONE_MINUS_SRC_ALPHA
2812
+ );
2813
+ gl.depthRange(0, 1);
2814
+ gl.clearDepth(1);
2815
+ gl.depthFunc(gl.LESS);
2816
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false);
2817
+ gl.bindVertexArray(shader.vao);
2818
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
2819
+ gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW);
2820
+ gl.enableVertexAttribArray(0);
2821
+ gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0);
2822
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
2823
+ gl.bindBuffer(gl.ARRAY_BUFFER, shader.buffer);
2824
+ gl.enableVertexAttribArray(1);
2825
+ gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, drawableBytes, 0);
2826
+ gl.vertexAttribDivisor(1, 1);
2827
+ gl.enableVertexAttribArray(2);
2828
+ gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, drawableBytes, 4);
2829
+ gl.vertexAttribDivisor(2, 1);
2830
+ gl.enableVertexAttribArray(3);
2831
+ gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, drawableBytes, 8);
2832
+ gl.vertexAttribDivisor(3, 1);
2833
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
2834
+ gl.bindTexture(gl.TEXTURE_2D, shader.textures[0]);
2835
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
2836
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
2837
+ if (this.#preloadAtlasImage)
2838
+ gl.texImage2D(
2839
+ gl.TEXTURE_2D,
2840
+ 0,
2841
+ gl.RGBA,
2842
+ gl.RGBA,
2843
+ gl.UNSIGNED_BYTE,
2844
+ this.#preloadAtlasImage
2845
+ );
2846
+ gl.bindTexture(gl.TEXTURE_2D, null);
2847
+ gl.bindTexture(gl.TEXTURE_2D, shader.textures[1]);
2848
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
2849
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
2850
+ gl.texImage2D(
2851
+ gl.TEXTURE_2D,
2852
+ 0,
2853
+ gl.RGBA16UI,
2854
+ // source XYWH cannot be > 65535.
2855
+ 1,
2856
+ this.#preloadAtlas.celXYWH.length / 4,
2857
+ // 4 u16s per row
2858
+ 0,
2859
+ gl.RGBA_INTEGER,
2860
+ gl.UNSIGNED_SHORT,
2861
+ new Uint16Array(this.#preloadAtlas.celXYWH)
2862
+ );
2863
+ gl.bindTexture(gl.TEXTURE_2D, null);
2864
+ gl.bindVertexArray(null);
2865
+ gl.uniform1i(shader.uniform.uTex, 0);
2866
+ gl.uniform1i(shader.uniform.uCels, 1);
2867
+ if (this.#preloadAtlasImage)
2868
+ gl.uniform2ui(
2869
+ shader.uniform.uTexWH,
2870
+ this.#preloadAtlasImage.naturalWidth,
2871
+ this.#preloadAtlasImage.naturalHeight
2872
+ );
2873
+ this.invalid = true;
2874
+ this.loseContext = gl.getExtension("WEBGL_lose_context") ?? void 0;
2875
+ return this.#ctx = { gl, spriteShader: shader, viewport: { w: 0, h: 0 } };
2876
+ }
2877
+ #onContextLost = (ev) => {
2878
+ ev.preventDefault();
2879
+ console.debug("[render] WebGL context lost");
2880
+ this.#ctx = void 0;
2881
+ };
2882
+ #onContextRestored = () => {
2883
+ console.debug("[render] WebGL context restored");
2884
+ this.#ctx = this.#Context();
2885
+ };
2886
+ };
2887
+ function GL2(canvas) {
2888
+ const gl = canvas.getContext("webgl2", {
2889
+ // to-do: expose.
2890
+ antialias: false,
2891
+ powerPreference: "low-power",
2892
+ // avoid flicker caused by clearing the drawing buffer. see
2893
+ // https://developer.chrome.com/blog/desynchronized/.
2894
+ preserveDrawingBuffer: true,
2895
+ ...!debug?.render && { desynchronized: true }
2896
+ });
2897
+ if (!gl) {
2898
+ console.debug("[render] no GL context");
2899
+ return;
2900
+ }
2901
+ if (debug?.render && !gl.getContextAttributes()?.desynchronized)
2902
+ console.debug("[render] no WebGL DOM desynchronization");
2903
+ return gl;
2904
+ }
2905
+
2906
+ // src/looper.ts
2907
+ var Looper = class {
2908
+ /** duration of frames observed. */
2909
+ age = 0;
2910
+ onFrame;
2911
+ #req = 0;
2912
+ #registered = false;
2913
+ register(op) {
2914
+ const fn = `${op}EventListener`;
2915
+ document[fn]("visibilitychange", this.#onVisibility);
2916
+ if (op === "remove") this.#cancel();
2917
+ this.#registered = op === "add";
2918
+ return this;
2919
+ }
2920
+ requestFrame() {
2921
+ if (this.#req || document.hidden || !this.#registered) return;
2922
+ this.#req = requestAnimationFrame(this.#onFrame);
2923
+ }
2924
+ [Symbol.dispose]() {
2925
+ this.register("remove");
2926
+ }
2927
+ #cancel() {
2928
+ if (this.#req) cancelAnimationFrame(this.#req);
2929
+ this.#req = 0;
2930
+ }
2931
+ #onFrame = (now) => {
2932
+ this.age = now;
2933
+ this.#req = 0;
2934
+ this.onFrame?.(now - (this.age || now));
2935
+ };
2936
+ #onVisibility = (ev) => {
2937
+ if (!ev.isTrusted) return;
2938
+ if (document.hidden) this.#cancel();
2939
+ else this.requestFrame();
2940
+ };
2941
+ };
2942
+
2943
+ // src/pixel-ratio-observer.ts
2944
+ var PixelRatioObserver = class {
2945
+ onChange = () => {
2946
+ };
2947
+ #mediaQuery;
2948
+ register(op) {
2949
+ this.#mediaQuery?.removeEventListener("change", this.#onChange);
2950
+ if (op === "add") {
2951
+ this.#mediaQuery = matchMedia(`not (resolution: ${devicePixelRatio}dppx)`);
2952
+ this.#mediaQuery.addEventListener("change", this.#onChange);
2953
+ } else this.#mediaQuery = void 0;
2954
+ return this;
2955
+ }
2956
+ [Symbol.dispose]() {
2957
+ this.register("remove");
2958
+ }
2959
+ #onChange = () => {
2960
+ this.register("add");
2961
+ this.onChange();
2962
+ };
2963
+ };
2964
+
2965
+ // src/void.ts
2966
+ var Void = class {
2967
+ cam = new Cam();
2968
+ canvas;
2969
+ framer = new Looper();
2970
+ input;
2971
+ preload;
2972
+ renderer;
2973
+ sprites;
2974
+ zoo = new Zoo();
2975
+ #pixelRatioObserver = new PixelRatioObserver();
2976
+ #preloadAtlasImage;
2977
+ #resizeObserver = new ResizeObserver(() => this.onResize());
2978
+ constructor(opts) {
2979
+ initMetaViewport();
2980
+ this.canvas = initCanvas(opts.canvas, opts.mode ?? "Int");
2981
+ initBody(this.canvas, opts.backgroundRGBA ?? 255);
2982
+ if (opts.minWH) this.cam.minWH = opts.minWH;
2983
+ this.cam.mode = opts.mode ?? "Int";
2984
+ this.cam.update(this.canvas);
2985
+ this.input = new Input(this.cam, this.canvas);
2986
+ if (opts.input !== "Custom") this.input.mapDefault();
2987
+ this.input.onEvent = () => this.onEvent();
2988
+ this.#pixelRatioObserver.onChange = () => this.onResize();
2989
+ if (opts.preloadAtlas) this.#preloadAtlasImage = opts.preloadAtlas.image;
2990
+ this.preload = opts.preloadAtlas ? parseAtlas(opts.preloadAtlas.json) : { anim: {}, celXYWH: [], tags: [] };
2991
+ this.renderer = new Renderer(this.preload ?? {}, this.canvas);
2992
+ this.sprites = new Pool({
2993
+ alloc: (pool) => this.onAllocSprite(pool),
2994
+ allocBytes: drawableBytes,
2995
+ minPages: opts.sprites?.minPages ?? 3,
2996
+ pageBlocks: opts.sprites?.pageBlocks ?? 1e3
2997
+ });
2998
+ this.framer.onFrame = (millis) => this.onFrame(millis);
2999
+ }
3000
+ onAllocSprite(pool) {
3001
+ return new Sprite(pool, 0, this.preload, this.framer);
3002
+ }
3003
+ onEvent() {
3004
+ this.framer.requestFrame();
3005
+ }
3006
+ /** update input, update canvas, update cam, update world, then render. */
3007
+ onFrame(millis) {
3008
+ if (document.hidden) return;
3009
+ this.input.update(millis);
3010
+ this.onLoop(millis);
3011
+ this.cam.postupdate();
3012
+ }
3013
+ // biome-ignore lint/correctness/noUnusedFunctionParameters:;
3014
+ onLoop(millis) {
3015
+ }
3016
+ onResize() {
3017
+ this.framer.requestFrame();
3018
+ }
3019
+ async register(op) {
3020
+ this.input.register(op);
3021
+ this.renderer.register(op);
3022
+ this.framer.register(op);
3023
+ if (!this.canvas.parentElement) throw Error("no canvas parent");
3024
+ if (op === "add") this.#resizeObserver.observe(this.canvas.parentElement);
3025
+ else this.#resizeObserver.unobserve(this.canvas.parentElement);
3026
+ this.#pixelRatioObserver.register(op);
3027
+ this.framer.requestFrame();
3028
+ if (this.#preloadAtlasImage) await loadImage(this.#preloadAtlasImage);
3029
+ this.renderer.load(this.#preloadAtlasImage);
3030
+ }
3031
+ requestFrame() {
3032
+ if (this.renderer.always || this.input.anyOn || this.input.gamepad)
3033
+ this.framer.requestFrame();
3034
+ }
3035
+ async [Symbol.asyncDispose]() {
3036
+ await this.register("remove");
3037
+ }
3038
+ };
3039
+
3040
+ // src/index.ts
3041
+ var version = voidVersion ? `${voidVersion.version}+${voidVersion.published}.${voidVersion.hash}` : "?";
3042
+
3043
+ // src/demo/assets/preload-atlas.json
3044
+ var preload_atlas_default = {
3045
+ anim: {
3046
+ "background--OrangeCheckerboard": { cels: 1, h: 2, id: 0, w: 2 },
3047
+ "background--GreyCheckerboard": { cels: 1, h: 2, id: 1, w: 2 },
3048
+ "background--Kiwi": { cels: 1, h: 2, id: 2, w: 2 },
3049
+ "background--Strawberry": { cels: 1, h: 2, id: 3, w: 2 },
3050
+ "background--Grape": { cels: 1, h: 2, id: 4, w: 2 },
3051
+ "background--Blueberry": { cels: 1, h: 2, id: 5, w: 2 },
3052
+ "background--Bubblegum": { cels: 1, h: 2, id: 6, w: 2 },
3053
+ "background--Transparent": { cels: 1, h: 2, id: 7, w: 2 },
3054
+ "background--Black": { cels: 1, h: 2, id: 8, w: 2 },
3055
+ "backpacker--WalkRight": {
3056
+ cels: 16,
3057
+ h: 13,
3058
+ hitbox: { x: 2, y: 0, w: 4, h: 4 },
3059
+ id: 9,
3060
+ w: 8
3061
+ },
3062
+ "backpacker--WalkDown": {
3063
+ cels: 16,
3064
+ h: 13,
3065
+ hitbox: { x: 2, y: 0, w: 4, h: 4 },
3066
+ id: 10,
3067
+ w: 8
3068
+ },
3069
+ "backpacker--WalkUp": {
3070
+ cels: 16,
3071
+ h: 13,
3072
+ hitbox: { x: 2, y: 0, w: 4, h: 4 },
3073
+ id: 11,
3074
+ w: 8
3075
+ },
3076
+ "cursor--Pointer": {
3077
+ cels: 1,
3078
+ h: 14,
3079
+ hitbox: { x: 0, y: 0, w: 2, h: 2 },
3080
+ hurtbox: { x: 0, y: 0, w: 2, h: 2 },
3081
+ id: 12,
3082
+ w: 8
3083
+ },
3084
+ "mem-prop-5x6--00": { cels: 1, h: 6, id: 13, w: 5 },
3085
+ "mem-prop-5x6--01": { cels: 1, h: 6, id: 14, w: 5 },
3086
+ "mem-prop-5x6--02": { cels: 1, h: 6, id: 15, w: 5 },
3087
+ "mem-prop-5x6--03": { cels: 1, h: 6, id: 16, w: 5 },
3088
+ "mem-prop-5x6--04": { cels: 1, h: 6, id: 17, w: 5 },
3089
+ "mem-prop-5x6--05": { cels: 1, h: 6, id: 18, w: 5 },
3090
+ "mem-prop-5x6--06": { cels: 1, h: 6, id: 19, w: 5 },
3091
+ "mem-prop-5x6--07": { cels: 1, h: 6, id: 20, w: 5 },
3092
+ "mem-prop-5x6--08": { cels: 1, h: 6, id: 21, w: 5 },
3093
+ "mem-prop-5x6--09": { cels: 1, h: 6, id: 22, w: 5 },
3094
+ "mem-prop-5x6--0a": { cels: 1, h: 6, id: 23, w: 5 },
3095
+ "mem-prop-5x6--0b": { cels: 1, h: 6, id: 24, w: 5 },
3096
+ "mem-prop-5x6--0c": { cels: 1, h: 6, id: 25, w: 5 },
3097
+ "mem-prop-5x6--0d": { cels: 1, h: 6, id: 26, w: 5 },
3098
+ "mem-prop-5x6--0e": { cels: 1, h: 6, id: 27, w: 5 },
3099
+ "mem-prop-5x6--0f": { cels: 1, h: 6, id: 28, w: 5 },
3100
+ "mem-prop-5x6--10": { cels: 1, h: 6, id: 29, w: 5 },
3101
+ "mem-prop-5x6--11": { cels: 1, h: 6, id: 30, w: 5 },
3102
+ "mem-prop-5x6--12": { cels: 1, h: 6, id: 31, w: 5 },
3103
+ "mem-prop-5x6--13": { cels: 1, h: 6, id: 32, w: 5 },
3104
+ "mem-prop-5x6--14": { cels: 1, h: 6, id: 33, w: 5 },
3105
+ "mem-prop-5x6--15": { cels: 1, h: 6, id: 34, w: 5 },
3106
+ "mem-prop-5x6--16": { cels: 1, h: 6, id: 35, w: 5 },
3107
+ "mem-prop-5x6--17": { cels: 1, h: 6, id: 36, w: 5 },
3108
+ "mem-prop-5x6--18": { cels: 1, h: 6, id: 37, w: 5 },
3109
+ "mem-prop-5x6--19": { cels: 1, h: 6, id: 38, w: 5 },
3110
+ "mem-prop-5x6--1a": { cels: 1, h: 6, id: 39, w: 5 },
3111
+ "mem-prop-5x6--1b": { cels: 1, h: 6, id: 40, w: 5 },
3112
+ "mem-prop-5x6--1c": { cels: 1, h: 6, id: 41, w: 5 },
3113
+ "mem-prop-5x6--1d": { cels: 1, h: 6, id: 42, w: 5 },
3114
+ "mem-prop-5x6--1e": { cels: 1, h: 6, id: 43, w: 5 },
3115
+ "mem-prop-5x6--1f": { cels: 1, h: 6, id: 44, w: 5 },
3116
+ "mem-prop-5x6--20": { cels: 1, h: 6, id: 45, w: 5 },
3117
+ "mem-prop-5x6--21": { cels: 1, h: 6, id: 46, w: 5 },
3118
+ "mem-prop-5x6--22": { cels: 1, h: 6, id: 47, w: 5 },
3119
+ "mem-prop-5x6--23": { cels: 1, h: 6, id: 48, w: 5 },
3120
+ "mem-prop-5x6--24": { cels: 1, h: 6, id: 49, w: 5 },
3121
+ "mem-prop-5x6--25": { cels: 1, h: 6, id: 50, w: 5 },
3122
+ "mem-prop-5x6--26": { cels: 1, h: 6, id: 51, w: 5 },
3123
+ "mem-prop-5x6--27": { cels: 1, h: 6, id: 52, w: 5 },
3124
+ "mem-prop-5x6--28": { cels: 1, h: 6, id: 53, w: 5 },
3125
+ "mem-prop-5x6--29": { cels: 1, h: 6, id: 54, w: 5 },
3126
+ "mem-prop-5x6--2a": { cels: 1, h: 6, id: 55, w: 5 },
3127
+ "mem-prop-5x6--2b": { cels: 1, h: 6, id: 56, w: 5 },
3128
+ "mem-prop-5x6--2c": { cels: 1, h: 6, id: 57, w: 5 },
3129
+ "mem-prop-5x6--2d": { cels: 1, h: 6, id: 58, w: 5 },
3130
+ "mem-prop-5x6--2e": { cels: 1, h: 6, id: 59, w: 5 },
3131
+ "mem-prop-5x6--2f": { cels: 1, h: 6, id: 60, w: 5 },
3132
+ "mem-prop-5x6--30": { cels: 1, h: 6, id: 61, w: 5 },
3133
+ "mem-prop-5x6--31": { cels: 1, h: 6, id: 62, w: 5 },
3134
+ "mem-prop-5x6--32": { cels: 1, h: 6, id: 63, w: 5 },
3135
+ "mem-prop-5x6--33": { cels: 1, h: 6, id: 64, w: 5 },
3136
+ "mem-prop-5x6--34": { cels: 1, h: 6, id: 65, w: 5 },
3137
+ "mem-prop-5x6--35": { cels: 1, h: 6, id: 66, w: 5 },
3138
+ "mem-prop-5x6--36": { cels: 1, h: 6, id: 67, w: 5 },
3139
+ "mem-prop-5x6--37": { cels: 1, h: 6, id: 68, w: 5 },
3140
+ "mem-prop-5x6--38": { cels: 1, h: 6, id: 69, w: 5 },
3141
+ "mem-prop-5x6--39": { cels: 1, h: 6, id: 70, w: 5 },
3142
+ "mem-prop-5x6--3a": { cels: 1, h: 6, id: 71, w: 5 },
3143
+ "mem-prop-5x6--3b": { cels: 1, h: 6, id: 72, w: 5 },
3144
+ "mem-prop-5x6--3c": { cels: 1, h: 6, id: 73, w: 5 },
3145
+ "mem-prop-5x6--3d": { cels: 1, h: 6, id: 74, w: 5 },
3146
+ "mem-prop-5x6--3e": { cels: 1, h: 6, id: 75, w: 5 },
3147
+ "mem-prop-5x6--3f": { cels: 1, h: 6, id: 76, w: 5 },
3148
+ "mem-prop-5x6--40": { cels: 1, h: 6, id: 77, w: 5 },
3149
+ "mem-prop-5x6--41": { cels: 1, h: 6, id: 78, w: 5 },
3150
+ "mem-prop-5x6--42": { cels: 1, h: 6, id: 79, w: 5 },
3151
+ "mem-prop-5x6--43": { cels: 1, h: 6, id: 80, w: 5 },
3152
+ "mem-prop-5x6--44": { cels: 1, h: 6, id: 81, w: 5 },
3153
+ "mem-prop-5x6--45": { cels: 1, h: 6, id: 82, w: 5 },
3154
+ "mem-prop-5x6--46": { cels: 1, h: 6, id: 83, w: 5 },
3155
+ "mem-prop-5x6--47": { cels: 1, h: 6, id: 84, w: 5 },
3156
+ "mem-prop-5x6--48": { cels: 1, h: 6, id: 85, w: 5 },
3157
+ "mem-prop-5x6--49": { cels: 1, h: 6, id: 86, w: 5 },
3158
+ "mem-prop-5x6--4a": { cels: 1, h: 6, id: 87, w: 5 },
3159
+ "mem-prop-5x6--4b": { cels: 1, h: 6, id: 88, w: 5 },
3160
+ "mem-prop-5x6--4c": { cels: 1, h: 6, id: 89, w: 5 },
3161
+ "mem-prop-5x6--4d": { cels: 1, h: 6, id: 90, w: 5 },
3162
+ "mem-prop-5x6--4e": { cels: 1, h: 6, id: 91, w: 5 },
3163
+ "mem-prop-5x6--4f": { cels: 1, h: 6, id: 92, w: 5 },
3164
+ "mem-prop-5x6--50": { cels: 1, h: 6, id: 93, w: 5 },
3165
+ "mem-prop-5x6--51": { cels: 1, h: 6, id: 94, w: 5 },
3166
+ "mem-prop-5x6--52": { cels: 1, h: 6, id: 95, w: 5 },
3167
+ "mem-prop-5x6--53": { cels: 1, h: 6, id: 96, w: 5 },
3168
+ "mem-prop-5x6--54": { cels: 1, h: 6, id: 97, w: 5 },
3169
+ "mem-prop-5x6--55": { cels: 1, h: 6, id: 98, w: 5 },
3170
+ "mem-prop-5x6--56": { cels: 1, h: 6, id: 99, w: 5 },
3171
+ "mem-prop-5x6--57": { cels: 1, h: 6, id: 100, w: 5 },
3172
+ "mem-prop-5x6--58": { cels: 1, h: 6, id: 101, w: 5 },
3173
+ "mem-prop-5x6--59": { cels: 1, h: 6, id: 102, w: 5 },
3174
+ "mem-prop-5x6--5a": { cels: 1, h: 6, id: 103, w: 5 },
3175
+ "mem-prop-5x6--5b": { cels: 1, h: 6, id: 104, w: 5 },
3176
+ "mem-prop-5x6--5c": { cels: 1, h: 6, id: 105, w: 5 },
3177
+ "mem-prop-5x6--5d": { cels: 1, h: 6, id: 106, w: 5 },
3178
+ "mem-prop-5x6--5e": { cels: 1, h: 6, id: 107, w: 5 },
3179
+ "mem-prop-5x6--5f": { cels: 1, h: 6, id: 108, w: 5 },
3180
+ "mem-prop-5x6--60": { cels: 1, h: 6, id: 109, w: 5 },
3181
+ "mem-prop-5x6--61": { cels: 1, h: 6, id: 110, w: 5 },
3182
+ "mem-prop-5x6--62": { cels: 1, h: 6, id: 111, w: 5 },
3183
+ "mem-prop-5x6--63": { cels: 1, h: 6, id: 112, w: 5 },
3184
+ "mem-prop-5x6--64": { cels: 1, h: 6, id: 113, w: 5 },
3185
+ "mem-prop-5x6--65": { cels: 1, h: 6, id: 114, w: 5 },
3186
+ "mem-prop-5x6--66": { cels: 1, h: 6, id: 115, w: 5 },
3187
+ "mem-prop-5x6--67": { cels: 1, h: 6, id: 116, w: 5 },
3188
+ "mem-prop-5x6--68": { cels: 1, h: 6, id: 117, w: 5 },
3189
+ "mem-prop-5x6--69": { cels: 1, h: 6, id: 118, w: 5 },
3190
+ "mem-prop-5x6--6a": { cels: 1, h: 6, id: 119, w: 5 },
3191
+ "mem-prop-5x6--6b": { cels: 1, h: 6, id: 120, w: 5 },
3192
+ "mem-prop-5x6--6c": { cels: 1, h: 6, id: 121, w: 5 },
3193
+ "mem-prop-5x6--6d": { cels: 1, h: 6, id: 122, w: 5 },
3194
+ "mem-prop-5x6--6e": { cels: 1, h: 6, id: 123, w: 5 },
3195
+ "mem-prop-5x6--6f": { cels: 1, h: 6, id: 124, w: 5 },
3196
+ "mem-prop-5x6--70": { cels: 1, h: 6, id: 125, w: 5 },
3197
+ "mem-prop-5x6--71": { cels: 1, h: 6, id: 126, w: 5 },
3198
+ "mem-prop-5x6--72": { cels: 1, h: 6, id: 127, w: 5 },
3199
+ "mem-prop-5x6--73": { cels: 1, h: 6, id: 128, w: 5 },
3200
+ "mem-prop-5x6--74": { cels: 1, h: 6, id: 129, w: 5 },
3201
+ "mem-prop-5x6--75": { cels: 1, h: 6, id: 130, w: 5 },
3202
+ "mem-prop-5x6--76": { cels: 1, h: 6, id: 131, w: 5 },
3203
+ "mem-prop-5x6--77": { cels: 1, h: 6, id: 132, w: 5 },
3204
+ "mem-prop-5x6--78": { cels: 1, h: 6, id: 133, w: 5 },
3205
+ "mem-prop-5x6--79": { cels: 1, h: 6, id: 134, w: 5 },
3206
+ "mem-prop-5x6--7a": { cels: 1, h: 6, id: 135, w: 5 },
3207
+ "mem-prop-5x6--7b": { cels: 1, h: 6, id: 136, w: 5 },
3208
+ "mem-prop-5x6--7c": { cels: 1, h: 6, id: 137, w: 5 },
3209
+ "mem-prop-5x6--7d": { cels: 1, h: 6, id: 138, w: 5 },
3210
+ "mem-prop-5x6--7e": { cels: 1, h: 6, id: 139, w: 5 },
3211
+ "mem-prop-5x6--7f": { cels: 1, h: 6, id: 140, w: 5 },
3212
+ "oidoid--Default": { cels: 1, h: 16, id: 141, w: 16 }
3213
+ },
3214
+ celXY: [
3215
+ 22,
3216
+ 37,
3217
+ 21,
3218
+ 27,
3219
+ 21,
3220
+ 29,
3221
+ 21,
3222
+ 31,
3223
+ 20,
3224
+ 33,
3225
+ 22,
3226
+ 33,
3227
+ 20,
3228
+ 35,
3229
+ 22,
3230
+ 35,
3231
+ 20,
3232
+ 37,
3233
+ 24,
3234
+ 26,
3235
+ 24,
3236
+ 26,
3237
+ 8,
3238
+ 16,
3239
+ 8,
3240
+ 16,
3241
+ 0,
3242
+ 16,
3243
+ 0,
3244
+ 16,
3245
+ 16,
3246
+ 14,
3247
+ 16,
3248
+ 14,
3249
+ 72,
3250
+ 13,
3251
+ 72,
3252
+ 13,
3253
+ 32,
3254
+ 26,
3255
+ 32,
3256
+ 26,
3257
+ 0,
3258
+ 16,
3259
+ 0,
3260
+ 16,
3261
+ 64,
3262
+ 13,
3263
+ 64,
3264
+ 13,
3265
+ 56,
3266
+ 13,
3267
+ 56,
3268
+ 13,
3269
+ 48,
3270
+ 13,
3271
+ 48,
3272
+ 13,
3273
+ 40,
3274
+ 13,
3275
+ 40,
3276
+ 13,
3277
+ 32,
3278
+ 13,
3279
+ 32,
3280
+ 13,
3281
+ 56,
3282
+ 13,
3283
+ 56,
3284
+ 13,
3285
+ 24,
3286
+ 13,
3287
+ 24,
3288
+ 13,
3289
+ 72,
3290
+ 0,
3291
+ 72,
3292
+ 0,
3293
+ 64,
3294
+ 0,
3295
+ 64,
3296
+ 0,
3297
+ 24,
3298
+ 0,
3299
+ 24,
3300
+ 0,
3301
+ 56,
3302
+ 0,
3303
+ 56,
3304
+ 0,
3305
+ 48,
3306
+ 0,
3307
+ 48,
3308
+ 0,
3309
+ 48,
3310
+ 0,
3311
+ 48,
3312
+ 0,
3313
+ 24,
3314
+ 0,
3315
+ 24,
3316
+ 0,
3317
+ 40,
3318
+ 0,
3319
+ 40,
3320
+ 0,
3321
+ 32,
3322
+ 0,
3323
+ 32,
3324
+ 0,
3325
+ 32,
3326
+ 0,
3327
+ 32,
3328
+ 0,
3329
+ 16,
3330
+ 0,
3331
+ 45,
3332
+ 56,
3333
+ 45,
3334
+ 56,
3335
+ 45,
3336
+ 56,
3337
+ 45,
3338
+ 56,
3339
+ 45,
3340
+ 56,
3341
+ 45,
3342
+ 56,
3343
+ 45,
3344
+ 56,
3345
+ 45,
3346
+ 56,
3347
+ 45,
3348
+ 56,
3349
+ 45,
3350
+ 56,
3351
+ 45,
3352
+ 56,
3353
+ 45,
3354
+ 56,
3355
+ 45,
3356
+ 56,
3357
+ 45,
3358
+ 56,
3359
+ 45,
3360
+ 56,
3361
+ 45,
3362
+ 56,
3363
+ 45,
3364
+ 56,
3365
+ 45,
3366
+ 56,
3367
+ 45,
3368
+ 56,
3369
+ 45,
3370
+ 56,
3371
+ 45,
3372
+ 56,
3373
+ 45,
3374
+ 56,
3375
+ 45,
3376
+ 56,
3377
+ 45,
3378
+ 56,
3379
+ 45,
3380
+ 56,
3381
+ 45,
3382
+ 56,
3383
+ 45,
3384
+ 56,
3385
+ 45,
3386
+ 56,
3387
+ 45,
3388
+ 56,
3389
+ 45,
3390
+ 56,
3391
+ 45,
3392
+ 56,
3393
+ 45,
3394
+ 56,
3395
+ 45,
3396
+ 56,
3397
+ 40,
3398
+ 56,
3399
+ 10,
3400
+ 53,
3401
+ 5,
3402
+ 53,
3403
+ 0,
3404
+ 53,
3405
+ 35,
3406
+ 51,
3407
+ 30,
3408
+ 51,
3409
+ 25,
3410
+ 51,
3411
+ 20,
3412
+ 51,
3413
+ 15,
3414
+ 51,
3415
+ 35,
3416
+ 45,
3417
+ 70,
3418
+ 50,
3419
+ 65,
3420
+ 50,
3421
+ 60,
3422
+ 50,
3423
+ 55,
3424
+ 50,
3425
+ 50,
3426
+ 50,
3427
+ 45,
3428
+ 50,
3429
+ 40,
3430
+ 50,
3431
+ 10,
3432
+ 47,
3433
+ 5,
3434
+ 47,
3435
+ 0,
3436
+ 47,
3437
+ 70,
3438
+ 62,
3439
+ 50,
3440
+ 56,
3441
+ 65,
3442
+ 62,
3443
+ 60,
3444
+ 62,
3445
+ 55,
3446
+ 62,
3447
+ 50,
3448
+ 62,
3449
+ 45,
3450
+ 62,
3451
+ 40,
3452
+ 62,
3453
+ 10,
3454
+ 59,
3455
+ 5,
3456
+ 59,
3457
+ 0,
3458
+ 59,
3459
+ 35,
3460
+ 57,
3461
+ 70,
3462
+ 32,
3463
+ 30,
3464
+ 57,
3465
+ 25,
3466
+ 57,
3467
+ 20,
3468
+ 57,
3469
+ 15,
3470
+ 57,
3471
+ 75,
3472
+ 56,
3473
+ 70,
3474
+ 56,
3475
+ 65,
3476
+ 56,
3477
+ 60,
3478
+ 56,
3479
+ 75,
3480
+ 50,
3481
+ 55,
3482
+ 56,
3483
+ 10,
3484
+ 35,
3485
+ 75,
3486
+ 32,
3487
+ 15,
3488
+ 33,
3489
+ 0,
3490
+ 35,
3491
+ 5,
3492
+ 35,
3493
+ 40,
3494
+ 38,
3495
+ 45,
3496
+ 38,
3497
+ 65,
3498
+ 32,
3499
+ 60,
3500
+ 32,
3501
+ 55,
3502
+ 32,
3503
+ 50,
3504
+ 32,
3505
+ 45,
3506
+ 32,
3507
+ 40,
3508
+ 26,
3509
+ 50,
3510
+ 26,
3511
+ 55,
3512
+ 26,
3513
+ 60,
3514
+ 26,
3515
+ 65,
3516
+ 26,
3517
+ 70,
3518
+ 26,
3519
+ 75,
3520
+ 26,
3521
+ 16,
3522
+ 27,
3523
+ 0,
3524
+ 29,
3525
+ 5,
3526
+ 29,
3527
+ 10,
3528
+ 29,
3529
+ 40,
3530
+ 32,
3531
+ 45,
3532
+ 26,
3533
+ 10,
3534
+ 41,
3535
+ 30,
3536
+ 45,
3537
+ 25,
3538
+ 45,
3539
+ 20,
3540
+ 45,
3541
+ 15,
3542
+ 45,
3543
+ 75,
3544
+ 44,
3545
+ 70,
3546
+ 44,
3547
+ 65,
3548
+ 44,
3549
+ 60,
3550
+ 44,
3551
+ 55,
3552
+ 44,
3553
+ 50,
3554
+ 44,
3555
+ 45,
3556
+ 44,
3557
+ 40,
3558
+ 44,
3559
+ 50,
3560
+ 38,
3561
+ 5,
3562
+ 41,
3563
+ 0,
3564
+ 41,
3565
+ 35,
3566
+ 39,
3567
+ 30,
3568
+ 39,
3569
+ 25,
3570
+ 39,
3571
+ 20,
3572
+ 39,
3573
+ 15,
3574
+ 39,
3575
+ 75,
3576
+ 38,
3577
+ 70,
3578
+ 38,
3579
+ 65,
3580
+ 38,
3581
+ 60,
3582
+ 38,
3583
+ 55,
3584
+ 38,
3585
+ 45,
3586
+ 56,
3587
+ 0,
3588
+ 0
3589
+ ]
3590
+ };
3591
+
3592
+ // src/demo/ents/clock-ent.ts
3593
+ var ClockEnt = class {
3594
+ #time = new TextEnt();
3595
+ constructor() {
3596
+ this.#time.scale = 3;
3597
+ this.#time.z = Layer.A;
3598
+ }
3599
+ free(v2) {
3600
+ this.#time.free(v2);
3601
+ }
3602
+ update(v2) {
3603
+ const now = /* @__PURE__ */ new Date();
3604
+ this.#time.text = timeString(now);
3605
+ if (this.#time.layout(v2) || v2.cam.invalid)
3606
+ this.#time.xy = v2.cam.follow(
3607
+ { w: this.#time.wh.w, h: this.#time.wh.h - this.#time.scaledLeading },
3608
+ this.#time.z,
3609
+ "N",
3610
+ { margin: { h: 8 } }
3611
+ );
3612
+ return this.#time.update(v2);
3613
+ }
3614
+ };
3615
+ function timeString(time) {
3616
+ const hh = `${time.getHours() % 12 || 12}`.padStart(2, " ");
3617
+ const mm = `${time.getMinutes()}`.padStart(2, "0");
3618
+ const ss = `${time.getSeconds()}`.padStart(2, "0");
3619
+ return `${hh}:${mm}:${ss}`;
3620
+ }
3621
+
3622
+ // src/demo/ents/render-toggle-ent.ts
3623
+ var RenderToggleEnt = class {
3624
+ #toggle;
3625
+ constructor(v2) {
3626
+ this.#toggle = new ButtonEnt(v2, {
3627
+ button: {
3628
+ w: { tag: "background--Strawberry" },
3629
+ nw: { tag: "background--Transparent" },
3630
+ n: { tag: "background--Bubblegum" },
3631
+ e: { tag: "background--Blueberry" },
3632
+ s: { tag: "background--Kiwi" },
3633
+ origin: { tag: "background--Grape" },
3634
+ border: { n: 1 },
3635
+ margin: { w: 2, h: 2 }
3636
+ },
3637
+ selected: { tag: "background--OrangeCheckerboard" },
3638
+ toggle: true,
3639
+ text: { text: "render", scale: 2 },
3640
+ w: 64,
3641
+ h: 22,
3642
+ x: 50,
3643
+ y: 25,
3644
+ pressed: { tag: "background--Bubblegum" }
3645
+ });
3646
+ }
3647
+ get on() {
3648
+ return this.#toggle.on;
3649
+ }
3650
+ free(v2) {
3651
+ this.#toggle.free(v2);
3652
+ }
3653
+ /** always updates but never invalidates. */
3654
+ update(v2) {
3655
+ return this.#toggle.update(v2);
3656
+ }
3657
+ };
3658
+
3659
+ // src/demo/ents/work-counter-ent.ts
3660
+ var WorkCounterEnt = class {
3661
+ #renders = 0;
3662
+ #text = new TextEnt();
3663
+ #updates = 0;
3664
+ constructor() {
3665
+ this.#text.z = Layer.A;
3666
+ }
3667
+ free(v2) {
3668
+ this.#text.free(v2);
3669
+ }
3670
+ incrementRender() {
3671
+ this.#renders++;
3672
+ }
3673
+ /** always updates but never invalidates. */
3674
+ update(v2) {
3675
+ this.#updates++;
3676
+ this.#text.text = `${this.#updates} updates
3677
+ ${this.#renders + 1} renders`;
3678
+ this.#text.layout(v2);
3679
+ this.#text.xy = v2.cam.follow(
3680
+ { w: this.#text.wh.w, h: this.#text.wh.h - this.#text.scaledLeading },
3681
+ this.#text.z,
3682
+ "NE",
3683
+ { margin: { w: 8, h: 8 } }
3684
+ );
3685
+ this.#text.update(v2);
3686
+ }
3687
+ };
3688
+
3689
+ // src/demo/game.ts
3690
+ var Game = class extends Void {
3691
+ #filterSprites;
3692
+ #interval = 0;
3693
+ #renderToggle;
3694
+ #timer = 0;
3695
+ #workCounter;
3696
+ constructor() {
3697
+ super({
3698
+ preloadAtlas: {
3699
+ image: document.querySelector("#preload-atlas"),
3700
+ json: preload_atlas_default
3701
+ },
3702
+ backgroundRGBA: 4294947327,
3703
+ minWH: { w: 320, h: 240 }
3704
+ });
3705
+ this.#filterSprites = new Pool({
3706
+ alloc: (pool) => new Sprite(pool, 0, this.preload, this.framer),
3707
+ allocBytes: drawableBytes,
3708
+ pageBlocks: 10
3709
+ });
3710
+ this.#renderToggle = new RenderToggleEnt(this);
3711
+ this.#workCounter = new WorkCounterEnt();
3712
+ this.#initZoo();
3713
+ }
3714
+ async register(op) {
3715
+ await super.register(op);
3716
+ if (op === "add") {
3717
+ this.framer.requestFrame();
3718
+ this.#startTimer();
3719
+ } else {
3720
+ this.#stopTimer();
3721
+ }
3722
+ }
3723
+ onLoop(_millis) {
3724
+ this.renderer.always = this.#renderToggle.on || !!debug?.invalid;
3725
+ let render = this.#updateCam();
3726
+ const updated = this.zoo.update(this);
3727
+ if (debug?.input) this.#printInput();
3728
+ render ||= updated || this.cam.invalid || this.renderer.invalid || this.renderer.always;
3729
+ if (render) {
3730
+ this.#workCounter.incrementRender();
3731
+ this.renderer.clear(4294947327);
3732
+ this.renderer.predraw(this.cam, this.framer);
3733
+ this.renderer.setDepth(true);
3734
+ this.renderer.draw(this.sprites);
3735
+ this.renderer.setDepth(false);
3736
+ this.renderer.draw(this.#filterSprites);
3737
+ }
3738
+ this.requestFrame();
3739
+ }
3740
+ #initZoo() {
3741
+ const border = new NinePatchEnt(this, {
3742
+ n: { tag: "background--Black" },
3743
+ origin: { tag: "background--Transparent" },
3744
+ border: { n: 1 },
3745
+ z: Layer.UIA
3746
+ // to-do: default 0 layer is dumb.
3747
+ });
3748
+ this.zoo.add(border);
3749
+ const box = this.cam.follow({ w: 0, h: 0 }, Layer.UIA, "NW", { fill: "XY" });
3750
+ border.xy = box;
3751
+ border.wh = box;
3752
+ const backpacker = this.sprites.alloc();
3753
+ backpacker.tag = "backpacker--WalkRight";
3754
+ backpacker.x = 7;
3755
+ backpacker.y = 7;
3756
+ backpacker.z = Layer.C;
3757
+ backpacker.stretch = true;
3758
+ backpacker.w *= 5;
3759
+ backpacker.h *= 5;
3760
+ const oidoid = new FollowCamEnt(this, "oidoid--Default", "SW");
3761
+ oidoid.z = Layer.UIG;
3762
+ oidoid.margin = { w: 4, h: 4 };
3763
+ this.zoo.add(
3764
+ new CursorEnt(this, "cursor--Pointer"),
3765
+ this.#renderToggle,
3766
+ new ClockEnt(),
3767
+ this.#workCounter,
3768
+ oidoid
3769
+ );
3770
+ const overlay = this.#filterSprites.alloc();
3771
+ overlay.tag = "background--GreyCheckerboard";
3772
+ overlay.w = drawableMaxWH.w;
3773
+ overlay.h = drawableMaxWH.h;
3774
+ overlay.z = Layer.UIA;
3775
+ }
3776
+ #printInput() {
3777
+ if (this.input.started) {
3778
+ const on = !!this.input.on.length;
3779
+ if (on) console.debug(`[input] buttons on: ${this.input.on.join(" ")}.`);
3780
+ else console.debug(`[input] buttons off.`);
3781
+ const combo = this.input.combo;
3782
+ if (combo.length > 1 && on)
3783
+ console.debug(
3784
+ `[input] combo: ${combo.map((set) => set.join("+")).join(" ")}.`
3785
+ );
3786
+ }
3787
+ if (this.input.point?.invalid && this.input.point?.click && !this.input.point.pinch)
3788
+ console.debug(
3789
+ `[input] ${this.input.point.drag.on ? "drag" : "click"} xy: ${this.input.point.x} ${this.input.point.y}.`
3790
+ );
3791
+ if (this.input.point?.pinch)
3792
+ console.debug(
3793
+ `[input] pinch xy: ${this.input.point.pinch.xy.x} ${this.input.point.pinch.xy.y}.`
3794
+ );
3795
+ if (this.input.wheel)
3796
+ console.debug(
3797
+ `[input] wheel xy: ${this.input.wheel.delta.xy.x} ${this.input.wheel.delta.xy.y}.`
3798
+ );
3799
+ }
3800
+ #startTimer() {
3801
+ this.#timer = setTimeout(
3802
+ () => {
3803
+ this.framer.requestFrame();
3804
+ this.#interval = setInterval(
3805
+ () => this.framer.requestFrame(),
3806
+ (debug?.seconds ? 1 : 60) * 1e3
3807
+ );
3808
+ },
3809
+ renderDelayMillis(/* @__PURE__ */ new Date(), debug?.seconds)
3810
+ );
3811
+ }
3812
+ #stopTimer() {
3813
+ clearTimeout(this.#timer);
3814
+ clearInterval(this.#interval);
3815
+ }
3816
+ #updateCam() {
3817
+ let render = this.input.isAnyOn("L", "R", "U", "D");
3818
+ if (this.input.isAnyOnStart("L", "R", "U", "D")) {
3819
+ this.cam.x = Math.trunc(this.cam.x);
3820
+ this.cam.y = Math.trunc(this.cam.y);
3821
+ }
3822
+ const d = 1 / 4;
3823
+ if (this.input.isOn("L")) this.cam.x -= d;
3824
+ if (this.input.isOn("R")) this.cam.x += d;
3825
+ if (this.input.isOn("U")) this.cam.y -= d;
3826
+ if (this.input.isOn("D")) this.cam.y += d;
3827
+ if (this.input.wheel?.delta.xy.y) {
3828
+ render = true;
3829
+ this.cam.zoomOut -= this.input.wheel.delta.client.y * 0.01;
3830
+ }
3831
+ this.cam.update(this.canvas);
3832
+ return render;
3833
+ }
3834
+ };
3835
+ function renderDelayMillis(time, debugSecs) {
3836
+ return ((debugSecs ? 0 : (59 - time.getSeconds() % 60) * 1e3) + 1e3 - time.getMilliseconds() % 1e3) % (debugSecs ? 1e3 : 6e4);
3837
+ }
3838
+
3839
+ // src/demo/index.ts
3840
+ console.debug(`void v${version} \u2500\u2500\u2500oidoid>\xB0\u2500\u2500`);
3841
+ var v = new Game();
3842
+ await v.register("add");
3843
+ if (debug) globalThis.v = v;
3844
+ //# sourceMappingURL=index.js.map