@oidoid/void 0.1.0-4 → 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 (300) 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 +31 -41
  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/anim.d.ts +0 -30
  231. package/dist/atlas/anim.js +0 -16
  232. package/dist/atlas/anim.js.map +0 -1
  233. package/dist/atlas/aseprite.d.ts +0 -37
  234. package/dist/atlas/aseprite.js +0 -2
  235. package/dist/atlas/aseprite.js.map +0 -1
  236. package/dist/atlas/atlas-parser.d.ts +0 -52
  237. package/dist/atlas/atlas-parser.js +0 -109
  238. package/dist/atlas/atlas-parser.js.map +0 -1
  239. package/dist/atlas/atlas.d.ts +0 -4
  240. package/dist/atlas/atlas.js +0 -2
  241. package/dist/atlas/atlas.js.map +0 -1
  242. package/dist/audio/synth.d.ts +0 -4
  243. package/dist/audio/synth.js +0 -21
  244. package/dist/audio/synth.js.map +0 -1
  245. package/dist/graphics/bitmap.d.ts +0 -14
  246. package/dist/graphics/bitmap.js +0 -14
  247. package/dist/graphics/bitmap.js.map +0 -1
  248. package/dist/graphics/cam.d.ts +0 -16
  249. package/dist/graphics/cam.js +0 -42
  250. package/dist/graphics/cam.js.map +0 -1
  251. package/dist/graphics/frag.glsl.d.ts +0 -1
  252. package/dist/graphics/frag.glsl.js +0 -15
  253. package/dist/graphics/frag.glsl.js.map +0 -1
  254. package/dist/graphics/frame-listener.d.ts +0 -16
  255. package/dist/graphics/frame-listener.js +0 -83
  256. package/dist/graphics/frame-listener.js.map +0 -1
  257. package/dist/graphics/renderer.d.ts +0 -12
  258. package/dist/graphics/renderer.js +0 -184
  259. package/dist/graphics/renderer.js.map +0 -1
  260. package/dist/graphics/vert.glsl.d.ts +0 -1
  261. package/dist/graphics/vert.glsl.js +0 -46
  262. package/dist/graphics/vert.glsl.js.map +0 -1
  263. package/dist/index.d.ts +0 -31
  264. package/dist/index.js +0 -79
  265. package/dist/index.js.map +0 -1
  266. package/dist/input/gamepad-poller.d.ts +0 -8
  267. package/dist/input/gamepad-poller.js +0 -38
  268. package/dist/input/gamepad-poller.js.map +0 -1
  269. package/dist/input/input.d.ts +0 -44
  270. package/dist/input/input.js +0 -175
  271. package/dist/input/input.js.map +0 -1
  272. package/dist/input/keyboard-poller.d.ts +0 -7
  273. package/dist/input/keyboard-poller.js +0 -30
  274. package/dist/input/keyboard-poller.js.map +0 -1
  275. package/dist/input/pointer-poller.d.ts +0 -12
  276. package/dist/input/pointer-poller.js +0 -67
  277. package/dist/input/pointer-poller.js.map +0 -1
  278. package/dist/sprite/sprite.d.ts +0 -51
  279. package/dist/sprite/sprite.js +0 -161
  280. package/dist/sprite/sprite.js.map +0 -1
  281. package/dist/storage/json-storage.d.ts +0 -4
  282. package/dist/storage/json-storage.js +0 -13
  283. package/dist/storage/json-storage.js.map +0 -1
  284. package/dist/test/tsconfig.json +0 -14
  285. package/dist/text/font.d.ts +0 -6
  286. package/dist/text/font.js +0 -18
  287. package/dist/text/font.js.map +0 -1
  288. package/dist/text/text-layout.d.ts +0 -11
  289. package/dist/text/text-layout.js +0 -73
  290. package/dist/text/text-layout.js.map +0 -1
  291. package/dist/tsconfig.json +0 -13
  292. package/dist/types/2d.d.ts +0 -9
  293. package/dist/types/2d.js +0 -2
  294. package/dist/types/2d.js.map +0 -1
  295. package/dist/void.js +0 -60
  296. package/dist/void.js.map +0 -7
  297. package/dist/void.meta.json +0 -289
  298. package/src/atlas/anim.js +0 -17
  299. package/tools/atlas-parser.js +0 -120
  300. package/tools/void.js +0 -143
@@ -0,0 +1,780 @@
1
+ import assert from 'node:assert/strict'
2
+ import {describe, test} from 'node:test'
3
+ import type {Anim, AtlasJSON} from '../../src/graphics/atlas.ts'
4
+ import type {XY} from '../../src/types/geo.ts'
5
+ import {
6
+ AsepriteDirection,
7
+ type AsepriteFrameMap,
8
+ type AsepriteTagSpan
9
+ } from './aseprite.ts'
10
+ import {
11
+ parseAnim,
12
+ parseAnimFrames,
13
+ parseAtlasJSON,
14
+ parseCel,
15
+ parseHitboxes
16
+ } from './atlas-json-parser.ts'
17
+
18
+ describe('parseAtlasJSON()', () => {
19
+ test('parses empty.', () => {
20
+ assert.deepEqual<AtlasJSON>(
21
+ parseAtlasJSON({
22
+ meta: {frameTags: [], size: {w: 0, h: 0}, slices: []},
23
+ frames: {}
24
+ }),
25
+ {anim: {}, celXY: []}
26
+ )
27
+ })
28
+
29
+ test('parses nonempty.', () => {
30
+ const frameTags = [
31
+ {name: 'scenery--Cloud', from: 0, to: 0, direction: 'forward'},
32
+ {name: 'palette--red', from: 1, to: 1, direction: 'forward'},
33
+ {name: 'scenery--Conifer', from: 2, to: 2, direction: 'forward'},
34
+ {name: 'scenery--ConiferShadow', from: 3, to: 3, direction: 'forward'},
35
+ {name: 'backpacker--WalkRight', from: 0, to: 7, direction: 'pingpong'}
36
+ ]
37
+ const frames = {
38
+ 'scenery--Cloud--0': {
39
+ frame: {x: 220, y: 18, w: 18, h: 18},
40
+ sourceSize: {w: 16, h: 16},
41
+ duration: 1
42
+ },
43
+ 'palette--red--1': {
44
+ frame: {x: 90, y: 54, w: 18, h: 18},
45
+ sourceSize: {w: 16, h: 16},
46
+ duration: 65535
47
+ },
48
+ 'scenery--Conifer--2': {
49
+ frame: {x: 72, y: 54, w: 18, h: 18},
50
+ sourceSize: {w: 16, h: 16},
51
+ duration: 65535
52
+ },
53
+ 'scenery--ConiferShadow--3': {
54
+ frame: {x: 54, y: 54, w: 18, h: 18},
55
+ sourceSize: {w: 16, h: 16},
56
+ duration: 65535
57
+ },
58
+ 'backpacker--WalkRight--0': {
59
+ frame: {x: 1408, y: 28, w: 8, h: 13},
60
+ sourceSize: {w: 8, h: 13},
61
+ duration: 62
62
+ },
63
+ 'backpacker--WalkRight--1': {
64
+ frame: {x: 1400, y: 28, w: 8, h: 13},
65
+ sourceSize: {w: 8, h: 13},
66
+ duration: 62
67
+ },
68
+ 'backpacker--WalkRight--2': {
69
+ frame: {x: 1392, y: 28, w: 8, h: 13},
70
+ sourceSize: {w: 8, h: 13},
71
+ duration: 62
72
+ },
73
+ 'backpacker--WalkRight--3': {
74
+ frame: {x: 1384, y: 28, w: 8, h: 13},
75
+ sourceSize: {w: 8, h: 13},
76
+ duration: 62
77
+ },
78
+ 'backpacker--WalkRight--4': {
79
+ frame: {x: 1376, y: 28, w: 8, h: 13},
80
+ sourceSize: {w: 8, h: 13},
81
+ duration: 62
82
+ },
83
+ 'backpacker--WalkRight--5': {
84
+ frame: {x: 1416, y: 28, w: 8, h: 13},
85
+ sourceSize: {w: 8, h: 13},
86
+ duration: 62
87
+ },
88
+ 'backpacker--WalkRight--6': {
89
+ frame: {x: 1392, y: 28, w: 8, h: 13},
90
+ sourceSize: {w: 8, h: 13},
91
+ duration: 62
92
+ },
93
+ 'backpacker--WalkRight--7': {
94
+ frame: {x: 1368, y: 28, w: 8, h: 13},
95
+ sourceSize: {w: 8, h: 13},
96
+ duration: 62
97
+ },
98
+ 'backpacker--WalkDown--8': {
99
+ frame: {x: 1360, y: 28, w: 8, h: 13},
100
+ sourceSize: {w: 8, h: 13},
101
+ duration: 62
102
+ }
103
+ }
104
+ const slices = [
105
+ {
106
+ name: 'scenery--Cloud',
107
+ color: '#ff0000ff',
108
+ keys: [{frame: 0, bounds: {x: 8, y: 12, w: 2, h: 3}}]
109
+ },
110
+ {
111
+ name: 'scenery--Cloud',
112
+ color: '#00ff00ff',
113
+ keys: [{frame: 0, bounds: {x: 1, y: 2, w: 3, h: 4}}]
114
+ },
115
+ {
116
+ name: 'palette--red',
117
+ color: '#ff0000ff',
118
+ keys: [{frame: 0, bounds: {x: 7, y: 11, w: 3, h: 4}}]
119
+ },
120
+ {
121
+ name: 'scenery--Conifer',
122
+ color: '#ff0000ff',
123
+ keys: [{frame: 0, bounds: {x: 7, y: 10, w: 3, h: 5}}]
124
+ },
125
+ {
126
+ name: 'scenery--ConiferShadow',
127
+ color: '#ff0000ff',
128
+ keys: [{frame: 0, bounds: {x: 7, y: 9, w: 3, h: 6}}]
129
+ },
130
+ {
131
+ name: 'backpacker--WalkRight',
132
+ color: '#ff0000ff',
133
+ keys: [{frame: 0, bounds: {x: 2, y: 0, w: 4, h: 4}}]
134
+ }
135
+ ]
136
+ assert.deepEqual<AtlasJSON>(
137
+ parseAtlasJSON({meta: {frameTags, size: {w: 0, h: 0}, slices}, frames}),
138
+ {
139
+ anim: {
140
+ 'scenery--Cloud': {
141
+ cels: 1,
142
+ id: 0,
143
+ w: 16,
144
+ h: 16,
145
+ hitbox: {x: 8, y: 12, w: 2, h: 3},
146
+ hurtbox: {x: 1, y: 2, w: 3, h: 4}
147
+ },
148
+ 'palette--red': {
149
+ cels: 1,
150
+ id: 1,
151
+ w: 16,
152
+ h: 16,
153
+ hitbox: {x: 7, y: 11, w: 3, h: 4},
154
+ hurtbox: undefined
155
+ },
156
+ 'scenery--Conifer': {
157
+ cels: 1,
158
+ id: 2,
159
+ w: 16,
160
+ h: 16,
161
+ hitbox: {x: 7, y: 10, w: 3, h: 5},
162
+ hurtbox: undefined
163
+ },
164
+ 'scenery--ConiferShadow': {
165
+ cels: 1,
166
+ id: 3,
167
+ w: 16,
168
+ h: 16,
169
+ hitbox: {x: 7, y: 9, w: 3, h: 6},
170
+ hurtbox: undefined
171
+ },
172
+ 'backpacker--WalkRight': {
173
+ cels: 14,
174
+ id: 4,
175
+ w: 8,
176
+ h: 13,
177
+ hitbox: {x: 2, y: 0, w: 4, h: 4},
178
+ hurtbox: undefined
179
+ }
180
+ },
181
+ celXY: [
182
+ 221, 19, 91, 55, 73, 55, 55, 55, 1408, 28, 1400, 28, 1392, 28, 1384,
183
+ 28, 1376, 28, 1416, 28, 1392, 28, 1368, 28, 1392, 28, 1416, 28, 1376,
184
+ 28, 1384, 28, 1392, 28, 1400, 28
185
+ ]
186
+ }
187
+ )
188
+ })
189
+
190
+ test('throws Error on duplicate FrameTag.', () => {
191
+ const frameTags = [
192
+ {name: 'scenery--Cloud', from: 0, to: 0, direction: 'forward'},
193
+ {name: 'palette--red', from: 1, to: 1, direction: 'forward'},
194
+ {name: 'scenery--Cloud', from: 0, to: 0, direction: 'forward'}
195
+ ]
196
+ const frames = {
197
+ 'scenery--Cloud--0': {
198
+ frame: {x: 220, y: 18, w: 18, h: 18},
199
+ sourceSize: {w: 16, h: 16},
200
+ duration: 1
201
+ },
202
+ 'palette--red--1': {
203
+ frame: {x: 90, y: 54, w: 18, h: 18},
204
+ sourceSize: {w: 16, h: 16},
205
+ duration: 65535
206
+ }
207
+ }
208
+ assert.throws(
209
+ () =>
210
+ parseAtlasJSON({
211
+ meta: {frameTags, size: {w: 0, h: 0}, slices: []},
212
+ frames
213
+ }),
214
+ Error('atlas tag "scenery--Cloud" duplicate')
215
+ )
216
+ })
217
+ })
218
+
219
+ describe('parseAnim()', () => {
220
+ test('parses FrameTag, Frame from Frame[], and Slice.', () => {
221
+ const frameTag: AsepriteTagSpan = {
222
+ direction: 'pingpong',
223
+ name: 'cloud--s',
224
+ from: 1,
225
+ to: 1
226
+ }
227
+ const frames = {
228
+ 'cloud--xs--0': {
229
+ frame: {x: 202, y: 36, w: 18, h: 18},
230
+ sourceSize: {w: 16, h: 16},
231
+ duration: 65535
232
+ },
233
+ 'cloud--s--1': {
234
+ frame: {x: 184, y: 36, w: 18, h: 18},
235
+ sourceSize: {w: 16, h: 16},
236
+ duration: 65535
237
+ },
238
+ 'cloud--m--2': {
239
+ frame: {x: 166, y: 36, w: 18, h: 18},
240
+ sourceSize: {w: 16, h: 16},
241
+ duration: 65535
242
+ }
243
+ }
244
+ const slices = [
245
+ {
246
+ name: 'cloud--xs',
247
+ color: '#ff0000ff',
248
+ keys: [{frame: 0, bounds: {x: 4, y: 12, w: 7, h: 3}}]
249
+ },
250
+ {
251
+ name: 'cloud--s',
252
+ color: '#ff0000ff',
253
+ keys: [{frame: 0, bounds: {x: 4, y: 11, w: 9, h: 4}}]
254
+ },
255
+ {
256
+ name: 'cloud--m',
257
+ color: '#ff0000ff',
258
+ keys: [{frame: 0, bounds: {x: 3, y: 11, w: 10, h: 4}}]
259
+ }
260
+ ]
261
+ assert.deepEqual<Anim>(parseAnim(16, frameTag, frames, slices), {
262
+ cels: 1,
263
+ id: 16,
264
+ w: 16,
265
+ h: 16,
266
+ hitbox: {x: 4, y: 11, w: 9, h: 4},
267
+ hurtbox: undefined
268
+ })
269
+ })
270
+
271
+ test('throws error when no frame is associated with tag.', () => {
272
+ const frameTag: AsepriteTagSpan = {
273
+ direction: 'pingpong',
274
+ name: 'frog--walk',
275
+ from: 0,
276
+ to: 0
277
+ }
278
+ assert.throws(
279
+ () => parseAnim(16, frameTag, {}, []),
280
+ Error('no atlas frame "frog--walk--0"')
281
+ )
282
+ })
283
+ })
284
+
285
+ describe('parseAnimFrames()', () => {
286
+ test('single cell', () => {
287
+ for (const direction of Object.values(AsepriteDirection)) {
288
+ const span: AsepriteTagSpan = {
289
+ direction,
290
+ name: 'stem--foo',
291
+ from: 0,
292
+ to: 0
293
+ }
294
+ const map: AsepriteFrameMap = {
295
+ 'stem--foo--0': {
296
+ duration: 1,
297
+ frame: {x: 0, y: 0, w: 0, h: 0},
298
+ sourceSize: {w: 0, h: 0}
299
+ }
300
+ }
301
+ assertAnimFrames(span, map, [0], direction)
302
+ }
303
+ })
304
+
305
+ test('full anim', () => {
306
+ const expected: {[dir in AsepriteDirection]: number[]} = {
307
+ forward: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
308
+ pingpong: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
309
+ pingpong_reverse: [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
310
+ reverse: [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
311
+ }
312
+ for (const direction of Object.values(AsepriteDirection)) {
313
+ const span: AsepriteTagSpan = {
314
+ direction,
315
+ name: 'stem--foo',
316
+ from: 0,
317
+ to: 15
318
+ }
319
+ const map: AsepriteFrameMap = {
320
+ 'stem--foo--0': {
321
+ duration: 1,
322
+ frame: {x: 0, y: 0, w: 0, h: 0},
323
+ sourceSize: {w: 0, h: 0}
324
+ },
325
+ 'stem--foo--1': {
326
+ duration: 1,
327
+ frame: {x: 0, y: 0, w: 0, h: 0},
328
+ sourceSize: {w: 0, h: 0}
329
+ },
330
+ 'stem--foo--2': {
331
+ duration: 1,
332
+ frame: {x: 0, y: 0, w: 0, h: 0},
333
+ sourceSize: {w: 0, h: 0}
334
+ },
335
+ 'stem--foo--3': {
336
+ duration: 1,
337
+ frame: {x: 0, y: 0, w: 0, h: 0},
338
+ sourceSize: {w: 0, h: 0}
339
+ },
340
+ 'stem--foo--4': {
341
+ duration: 1,
342
+ frame: {x: 0, y: 0, w: 0, h: 0},
343
+ sourceSize: {w: 0, h: 0}
344
+ },
345
+ 'stem--foo--5': {
346
+ duration: 1,
347
+ frame: {x: 0, y: 0, w: 0, h: 0},
348
+ sourceSize: {w: 0, h: 0}
349
+ },
350
+ 'stem--foo--6': {
351
+ duration: 1,
352
+ frame: {x: 0, y: 0, w: 0, h: 0},
353
+ sourceSize: {w: 0, h: 0}
354
+ },
355
+ 'stem--foo--7': {
356
+ duration: 1,
357
+ frame: {x: 0, y: 0, w: 0, h: 0},
358
+ sourceSize: {w: 0, h: 0}
359
+ },
360
+ 'stem--foo--8': {
361
+ duration: 1,
362
+ frame: {x: 0, y: 0, w: 0, h: 0},
363
+ sourceSize: {w: 0, h: 0}
364
+ },
365
+ 'stem--foo--9': {
366
+ duration: 1,
367
+ frame: {x: 0, y: 0, w: 0, h: 0},
368
+ sourceSize: {w: 0, h: 0}
369
+ },
370
+ 'stem--foo--10': {
371
+ duration: 1,
372
+ frame: {x: 0, y: 0, w: 0, h: 0},
373
+ sourceSize: {w: 0, h: 0}
374
+ },
375
+ 'stem--foo--11': {
376
+ duration: 1,
377
+ frame: {x: 0, y: 0, w: 0, h: 0},
378
+ sourceSize: {w: 0, h: 0}
379
+ },
380
+ 'stem--foo--12': {
381
+ duration: 1,
382
+ frame: {x: 0, y: 0, w: 0, h: 0},
383
+ sourceSize: {w: 0, h: 0}
384
+ },
385
+ 'stem--foo--13': {
386
+ duration: 1,
387
+ frame: {x: 0, y: 0, w: 0, h: 0},
388
+ sourceSize: {w: 0, h: 0}
389
+ },
390
+ 'stem--foo--14': {
391
+ duration: 1,
392
+ frame: {x: 0, y: 0, w: 0, h: 0},
393
+ sourceSize: {w: 0, h: 0}
394
+ },
395
+ 'stem--foo--15': {
396
+ duration: 1,
397
+ frame: {x: 0, y: 0, w: 0, h: 0},
398
+ sourceSize: {w: 0, h: 0}
399
+ }
400
+ }
401
+ assertAnimFrames(span, map, expected[direction], direction)
402
+ }
403
+ })
404
+
405
+ test('short anim', () => {
406
+ const expected: {[dir in AsepriteDirection]: number[]} = {
407
+ forward: [0, 1, 2],
408
+ pingpong: [0, 1, 2, 1],
409
+ pingpong_reverse: [2, 1, 0, 1],
410
+ reverse: [2, 1, 0]
411
+ }
412
+ for (const direction of Object.values(AsepriteDirection)) {
413
+ const span: AsepriteTagSpan = {
414
+ direction,
415
+ name: 'stem--foo',
416
+ from: 0,
417
+ to: 2
418
+ }
419
+ const map: AsepriteFrameMap = {
420
+ 'stem--foo--0': {
421
+ duration: 1,
422
+ frame: {x: 0, y: 0, w: 0, h: 0},
423
+ sourceSize: {w: 0, h: 0}
424
+ },
425
+ 'stem--foo--1': {
426
+ duration: 1,
427
+ frame: {x: 0, y: 0, w: 0, h: 0},
428
+ sourceSize: {w: 0, h: 0}
429
+ },
430
+ 'stem--foo--2': {
431
+ duration: 1,
432
+ frame: {x: 0, y: 0, w: 0, h: 0},
433
+ sourceSize: {w: 0, h: 0}
434
+ }
435
+ }
436
+ assertAnimFrames(span, map, expected[direction], direction)
437
+ }
438
+ })
439
+
440
+ test('short anim with another anim', () => {
441
+ const expected: {[dir in AsepriteDirection]: number[]} = {
442
+ forward: [1, 2, 3],
443
+ pingpong: [1, 2, 3, 2],
444
+ pingpong_reverse: [3, 2, 1, 2],
445
+ reverse: [3, 2, 1]
446
+ }
447
+ for (const direction of Object.values(AsepriteDirection)) {
448
+ const span: AsepriteTagSpan = {
449
+ direction,
450
+ name: 'stem--bar',
451
+ from: 1,
452
+ to: 3
453
+ }
454
+ const map: AsepriteFrameMap = {
455
+ 'stem--foo--0': {
456
+ duration: 1,
457
+ frame: {x: 0, y: 0, w: 0, h: 0},
458
+ sourceSize: {w: 0, h: 0}
459
+ },
460
+ 'stem--bar--1': {
461
+ duration: 1,
462
+ frame: {x: 0, y: 0, w: 0, h: 0},
463
+ sourceSize: {w: 0, h: 0}
464
+ },
465
+ 'stem--bar--2': {
466
+ duration: 1,
467
+ frame: {x: 0, y: 0, w: 0, h: 0},
468
+ sourceSize: {w: 0, h: 0}
469
+ },
470
+ 'stem--bar--3': {
471
+ duration: 1,
472
+ frame: {x: 0, y: 0, w: 0, h: 0},
473
+ sourceSize: {w: 0, h: 0}
474
+ }
475
+ }
476
+ assertAnimFrames(span, map, expected[direction], direction)
477
+ }
478
+ })
479
+
480
+ test('short anim with multi-cel durations', () => {
481
+ const expected: {[dir in AsepriteDirection]: number[]} = {
482
+ forward: [0, 1, 1, 2],
483
+ pingpong: [0, 1, 1, 2, 1, 1],
484
+ pingpong_reverse: [2, 1, 1, 0, 1, 1],
485
+ reverse: [2, 1, 1, 0]
486
+ }
487
+ for (const direction of Object.values(AsepriteDirection)) {
488
+ const span: AsepriteTagSpan = {
489
+ direction,
490
+ name: 'stem--foo',
491
+ from: 0,
492
+ to: 2
493
+ }
494
+ const map: AsepriteFrameMap = {
495
+ 'stem--foo--0': {
496
+ duration: 1,
497
+ frame: {x: 0, y: 0, w: 0, h: 0},
498
+ sourceSize: {w: 0, h: 0}
499
+ },
500
+ 'stem--foo--1': {
501
+ duration: 63,
502
+ frame: {x: 0, y: 0, w: 0, h: 0},
503
+ sourceSize: {w: 0, h: 0}
504
+ },
505
+ 'stem--foo--2': {
506
+ duration: 1,
507
+ frame: {x: 0, y: 0, w: 0, h: 0},
508
+ sourceSize: {w: 0, h: 0}
509
+ }
510
+ }
511
+ assertAnimFrames(span, map, expected[direction], direction)
512
+ }
513
+ })
514
+ })
515
+
516
+ describe('parseCel()', () => {
517
+ test('parses 1:1 texture mapping/', () => {
518
+ const frame = {
519
+ frame: {x: 1, y: 2, w: 3, h: 4},
520
+ rotated: false,
521
+ trimmed: false,
522
+ sourceSize: {w: 3, h: 4},
523
+ duration: 1
524
+ }
525
+ assert.deepEqual<XY>(parseCel(frame), {x: 1, y: 2})
526
+ })
527
+
528
+ test('parses texture mapping with padding', () => {
529
+ const frame = {
530
+ frame: {x: 1, y: 2, w: 5, h: 6},
531
+ rotated: false,
532
+ trimmed: false,
533
+ sourceSize: {w: 3, h: 4},
534
+ duration: 1
535
+ }
536
+ assert.deepEqual<XY>(parseCel(frame), {x: 2, y: 3})
537
+ })
538
+ })
539
+
540
+ describe('parseHitboxes()', () => {
541
+ test('parses hitbox.', () => {
542
+ const span: AsepriteTagSpan = {
543
+ direction: 'pingpong',
544
+ name: 'stem--foo',
545
+ from: 0,
546
+ to: 0
547
+ }
548
+ const slices = [
549
+ {
550
+ name: 'stem--foo',
551
+ color: '#ff0000ff',
552
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
553
+ }
554
+ ]
555
+ assert.deepEqual(parseHitboxes(span, slices), {
556
+ hitbox: {x: 0, y: 1, w: 2, h: 3},
557
+ hurtbox: undefined
558
+ })
559
+ })
560
+
561
+ test('parses hurtbox.', () => {
562
+ const span: AsepriteTagSpan = {
563
+ direction: 'pingpong',
564
+ name: 'stem--foo',
565
+ from: 0,
566
+ to: 0
567
+ }
568
+ const slices = [
569
+ {
570
+ name: 'stem--foo',
571
+ color: '#00ff00ff',
572
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
573
+ }
574
+ ]
575
+ assert.deepEqual(parseHitboxes(span, slices), {
576
+ hitbox: undefined,
577
+ hurtbox: {x: 0, y: 1, w: 2, h: 3}
578
+ })
579
+ })
580
+
581
+ test('parses hitbox and hurtbox (blue).', () => {
582
+ const span: AsepriteTagSpan = {
583
+ direction: 'pingpong',
584
+ name: 'stem--foo',
585
+ from: 0,
586
+ to: 0
587
+ }
588
+ const slices = [
589
+ {
590
+ name: 'stem--foo',
591
+ color: '#0000ffff',
592
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
593
+ }
594
+ ]
595
+ assert.deepEqual(parseHitboxes(span, slices), {
596
+ hitbox: {x: 0, y: 1, w: 2, h: 3},
597
+ hurtbox: {x: 0, y: 1, w: 2, h: 3}
598
+ })
599
+ })
600
+
601
+ test('parses hitbox and hurtbox.', () => {
602
+ const span: AsepriteTagSpan = {
603
+ direction: 'pingpong',
604
+ name: 'stem--foo',
605
+ from: 0,
606
+ to: 0
607
+ }
608
+ const slices = [
609
+ {
610
+ name: 'stem--foo',
611
+ color: '#ff0000ff',
612
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
613
+ },
614
+ {
615
+ name: 'stem--foo',
616
+ color: '#00ff00ff',
617
+ keys: [{frame: 0, bounds: {x: 4, y: 5, w: 6, h: 7}}]
618
+ }
619
+ ]
620
+ assert.deepEqual(parseHitboxes(span, slices), {
621
+ hitbox: {x: 0, y: 1, w: 2, h: 3},
622
+ hurtbox: {x: 4, y: 5, w: 6, h: 7}
623
+ })
624
+ })
625
+
626
+ test('filters out unrelated tags.', () => {
627
+ const span: AsepriteTagSpan = {
628
+ direction: 'pingpong',
629
+ name: 'stem--foo',
630
+ from: 0,
631
+ to: 0
632
+ }
633
+ const slices = [
634
+ {
635
+ name: 'unrelated--bar',
636
+ color: '#ff0000ff',
637
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
638
+ },
639
+ {
640
+ name: 'stem--foo',
641
+ color: '#ff0000ff',
642
+ keys: [{frame: 0, bounds: {x: 4, y: 5, w: 6, h: 7}}]
643
+ }
644
+ ]
645
+ assert.deepEqual(parseHitboxes(span, slices), {
646
+ hitbox: {x: 4, y: 5, w: 6, h: 7},
647
+ hurtbox: undefined
648
+ })
649
+ })
650
+
651
+ test('throws on frame with multiple keys.', () => {
652
+ const span: AsepriteTagSpan = {
653
+ direction: 'pingpong',
654
+ name: 'stem--foo',
655
+ from: 0,
656
+ to: 2
657
+ }
658
+ const slices = [
659
+ {
660
+ name: 'stem--foo',
661
+ color: '0000ffff',
662
+ keys: [
663
+ {frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}},
664
+ {frame: 1, bounds: {x: 4, y: 5, w: 6, h: 7}},
665
+ {frame: 2, bounds: {x: 8, y: 9, w: 10, h: 11}}
666
+ ]
667
+ }
668
+ ]
669
+ assert.throws(
670
+ () => parseHitboxes(span, slices),
671
+ Error('atlas tag "stem--foo" hitbox bounds varies across frames')
672
+ )
673
+ })
674
+
675
+ test('defaults to undefined hitbox.', () => {
676
+ const span: AsepriteTagSpan = {
677
+ direction: 'pingpong',
678
+ name: 'stem--foo',
679
+ from: 0,
680
+ to: 0
681
+ }
682
+ assert.deepEqual(parseHitboxes(span, []), {
683
+ hitbox: undefined,
684
+ hurtbox: undefined
685
+ })
686
+ })
687
+
688
+ test('throws on unsupported color.', () => {
689
+ const span: AsepriteTagSpan = {
690
+ direction: 'pingpong',
691
+ name: 'stem--foo',
692
+ from: 0,
693
+ to: 0
694
+ }
695
+ const slices = [
696
+ {
697
+ name: 'stem--foo',
698
+ color: '#ff00ffff',
699
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
700
+ }
701
+ ]
702
+ assert.throws(
703
+ () => parseHitboxes(span, slices),
704
+ Error('atlas tag "stem--foo" hitbox color #ff00ffff unsupported')
705
+ )
706
+ })
707
+
708
+ test('throws on multiple hitboxes.', () => {
709
+ const span: AsepriteTagSpan = {
710
+ direction: 'pingpong',
711
+ name: 'stem--foo',
712
+ from: 0,
713
+ to: 1
714
+ }
715
+ const slices = [
716
+ {
717
+ name: 'stem--foo',
718
+ color: '#ff0000ff',
719
+ keys: [
720
+ {frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}},
721
+ {frame: 1, bounds: {x: 4, y: 5, w: 6, h: 7}},
722
+ {frame: 2, bounds: {x: 12, y: 13, w: 14, h: 15}}
723
+ ]
724
+ },
725
+ {
726
+ name: 'stem--foo',
727
+ color: '#ff0000ff',
728
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
729
+ }
730
+ ]
731
+ assert.throws(
732
+ () => parseHitboxes(span, slices),
733
+ Error('atlas tag "stem--foo" hitbox bounds varies across frames')
734
+ )
735
+ })
736
+
737
+ test('throws on multiple hurtboxes.', () => {
738
+ const span: AsepriteTagSpan = {
739
+ direction: 'pingpong',
740
+ name: 'stem--foo',
741
+ from: 0,
742
+ to: 1
743
+ }
744
+ const slices = [
745
+ {
746
+ name: 'stem--foo',
747
+ color: '#00ff00ff',
748
+ keys: [
749
+ {frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}},
750
+ {frame: 1, bounds: {x: 4, y: 5, w: 6, h: 7}},
751
+ {frame: 2, bounds: {x: 12, y: 13, w: 14, h: 15}}
752
+ ]
753
+ },
754
+ {
755
+ name: 'stem--foo',
756
+ color: '#00ff00ff',
757
+ keys: [{frame: 0, bounds: {x: 0, y: 1, w: 2, h: 3}}]
758
+ }
759
+ ]
760
+ assert.throws(
761
+ () => parseHitboxes(span, slices),
762
+ Error('atlas tag "stem--foo" hitbox bounds varies across frames')
763
+ )
764
+ })
765
+ })
766
+
767
+ function assertAnimFrames(
768
+ span: Readonly<AsepriteTagSpan>,
769
+ map: Readonly<AsepriteFrameMap>,
770
+ expected: number[],
771
+ msg?: string | undefined
772
+ ): void {
773
+ assert.deepEqual(
774
+ [...parseAnimFrames(span, map)].map(frame =>
775
+ Object.values(map).indexOf(frame)
776
+ ),
777
+ expected,
778
+ msg
779
+ )
780
+ }