@origingame/create-game 0.0.0-stage → 0.1.0

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 (581) hide show
  1. package/README.md +57 -2
  2. package/archetypes/README.md +99 -0
  3. package/archetypes/idle/.origin/setup +14 -0
  4. package/archetypes/idle/LICENSES.md +12 -0
  5. package/archetypes/idle/README.md +234 -0
  6. package/archetypes/idle/assets/audio/buy.wav +0 -0
  7. package/archetypes/idle/assets/audio/milestone.wav +0 -0
  8. package/archetypes/idle/assets/audio/nova.wav +0 -0
  9. package/archetypes/idle/assets/audio/orbit.wav +0 -0
  10. package/archetypes/idle/assets/audio/tap.wav +0 -0
  11. package/archetypes/idle/assets/audio/ui-close.ogt +9 -0
  12. package/archetypes/idle/assets/audio/ui-error.ogt +9 -0
  13. package/archetypes/idle/assets/audio/ui-open.ogt +9 -0
  14. package/archetypes/idle/assets/audio/ui-press.ogt +9 -0
  15. package/archetypes/idle/assets/audio/ui-success.ogt +9 -0
  16. package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf +0 -0
  17. package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
  18. package/archetypes/idle/assets/fonts/OFL.txt +93 -0
  19. package/archetypes/idle/assets/fx/drift.ogt +21 -0
  20. package/archetypes/idle/assets/fx/milestone.ogt +21 -0
  21. package/archetypes/idle/assets/fx/nova.ogt +22 -0
  22. package/archetypes/idle/assets/fx/stars.ogt +20 -0
  23. package/archetypes/idle/assets/fx/tap.ogt +23 -0
  24. package/archetypes/idle/assets/looks/idle.ogt +17 -0
  25. package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf +0 -0
  26. package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf.ogt +9 -0
  27. package/archetypes/idle/assets/skins/sparkorb/LICENSES.md +19 -0
  28. package/archetypes/idle/assets/skins/sparkorb/OFL.txt +95 -0
  29. package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf +0 -0
  30. package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf.ogt +9 -0
  31. package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf +0 -0
  32. package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf.ogt +9 -0
  33. package/archetypes/idle/assets/skins/sparkorb/atlas.png +0 -0
  34. package/archetypes/idle/assets/skins/sparkorb/atlas.png.ogt +7 -0
  35. package/archetypes/idle/assets/skins/sparkorb/icons.png +0 -0
  36. package/archetypes/idle/assets/skins/sparkorb/icons.png.ogt +7 -0
  37. package/archetypes/idle/assets/skins/sparkorb/skin.ogt +113 -0
  38. package/archetypes/idle/assets/sprites/glow.png +0 -0
  39. package/archetypes/idle/assets/sprites/glow.png.ogt +8 -0
  40. package/archetypes/idle/assets/sprites/mote-crystal.png +0 -0
  41. package/archetypes/idle/assets/sprites/mote-crystal.png.ogt +7 -0
  42. package/archetypes/idle/assets/sprites/mote-ember.png +0 -0
  43. package/archetypes/idle/assets/sprites/mote-ember.png.ogt +7 -0
  44. package/archetypes/idle/assets/sprites/mote-star.png +0 -0
  45. package/archetypes/idle/assets/sprites/mote-star.png.ogt +7 -0
  46. package/archetypes/idle/assets/sprites/mote-storm.png +0 -0
  47. package/archetypes/idle/assets/sprites/mote-storm.png.ogt +7 -0
  48. package/archetypes/idle/assets/sprites/orb.png +0 -0
  49. package/archetypes/idle/assets/sprites/orb.png.ogt +7 -0
  50. package/archetypes/idle/assets/sprites/spark.png +0 -0
  51. package/archetypes/idle/assets/sprites/spark.png.ogt +7 -0
  52. package/archetypes/idle/assets/strings/en.ogt +62 -0
  53. package/archetypes/idle/assets/strings/zh-CN.ogt +62 -0
  54. package/archetypes/idle/gitattributes +22 -0
  55. package/archetypes/idle/host.d.ts +46 -0
  56. package/archetypes/idle/package.json +18 -0
  57. package/archetypes/idle/project.ogt +14 -0
  58. package/archetypes/idle/references/metal/card.png +0 -0
  59. package/archetypes/idle/references/metal/orbit.png +0 -0
  60. package/archetypes/idle/references/metal/title.png +0 -0
  61. package/archetypes/idle/src/components.ts +139 -0
  62. package/archetypes/idle/src/main.ts +247 -0
  63. package/archetypes/idle/src/numbers.ts +126 -0
  64. package/archetypes/idle/src/systems.ts +340 -0
  65. package/archetypes/idle/src/ui.ts +412 -0
  66. package/archetypes/idle/tests/away.og.ts +42 -0
  67. package/archetypes/idle/tests/flow.og.ts +57 -0
  68. package/archetypes/idle/tests/frames.og.ts +33 -0
  69. package/archetypes/idle/tests/frames.ts +134 -0
  70. package/archetypes/idle/tests/lib.ts +74 -0
  71. package/archetypes/idle/tests/milestone.og.ts +32 -0
  72. package/archetypes/idle/tests/nova.og.ts +52 -0
  73. package/archetypes/idle/tests/offline.og.ts +60 -0
  74. package/archetypes/idle/tests/pad.og.ts +55 -0
  75. package/archetypes/idle/tests/pause.og.ts +68 -0
  76. package/archetypes/idle/tests/phone.og.ts +50 -0
  77. package/archetypes/idle/tests/replay.og.ts +28 -0
  78. package/archetypes/idle/tools/make-assets.py +448 -0
  79. package/archetypes/idle/tools/oglite.py +285 -0
  80. package/archetypes/idle/tsconfig.json +17 -0
  81. package/archetypes/match3/.origin/setup +14 -0
  82. package/archetypes/match3/LICENSES.md +7 -0
  83. package/archetypes/match3/README.md +205 -0
  84. package/archetypes/match3/assets/audio/cascade.wav +0 -0
  85. package/archetypes/match3/assets/audio/clear.wav +0 -0
  86. package/archetypes/match3/assets/audio/lost.wav +0 -0
  87. package/archetypes/match3/assets/audio/refused.wav +0 -0
  88. package/archetypes/match3/assets/audio/select.wav +0 -0
  89. package/archetypes/match3/assets/audio/swap.wav +0 -0
  90. package/archetypes/match3/assets/audio/won.wav +0 -0
  91. package/archetypes/match3/assets/fonts/OFL.txt +93 -0
  92. package/archetypes/match3/assets/fonts/ui.ttf +0 -0
  93. package/archetypes/match3/assets/fonts/ui.ttf.ogt +11 -0
  94. package/archetypes/match3/assets/scenes/main.ogt +24 -0
  95. package/archetypes/match3/assets/sprites/backdrop.png +0 -0
  96. package/archetypes/match3/assets/sprites/board.ogt +21 -0
  97. package/archetypes/match3/assets/sprites/cells.ogt +7 -0
  98. package/archetypes/match3/assets/sprites/cells.png +0 -0
  99. package/archetypes/match3/assets/sprites/cells.png.ogt +7 -0
  100. package/archetypes/match3/assets/sprites/gems.ogt +75 -0
  101. package/archetypes/match3/assets/sprites/gems.png +0 -0
  102. package/archetypes/match3/assets/sprites/panel.png +0 -0
  103. package/archetypes/match3/assets/sprites/ring.png +0 -0
  104. package/archetypes/match3/gitattributes +22 -0
  105. package/archetypes/match3/host.d.ts +46 -0
  106. package/archetypes/match3/package.json +18 -0
  107. package/archetypes/match3/project.ogt +18 -0
  108. package/archetypes/match3/references/metal/cascade.png +0 -0
  109. package/archetypes/match3/references/metal/clearing.png +0 -0
  110. package/archetypes/match3/references/metal/dealt.png +0 -0
  111. package/archetypes/match3/src/art.ts +54 -0
  112. package/archetypes/match3/src/board.ts +112 -0
  113. package/archetypes/match3/src/components.ts +95 -0
  114. package/archetypes/match3/src/layout.ts +25 -0
  115. package/archetypes/match3/src/main.ts +199 -0
  116. package/archetypes/match3/src/systems.ts +631 -0
  117. package/archetypes/match3/tests/drag.og.ts +31 -0
  118. package/archetypes/match3/tests/endings.og.ts +40 -0
  119. package/archetypes/match3/tests/frames.og.ts +49 -0
  120. package/archetypes/match3/tests/frames.ts +134 -0
  121. package/archetypes/match3/tests/hidpi.og.ts +41 -0
  122. package/archetypes/match3/tests/lib.ts +64 -0
  123. package/archetypes/match3/tests/replay.og.ts +28 -0
  124. package/archetypes/match3/tests/sounds.og.ts +50 -0
  125. package/archetypes/match3/tests/swap.og.ts +67 -0
  126. package/archetypes/match3/tools/make-assets.py +404 -0
  127. package/archetypes/match3/tools/oglite.py +285 -0
  128. package/archetypes/match3/tsconfig.json +17 -0
  129. package/archetypes/rhythm/.origin/setup +14 -0
  130. package/archetypes/rhythm/LICENSES.md +13 -0
  131. package/archetypes/rhythm/README.md +235 -0
  132. package/archetypes/rhythm/assets/audio/bass0.wav +0 -0
  133. package/archetypes/rhythm/assets/audio/bass1.wav +0 -0
  134. package/archetypes/rhythm/assets/audio/bass2.wav +0 -0
  135. package/archetypes/rhythm/assets/audio/bass3.wav +0 -0
  136. package/archetypes/rhythm/assets/audio/chords0.wav +0 -0
  137. package/archetypes/rhythm/assets/audio/chords1.wav +0 -0
  138. package/archetypes/rhythm/assets/audio/chords2.wav +0 -0
  139. package/archetypes/rhythm/assets/audio/chords3.wav +0 -0
  140. package/archetypes/rhythm/assets/audio/clear.wav +0 -0
  141. package/archetypes/rhythm/assets/audio/click.wav +0 -0
  142. package/archetypes/rhythm/assets/audio/drums.wav +0 -0
  143. package/archetypes/rhythm/assets/audio/fail.wav +0 -0
  144. package/archetypes/rhythm/assets/audio/leadA.wav +0 -0
  145. package/archetypes/rhythm/assets/audio/leadB.wav +0 -0
  146. package/archetypes/rhythm/assets/audio/miss.wav +0 -0
  147. package/archetypes/rhythm/assets/audio/tap0.wav +0 -0
  148. package/archetypes/rhythm/assets/audio/tap1.wav +0 -0
  149. package/archetypes/rhythm/assets/audio/tap2.wav +0 -0
  150. package/archetypes/rhythm/assets/audio/ui-close.ogt +9 -0
  151. package/archetypes/rhythm/assets/audio/ui-error.ogt +9 -0
  152. package/archetypes/rhythm/assets/audio/ui-open.ogt +9 -0
  153. package/archetypes/rhythm/assets/audio/ui-press.ogt +9 -0
  154. package/archetypes/rhythm/assets/audio/ui-success.ogt +9 -0
  155. package/archetypes/rhythm/assets/charts/neon-pulse.ogt +919 -0
  156. package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf +0 -0
  157. package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
  158. package/archetypes/rhythm/assets/fonts/OFL.txt +93 -0
  159. package/archetypes/rhythm/assets/fx/hit.ogt +22 -0
  160. package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf +0 -0
  161. package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf.ogt +9 -0
  162. package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf +0 -0
  163. package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf.ogt +9 -0
  164. package/archetypes/rhythm/assets/skins/lanebeat/LICENSES.md +17 -0
  165. package/archetypes/rhythm/assets/skins/lanebeat/OFL.txt +95 -0
  166. package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf +0 -0
  167. package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf.ogt +9 -0
  168. package/archetypes/rhythm/assets/skins/lanebeat/atlas.png +0 -0
  169. package/archetypes/rhythm/assets/skins/lanebeat/atlas.png.ogt +7 -0
  170. package/archetypes/rhythm/assets/skins/lanebeat/icons.png +0 -0
  171. package/archetypes/rhythm/assets/skins/lanebeat/icons.png.ogt +7 -0
  172. package/archetypes/rhythm/assets/skins/lanebeat/skin.ogt +110 -0
  173. package/archetypes/rhythm/assets/sprites/lane.png +0 -0
  174. package/archetypes/rhythm/assets/sprites/lane.png.ogt +7 -0
  175. package/archetypes/rhythm/assets/sprites/note.png +0 -0
  176. package/archetypes/rhythm/assets/sprites/note.png.ogt +7 -0
  177. package/archetypes/rhythm/assets/sprites/ring.png +0 -0
  178. package/archetypes/rhythm/assets/sprites/ring.png.ogt +7 -0
  179. package/archetypes/rhythm/assets/sprites/spark.png +0 -0
  180. package/archetypes/rhythm/assets/sprites/spark.png.ogt +7 -0
  181. package/archetypes/rhythm/assets/strings/en.ogt +61 -0
  182. package/archetypes/rhythm/assets/strings/zh-CN.ogt +61 -0
  183. package/archetypes/rhythm/gitattributes +22 -0
  184. package/archetypes/rhythm/host.d.ts +46 -0
  185. package/archetypes/rhythm/package.json +18 -0
  186. package/archetypes/rhythm/project.ogt +14 -0
  187. package/archetypes/rhythm/references/metal/highway.png +0 -0
  188. package/archetypes/rhythm/references/metal/results.png +0 -0
  189. package/archetypes/rhythm/references/metal/title.png +0 -0
  190. package/archetypes/rhythm/src/components.ts +147 -0
  191. package/archetypes/rhythm/src/main.ts +202 -0
  192. package/archetypes/rhythm/src/systems.ts +490 -0
  193. package/archetypes/rhythm/src/ui.ts +421 -0
  194. package/archetypes/rhythm/tests/band.og.ts +45 -0
  195. package/archetypes/rhythm/tests/calibrate.og.ts +49 -0
  196. package/archetypes/rhythm/tests/clear.og.ts +51 -0
  197. package/archetypes/rhythm/tests/fail.og.ts +40 -0
  198. package/archetypes/rhythm/tests/flow.og.ts +54 -0
  199. package/archetypes/rhythm/tests/frames.og.ts +35 -0
  200. package/archetypes/rhythm/tests/frames.ts +134 -0
  201. package/archetypes/rhythm/tests/lib.ts +123 -0
  202. package/archetypes/rhythm/tests/pad.og.ts +41 -0
  203. package/archetypes/rhythm/tests/pause.og.ts +77 -0
  204. package/archetypes/rhythm/tests/phone.og.ts +44 -0
  205. package/archetypes/rhythm/tests/replay.og.ts +27 -0
  206. package/archetypes/rhythm/tests/timing.og.ts +37 -0
  207. package/archetypes/rhythm/tools/make-assets.py +383 -0
  208. package/archetypes/rhythm/tools/oglite.py +285 -0
  209. package/archetypes/rhythm/tsconfig.json +17 -0
  210. package/archetypes/roguelike/.origin/setup +14 -0
  211. package/archetypes/roguelike/LICENSES.md +14 -0
  212. package/archetypes/roguelike/README.md +256 -0
  213. package/archetypes/roguelike/assets/ai/foe.ogt +28 -0
  214. package/archetypes/roguelike/assets/ai/guardian.ogt +26 -0
  215. package/archetypes/roguelike/assets/audio/bump.wav +0 -0
  216. package/archetypes/roguelike/assets/audio/drink.wav +0 -0
  217. package/archetypes/roguelike/assets/audio/fall.wav +0 -0
  218. package/archetypes/roguelike/assets/audio/hit.wav +0 -0
  219. package/archetypes/roguelike/assets/audio/hurt.wav +0 -0
  220. package/archetypes/roguelike/assets/audio/item.wav +0 -0
  221. package/archetypes/roguelike/assets/audio/kill.wav +0 -0
  222. package/archetypes/roguelike/assets/audio/pickup.wav +0 -0
  223. package/archetypes/roguelike/assets/audio/roar.wav +0 -0
  224. package/archetypes/roguelike/assets/audio/stairs.wav +0 -0
  225. package/archetypes/roguelike/assets/audio/step.ogt +9 -0
  226. package/archetypes/roguelike/assets/audio/telegraph.wav +0 -0
  227. package/archetypes/roguelike/assets/audio/tomb.wav +0 -0
  228. package/archetypes/roguelike/assets/audio/ui-close.ogt +9 -0
  229. package/archetypes/roguelike/assets/audio/ui-error.ogt +9 -0
  230. package/archetypes/roguelike/assets/audio/ui-open.ogt +9 -0
  231. package/archetypes/roguelike/assets/audio/ui-press.ogt +9 -0
  232. package/archetypes/roguelike/assets/audio/ui-success.ogt +9 -0
  233. package/archetypes/roguelike/assets/audio/won.wav +0 -0
  234. package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf +0 -0
  235. package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
  236. package/archetypes/roguelike/assets/fonts/OFL.txt +93 -0
  237. package/archetypes/roguelike/assets/maps/dive.ogt +106 -0
  238. package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf +0 -0
  239. package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf.ogt +9 -0
  240. package/archetypes/roguelike/assets/skins/lampdive/LICENSES.md +16 -0
  241. package/archetypes/roguelike/assets/skins/lampdive/OFL.txt +93 -0
  242. package/archetypes/roguelike/assets/skins/lampdive/atlas.png +0 -0
  243. package/archetypes/roguelike/assets/skins/lampdive/atlas.png.ogt +7 -0
  244. package/archetypes/roguelike/assets/skins/lampdive/icons.png +0 -0
  245. package/archetypes/roguelike/assets/skins/lampdive/icons.png.ogt +7 -0
  246. package/archetypes/roguelike/assets/skins/lampdive/skin.ogt +115 -0
  247. package/archetypes/roguelike/assets/sprites/dive.ogt +50 -0
  248. package/archetypes/roguelike/assets/sprites/dive.png +0 -0
  249. package/archetypes/roguelike/assets/sprites/dive.png.ogt +7 -0
  250. package/archetypes/roguelike/assets/sprites/glow.png +0 -0
  251. package/archetypes/roguelike/assets/sprites/glow.png.ogt +7 -0
  252. package/archetypes/roguelike/assets/strings/en.ogt +57 -0
  253. package/archetypes/roguelike/assets/strings/zh-CN.ogt +57 -0
  254. package/archetypes/roguelike/assets/tiles/tomb.ogt +31 -0
  255. package/archetypes/roguelike/assets/tiles/tomb.png +0 -0
  256. package/archetypes/roguelike/assets/tiles/tomb.png.ogt +7 -0
  257. package/archetypes/roguelike/gitattributes +22 -0
  258. package/archetypes/roguelike/host.d.ts +46 -0
  259. package/archetypes/roguelike/package.json +18 -0
  260. package/archetypes/roguelike/project.ogt +14 -0
  261. package/archetypes/roguelike/references/metal/dive.png +0 -0
  262. package/archetypes/roguelike/references/metal/over.png +0 -0
  263. package/archetypes/roguelike/references/metal/title.png +0 -0
  264. package/archetypes/roguelike/src/art.ts +23 -0
  265. package/archetypes/roguelike/src/components.ts +169 -0
  266. package/archetypes/roguelike/src/dive.ts +144 -0
  267. package/archetypes/roguelike/src/foes.ts +174 -0
  268. package/archetypes/roguelike/src/main.ts +258 -0
  269. package/archetypes/roguelike/src/systems.ts +620 -0
  270. package/archetypes/roguelike/src/ui.ts +350 -0
  271. package/archetypes/roguelike/tests/flow.og.ts +54 -0
  272. package/archetypes/roguelike/tests/foes.og.ts +45 -0
  273. package/archetypes/roguelike/tests/frames.og.ts +32 -0
  274. package/archetypes/roguelike/tests/frames.ts +134 -0
  275. package/archetypes/roguelike/tests/lib.ts +83 -0
  276. package/archetypes/roguelike/tests/lose.og.ts +44 -0
  277. package/archetypes/roguelike/tests/pad.og.ts +54 -0
  278. package/archetypes/roguelike/tests/pause.og.ts +59 -0
  279. package/archetypes/roguelike/tests/phone.og.ts +54 -0
  280. package/archetypes/roguelike/tests/replay.og.ts +24 -0
  281. package/archetypes/roguelike/tests/win.og.ts +60 -0
  282. package/archetypes/roguelike/tools/make-assets.py +518 -0
  283. package/archetypes/roguelike/tools/oglite.py +285 -0
  284. package/archetypes/roguelike/tsconfig.json +17 -0
  285. package/archetypes/runner/.origin/setup +14 -0
  286. package/archetypes/runner/LICENSES.md +10 -0
  287. package/archetypes/runner/README.md +225 -0
  288. package/archetypes/runner/assets/audio/coin.wav +0 -0
  289. package/archetypes/runner/assets/audio/crash.wav +0 -0
  290. package/archetypes/runner/assets/audio/hold.ogt +9 -0
  291. package/archetypes/runner/assets/audio/jump.wav +0 -0
  292. package/archetypes/runner/assets/audio/start.wav +0 -0
  293. package/archetypes/runner/assets/fonts/OFL.txt +93 -0
  294. package/archetypes/runner/assets/fonts/ui.ttf +0 -0
  295. package/archetypes/runner/assets/fonts/ui.ttf.ogt +11 -0
  296. package/archetypes/runner/assets/maps/far.ogt +25 -0
  297. package/archetypes/runner/assets/maps/near.ogt +25 -0
  298. package/archetypes/runner/assets/maps/roofs.ogt +19 -0
  299. package/archetypes/runner/assets/scenes/main.ogt +35 -0
  300. package/archetypes/runner/assets/sprites/coin.ogt +11 -0
  301. package/archetypes/runner/assets/sprites/coin.png +0 -0
  302. package/archetypes/runner/assets/sprites/coin.png.ogt +7 -0
  303. package/archetypes/runner/assets/sprites/courier.ogt +32 -0
  304. package/archetypes/runner/assets/sprites/courier.png +0 -0
  305. package/archetypes/runner/assets/sprites/courier.png.ogt +7 -0
  306. package/archetypes/runner/assets/sprites/props.ogt +21 -0
  307. package/archetypes/runner/assets/sprites/props.png +0 -0
  308. package/archetypes/runner/assets/sprites/props.png.ogt +7 -0
  309. package/archetypes/runner/assets/sprites/sky.png +0 -0
  310. package/archetypes/runner/assets/sprites/sky.png.ogt +7 -0
  311. package/archetypes/runner/assets/tiles/city.ogt +18 -0
  312. package/archetypes/runner/assets/tiles/city.png +0 -0
  313. package/archetypes/runner/assets/tiles/city.png.ogt +7 -0
  314. package/archetypes/runner/gitattributes +22 -0
  315. package/archetypes/runner/host.d.ts +46 -0
  316. package/archetypes/runner/package.json +18 -0
  317. package/archetypes/runner/project.ogt +18 -0
  318. package/archetypes/runner/references/metal/frames-coin.png +0 -0
  319. package/archetypes/runner/references/metal/frames-crash.png +0 -0
  320. package/archetypes/runner/references/metal/frames-title.png +0 -0
  321. package/archetypes/runner/src/art.ts +57 -0
  322. package/archetypes/runner/src/components.ts +94 -0
  323. package/archetypes/runner/src/main.ts +241 -0
  324. package/archetypes/runner/src/systems.ts +553 -0
  325. package/archetypes/runner/tests/coins.og.ts +30 -0
  326. package/archetypes/runner/tests/flow.og.ts +72 -0
  327. package/archetypes/runner/tests/frames.og.ts +37 -0
  328. package/archetypes/runner/tests/frames.ts +134 -0
  329. package/archetypes/runner/tests/jump.og.ts +44 -0
  330. package/archetypes/runner/tests/lib.ts +42 -0
  331. package/archetypes/runner/tests/records.og.ts +43 -0
  332. package/archetypes/runner/tests/replay.og.ts +36 -0
  333. package/archetypes/runner/tests/sounds.og.ts +43 -0
  334. package/archetypes/runner/tests/tune.og.ts +36 -0
  335. package/archetypes/runner/tools/make-assets.py +603 -0
  336. package/archetypes/runner/tools/oglite.py +285 -0
  337. package/archetypes/runner/tsconfig.json +17 -0
  338. package/archetypes/third-person/.origin/setup +14 -0
  339. package/archetypes/third-person/LICENSES.md +23 -0
  340. package/archetypes/third-person/README.md +249 -0
  341. package/archetypes/third-person/assets/ai/sentinel-east.ogt +69 -0
  342. package/archetypes/third-person/assets/ai/sentinel-north.ogt +69 -0
  343. package/archetypes/third-person/assets/ai/sentinel-west.ogt +69 -0
  344. package/archetypes/third-person/assets/anims/humanoid-clips.glb +0 -0
  345. package/archetypes/third-person/assets/audio/alarm.wav +0 -0
  346. package/archetypes/third-person/assets/audio/dawn.wav +0 -0
  347. package/archetypes/third-person/assets/audio/grab.wav +0 -0
  348. package/archetypes/third-person/assets/audio/ignite.wav +0 -0
  349. package/archetypes/third-person/assets/audio/jump.wav +0 -0
  350. package/archetypes/third-person/assets/audio/night.wav +0 -0
  351. package/archetypes/third-person/assets/audio/splash.wav +0 -0
  352. package/archetypes/third-person/assets/audio/step.ogt +9 -0
  353. package/archetypes/third-person/assets/audio/ui-close.ogt +9 -0
  354. package/archetypes/third-person/assets/audio/ui-error.ogt +9 -0
  355. package/archetypes/third-person/assets/audio/ui-open.ogt +9 -0
  356. package/archetypes/third-person/assets/audio/ui-press.ogt +9 -0
  357. package/archetypes/third-person/assets/audio/ui-success.ogt +9 -0
  358. package/archetypes/third-person/assets/audio/vale.wav +0 -0
  359. package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf +0 -0
  360. package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
  361. package/archetypes/third-person/assets/fonts/OFL.txt +93 -0
  362. package/archetypes/third-person/assets/fx/burst.ogt +25 -0
  363. package/archetypes/third-person/assets/fx/fire.ogt +24 -0
  364. package/archetypes/third-person/assets/fx/smoke.ogt +24 -0
  365. package/archetypes/third-person/assets/fx/splash.ogt +24 -0
  366. package/archetypes/third-person/assets/luts/teal-orange.cube +4917 -0
  367. package/archetypes/third-person/assets/models/stout.glb +0 -0
  368. package/archetypes/third-person/assets/models/strider.glb +0 -0
  369. package/archetypes/third-person/assets/models/strider.glb.ogt +9 -0
  370. package/archetypes/third-person/assets/nav/vale.ogt +43 -0
  371. package/archetypes/third-person/assets/rigs/strider.ogt +6 -0
  372. package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf +0 -0
  373. package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf.ogt +9 -0
  374. package/archetypes/third-person/assets/skins/ember/LICENSES.md +13 -0
  375. package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf +0 -0
  376. package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf.ogt +9 -0
  377. package/archetypes/third-person/assets/skins/ember/OFL.txt +94 -0
  378. package/archetypes/third-person/assets/skins/ember/atlas.png +0 -0
  379. package/archetypes/third-person/assets/skins/ember/atlas.png.ogt +7 -0
  380. package/archetypes/third-person/assets/skins/ember/icons.png +0 -0
  381. package/archetypes/third-person/assets/skins/ember/icons.png.ogt +7 -0
  382. package/archetypes/third-person/assets/skins/ember/skin.ogt +109 -0
  383. package/archetypes/third-person/assets/strings/en.ogt +47 -0
  384. package/archetypes/third-person/assets/strings/zh-CN.ogt +47 -0
  385. package/archetypes/third-person/assets/terrain/vale-control.png +0 -0
  386. package/archetypes/third-person/assets/terrain/vale.ogt +42 -0
  387. package/archetypes/third-person/assets/terrain/vale.png +0 -0
  388. package/archetypes/third-person/assets/textures/decals.png +0 -0
  389. package/archetypes/third-person/assets/textures/flame.png +0 -0
  390. package/archetypes/third-person/assets/textures/smoke.png +0 -0
  391. package/archetypes/third-person/assets/textures/spark.png +0 -0
  392. package/archetypes/third-person/assets/textures/terrain-grass.png +0 -0
  393. package/archetypes/third-person/assets/textures/terrain-path.png +0 -0
  394. package/archetypes/third-person/assets/textures/terrain-rock.png +0 -0
  395. package/archetypes/third-person/assets/textures/terrain-sand.png +0 -0
  396. package/archetypes/third-person/gitattributes +22 -0
  397. package/archetypes/third-person/host.d.ts +46 -0
  398. package/archetypes/third-person/package.json +18 -0
  399. package/archetypes/third-person/project.ogt +14 -0
  400. package/archetypes/third-person/references/metal/beacon.png +0 -0
  401. package/archetypes/third-person/references/metal/dawn.png +0 -0
  402. package/archetypes/third-person/references/metal/title.png +0 -0
  403. package/archetypes/third-person/references/webgl2/beacon.png +0 -0
  404. package/archetypes/third-person/src/anim.ts +87 -0
  405. package/archetypes/third-person/src/beacons.ts +80 -0
  406. package/archetypes/third-person/src/components.ts +148 -0
  407. package/archetypes/third-person/src/hero.ts +293 -0
  408. package/archetypes/third-person/src/main.ts +164 -0
  409. package/archetypes/third-person/src/sentinels.ts +159 -0
  410. package/archetypes/third-person/src/sound.ts +66 -0
  411. package/archetypes/third-person/src/ui.ts +451 -0
  412. package/archetypes/third-person/src/world.ts +212 -0
  413. package/archetypes/third-person/tests/flow.og.ts +70 -0
  414. package/archetypes/third-person/tests/frames.og.ts +35 -0
  415. package/archetypes/third-person/tests/frames.ts +134 -0
  416. package/archetypes/third-person/tests/hitstop.og.ts +26 -0
  417. package/archetypes/third-person/tests/lib.ts +87 -0
  418. package/archetypes/third-person/tests/lose.og.ts +44 -0
  419. package/archetypes/third-person/tests/pause.og.ts +64 -0
  420. package/archetypes/third-person/tests/phone.og.ts +65 -0
  421. package/archetypes/third-person/tests/replay.og.ts +32 -0
  422. package/archetypes/third-person/tests/restart.og.ts +28 -0
  423. package/archetypes/third-person/tests/sentinels.og.ts +48 -0
  424. package/archetypes/third-person/tests/win.og.ts +62 -0
  425. package/archetypes/third-person/tools/make-assets.py +353 -0
  426. package/archetypes/third-person/tools/oglite.py +285 -0
  427. package/archetypes/third-person/tsconfig.json +17 -0
  428. package/archetypes/topdown/.origin/setup +14 -0
  429. package/archetypes/topdown/LICENSES.md +10 -0
  430. package/archetypes/topdown/README.md +235 -0
  431. package/archetypes/topdown/assets/ai/slime.ogt +49 -0
  432. package/archetypes/topdown/assets/audio/coin.wav +0 -0
  433. package/archetypes/topdown/assets/audio/door.wav +0 -0
  434. package/archetypes/topdown/assets/audio/hit.wav +0 -0
  435. package/archetypes/topdown/assets/audio/hurt.wav +0 -0
  436. package/archetypes/topdown/assets/audio/key.wav +0 -0
  437. package/archetypes/topdown/assets/audio/step.ogt +9 -0
  438. package/archetypes/topdown/assets/fonts/OFL.txt +93 -0
  439. package/archetypes/topdown/assets/fonts/ui.ttf +0 -0
  440. package/archetypes/topdown/assets/fonts/ui.ttf.ogt +9 -0
  441. package/archetypes/topdown/assets/maps/tomb.tmj +2183 -0
  442. package/archetypes/topdown/assets/sprites/hero.ogt +58 -0
  443. package/archetypes/topdown/assets/sprites/hero.png +0 -0
  444. package/archetypes/topdown/assets/sprites/hero.png.ogt +7 -0
  445. package/archetypes/topdown/assets/sprites/items.ogt +15 -0
  446. package/archetypes/topdown/assets/sprites/items.png +0 -0
  447. package/archetypes/topdown/assets/sprites/items.png.ogt +7 -0
  448. package/archetypes/topdown/assets/sprites/slime.ogt +17 -0
  449. package/archetypes/topdown/assets/sprites/slime.png +0 -0
  450. package/archetypes/topdown/assets/sprites/slime.png.ogt +7 -0
  451. package/archetypes/topdown/assets/tiles/dungeon.ogt +65 -0
  452. package/archetypes/topdown/assets/tiles/dungeon.png +0 -0
  453. package/archetypes/topdown/assets/tiles/dungeon.png.ogt +7 -0
  454. package/archetypes/topdown/gitattributes +22 -0
  455. package/archetypes/topdown/host.d.ts +46 -0
  456. package/archetypes/topdown/package.json +18 -0
  457. package/archetypes/topdown/project.ogt +14 -0
  458. package/archetypes/topdown/references/metal/crit.png +0 -0
  459. package/archetypes/topdown/references/metal/dash.png +0 -0
  460. package/archetypes/topdown/references/metal/east.png +0 -0
  461. package/archetypes/topdown/references/metal/start.png +0 -0
  462. package/archetypes/topdown/src/art.ts +48 -0
  463. package/archetypes/topdown/src/components.ts +128 -0
  464. package/archetypes/topdown/src/main.ts +275 -0
  465. package/archetypes/topdown/src/systems.ts +503 -0
  466. package/archetypes/topdown/tests/ai.og.ts +64 -0
  467. package/archetypes/topdown/tests/combat.og.ts +72 -0
  468. package/archetypes/topdown/tests/door.og.ts +62 -0
  469. package/archetypes/topdown/tests/flee.og.ts +49 -0
  470. package/archetypes/topdown/tests/frames.og.ts +45 -0
  471. package/archetypes/topdown/tests/frames.ts +134 -0
  472. package/archetypes/topdown/tests/lib.ts +71 -0
  473. package/archetypes/topdown/tests/replay.og.ts +40 -0
  474. package/archetypes/topdown/tests/walk.og.ts +46 -0
  475. package/archetypes/topdown/tools/make-assets.py +623 -0
  476. package/archetypes/topdown/tools/oglite.py +285 -0
  477. package/archetypes/topdown/tsconfig.json +17 -0
  478. package/archetypes/tower-defense/.origin/setup +14 -0
  479. package/archetypes/tower-defense/LICENSES.md +15 -0
  480. package/archetypes/tower-defense/README.md +240 -0
  481. package/archetypes/tower-defense/assets/ai/plant.ogt +16 -0
  482. package/archetypes/tower-defense/assets/audio/clear.wav +0 -0
  483. package/archetypes/tower-defense/assets/audio/frost.wav +0 -0
  484. package/archetypes/tower-defense/assets/audio/leak.wav +0 -0
  485. package/archetypes/tower-defense/assets/audio/lost.wav +0 -0
  486. package/archetypes/tower-defense/assets/audio/night.wav +0 -0
  487. package/archetypes/tower-defense/assets/audio/plant.wav +0 -0
  488. package/archetypes/tower-defense/assets/audio/pop.wav +0 -0
  489. package/archetypes/tower-defense/assets/audio/thorn.wav +0 -0
  490. package/archetypes/tower-defense/assets/audio/ui-close.ogt +9 -0
  491. package/archetypes/tower-defense/assets/audio/ui-error.ogt +9 -0
  492. package/archetypes/tower-defense/assets/audio/ui-open.ogt +9 -0
  493. package/archetypes/tower-defense/assets/audio/ui-press.ogt +9 -0
  494. package/archetypes/tower-defense/assets/audio/ui-success.ogt +9 -0
  495. package/archetypes/tower-defense/assets/audio/wave.wav +0 -0
  496. package/archetypes/tower-defense/assets/audio/won.wav +0 -0
  497. package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf +0 -0
  498. package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
  499. package/archetypes/tower-defense/assets/fonts/OFL.txt +93 -0
  500. package/archetypes/tower-defense/assets/fx/fireflies.ogt +21 -0
  501. package/archetypes/tower-defense/assets/fx/pop.ogt +21 -0
  502. package/archetypes/tower-defense/assets/maps/garden.ogt +91 -0
  503. package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf +0 -0
  504. package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf.ogt +9 -0
  505. package/archetypes/tower-defense/assets/skins/pathguard/LICENSES.md +13 -0
  506. package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf +0 -0
  507. package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf.ogt +9 -0
  508. package/archetypes/tower-defense/assets/skins/pathguard/OFL.txt +94 -0
  509. package/archetypes/tower-defense/assets/skins/pathguard/atlas.png +0 -0
  510. package/archetypes/tower-defense/assets/skins/pathguard/atlas.png.ogt +7 -0
  511. package/archetypes/tower-defense/assets/skins/pathguard/icons.png +0 -0
  512. package/archetypes/tower-defense/assets/skins/pathguard/icons.png.ogt +7 -0
  513. package/archetypes/tower-defense/assets/skins/pathguard/skin.ogt +111 -0
  514. package/archetypes/tower-defense/assets/sprites/garden.ogt +66 -0
  515. package/archetypes/tower-defense/assets/sprites/garden.png +0 -0
  516. package/archetypes/tower-defense/assets/sprites/garden.png.ogt +7 -0
  517. package/archetypes/tower-defense/assets/sprites/glow.png +0 -0
  518. package/archetypes/tower-defense/assets/sprites/glow.png.ogt +7 -0
  519. package/archetypes/tower-defense/assets/sprites/ring.png +0 -0
  520. package/archetypes/tower-defense/assets/sprites/ring.png.ogt +7 -0
  521. package/archetypes/tower-defense/assets/sprites/spark.png +0 -0
  522. package/archetypes/tower-defense/assets/sprites/spark.png.ogt +7 -0
  523. package/archetypes/tower-defense/assets/strings/en.ogt +47 -0
  524. package/archetypes/tower-defense/assets/strings/zh-CN.ogt +47 -0
  525. package/archetypes/tower-defense/assets/tiles/garden.ogt +10 -0
  526. package/archetypes/tower-defense/assets/tiles/garden.png +0 -0
  527. package/archetypes/tower-defense/assets/tiles/garden.png.ogt +7 -0
  528. package/archetypes/tower-defense/gitattributes +22 -0
  529. package/archetypes/tower-defense/host.d.ts +46 -0
  530. package/archetypes/tower-defense/package.json +18 -0
  531. package/archetypes/tower-defense/project.ogt +14 -0
  532. package/archetypes/tower-defense/references/metal/end.png +0 -0
  533. package/archetypes/tower-defense/references/metal/title.png +0 -0
  534. package/archetypes/tower-defense/references/metal/wave.png +0 -0
  535. package/archetypes/tower-defense/src/art.ts +24 -0
  536. package/archetypes/tower-defense/src/components.ts +156 -0
  537. package/archetypes/tower-defense/src/main.ts +253 -0
  538. package/archetypes/tower-defense/src/systems.ts +658 -0
  539. package/archetypes/tower-defense/src/ui.ts +382 -0
  540. package/archetypes/tower-defense/tests/flow.og.ts +56 -0
  541. package/archetypes/tower-defense/tests/frames.og.ts +31 -0
  542. package/archetypes/tower-defense/tests/frames.ts +134 -0
  543. package/archetypes/tower-defense/tests/lib.ts +81 -0
  544. package/archetypes/tower-defense/tests/lose.og.ts +40 -0
  545. package/archetypes/tower-defense/tests/maze.og.ts +53 -0
  546. package/archetypes/tower-defense/tests/pad.og.ts +41 -0
  547. package/archetypes/tower-defense/tests/pause.og.ts +59 -0
  548. package/archetypes/tower-defense/tests/phone.og.ts +49 -0
  549. package/archetypes/tower-defense/tests/replay.og.ts +28 -0
  550. package/archetypes/tower-defense/tests/win.og.ts +58 -0
  551. package/archetypes/tower-defense/tools/make-assets.py +640 -0
  552. package/archetypes/tower-defense/tools/oglite.py +285 -0
  553. package/archetypes/tower-defense/tsconfig.json +17 -0
  554. package/bin/create.ts +496 -0
  555. package/looks/catalogue.json +1871 -0
  556. package/package.json +31 -4
  557. package/template/.origin/setup +14 -0
  558. package/template/LICENSES.md +23 -0
  559. package/template/README.md +37 -0
  560. package/template/assets/ai/guard.ogt +48 -0
  561. package/template/assets/audio/blip.wav +0 -0
  562. package/template/assets/audio/click.ogt +9 -0
  563. package/template/assets/fonts/NotoSansSC-Regular-subset.ttf +0 -0
  564. package/template/assets/fonts/NotoSansSC-Regular-subset.ttf.ogt +12 -0
  565. package/template/assets/fonts/OFL.txt +93 -0
  566. package/template/assets/looks/origin-game.ogt +12 -0
  567. package/template/assets/models/dropship.glb +0 -0
  568. package/template/assets/models/walker.glb +0 -0
  569. package/template/assets/nav/yard.ogt +27 -0
  570. package/template/assets/scenes/main.ogt +34 -0
  571. package/template/assets/strings/en.ogt +14 -0
  572. package/template/assets/textures/stone.png +0 -0
  573. package/template/assets/textures/stone_n.png +0 -0
  574. package/template/assets/textures/stone_n.png.ogt +7 -0
  575. package/template/gitattributes +22 -0
  576. package/template/package.json +18 -0
  577. package/template/project.ogt +25 -0
  578. package/template/src/main.ts +246 -0
  579. package/template/tests/guard.og.ts +67 -0
  580. package/template/tests/smoke.og.ts +43 -0
  581. package/template/tsconfig.json +17 -0
@@ -0,0 +1,37 @@
1
+ // The look, frame by frame: the title over the scrolling city, a coin's
2
+ // pickup mid-run ("+10" rising from the popping coin, dust at the feet) and
3
+ // the crash's hit stop (the courier flashing red on the crate, the view
4
+ // shaking). Each is compared with references/<tier>/frames-<file> under
5
+ // og-tests' tolerance (tests/frames.ts); `OG_FX_CAPTURE=1 og test .` records
6
+ // them. The script has no dice in it: patterns are off, the coin and the
7
+ // crate are placed.
8
+ import { playtest } from "@origingame/engine/playtest";
9
+ import { checkFrames } from "./frames.ts";
10
+ import { OVER, RUNNING, runOf, tap } from "./lib.ts";
11
+
12
+ const FILES = ["title.png", "coin.png", "crash.png"] as const;
13
+
14
+ export default playtest({
15
+ name: "reference frames: title, a coin's pickup, the crash",
16
+ commands: [
17
+ "0.1:set:runner.Tuning.spawnInterval=60",
18
+ "0.3:screenshot:title.png",
19
+ tap(0.5),
20
+ "1.0:place:coin:-2",
21
+ "1.6:screenshot:coin.png",
22
+ "1.6:dump_entity:runner:coin.json",
23
+ "2.0:place:crate:1",
24
+ // The crate reaches the runner in tick 173; 2.95 s is three ticks into the eight-tick hit stop.
25
+ "2.95:screenshot:crash.png",
26
+ "2.95:dump_entity:runner:crash.json",
27
+ "3.0:quit",
28
+ ].join(";"),
29
+ check(run, t) {
30
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
31
+ const coin = runOf(run, "coin.json");
32
+ t.ok(coin.phase === RUNNING && coin.coins === 1, "the coin frame is mid-run, just after the pickup");
33
+ const crash = runOf(run, "crash.json");
34
+ t.ok(crash.phase === OVER && crash.phaseTicks < 8, `the crash frame is inside the hit stop (${crash.phaseTicks} ticks after)`);
35
+ checkFrames(run, t, FILES, "frames-");
36
+ },
37
+ });
@@ -0,0 +1,134 @@
1
+ // The reference-frame check: decode the PNGs a run wrote and compare them
2
+ // with references/<tier>/ under og-tests' tolerance (a channel off by more
3
+ // than 32/255 is an outlier; fail above 0.5 % outliers or an RGB RMSE above
4
+ // 0.01). A tier without its own references compares with `metal` and says
5
+ // so. `OG_FX_CAPTURE=1 og test .` records this tier's references instead.
6
+ // (Copied from templates/fx-showcase/tests/frames.ts, so the archetype stands alone.)
7
+
8
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
9
+ import { dirname, join, resolve } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { inflateSync } from "node:zlib";
12
+ import type { PlaytestChecks, PlaytestRun } from "@origingame/engine/playtest";
13
+
14
+ export interface Image {
15
+ width: number;
16
+ height: number;
17
+ /** RGBA8 rows. */
18
+ rgba: Uint8Array;
19
+ }
20
+
21
+ /** An 8-bit RGB or RGBA, non-interlaced PNG, unfiltered. */
22
+ export function decodePng(bytes: Uint8Array): Image {
23
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
24
+ let at = 8;
25
+ let width = 0;
26
+ let height = 0;
27
+ let channels = 4;
28
+ const idat: Uint8Array[] = [];
29
+ while (at < bytes.length) {
30
+ const len = view.getUint32(at);
31
+ const type = String.fromCharCode(...bytes.subarray(at + 4, at + 8));
32
+ const data = bytes.subarray(at + 8, at + 8 + len);
33
+ if (type === "IHDR") {
34
+ width = view.getUint32(at + 8);
35
+ height = view.getUint32(at + 12);
36
+ const depth = data[8]!;
37
+ const color = data[9]!;
38
+ if (depth !== 8 || (color !== 6 && color !== 2) || data[12] !== 0) throw new Error(`unsupported PNG (depth ${depth}, colour ${color}, interlace ${data[12]})`);
39
+ channels = color === 6 ? 4 : 3;
40
+ } else if (type === "IDAT") idat.push(data);
41
+ else if (type === "IEND") break;
42
+ at += 12 + len;
43
+ }
44
+ const raw = inflateSync(Buffer.concat(idat));
45
+ const stride = width * channels;
46
+ const out = new Uint8Array(width * height * 4);
47
+ const prev = new Uint8Array(stride);
48
+ const cur = new Uint8Array(stride);
49
+ for (let y = 0; y < height; y++) {
50
+ const filter = raw[y * (stride + 1)]!;
51
+ const line = raw.subarray(y * (stride + 1) + 1, (y + 1) * (stride + 1));
52
+ for (let i = 0; i < stride; i++) {
53
+ const a = i >= channels ? cur[i - channels]! : 0;
54
+ const b = prev[i]!;
55
+ const c = i >= channels ? prev[i - channels]! : 0;
56
+ let v = line[i]!;
57
+ if (filter === 1) v += a;
58
+ else if (filter === 2) v += b;
59
+ else if (filter === 3) v += (a + b) >> 1;
60
+ else if (filter === 4) {
61
+ const p = a + b - c;
62
+ const pa = Math.abs(p - a), pb = Math.abs(p - b), pc = Math.abs(p - c);
63
+ v += pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
64
+ }
65
+ cur[i] = v & 255;
66
+ }
67
+ for (let x = 0; x < width; x++) {
68
+ for (let k = 0; k < 4; k++) out[(y * width + x) * 4 + k] = k < channels ? cur[x * channels + k]! : 255;
69
+ }
70
+ prev.set(cur);
71
+ }
72
+ return { width, height, rgba: out };
73
+ }
74
+
75
+ /** og-tests' rule: outlier fraction and RGB RMSE between two equal-size frames. */
76
+ export function difference(a: Image, b: Image): { outliers: number; rmse: number } {
77
+ if (a.width !== b.width || a.height !== b.height) return { outliers: 1, rmse: 1 };
78
+ let outliers = 0;
79
+ let sum = 0;
80
+ const n = a.width * a.height;
81
+ for (let p = 0; p < n; p++) {
82
+ let out = false;
83
+ for (let k = 0; k < 3; k++) {
84
+ const d = Math.abs(a.rgba[p * 4 + k]! - b.rgba[p * 4 + k]!);
85
+ if (d > 32) out = true;
86
+ const f = d / 255;
87
+ sum += f * f;
88
+ }
89
+ if (out) outliers++;
90
+ }
91
+ return { outliers: outliers / n, rmse: Math.sqrt(sum / (n * 3)) };
92
+ }
93
+
94
+ /** The playtest's output directory (the bundled playtest runs from it). */
95
+ export function outDir(): string {
96
+ return dirname(fileURLToPath(import.meta.url));
97
+ }
98
+
99
+ /** The project's references/, from its og-out/test/<name>/. */
100
+ export function referencesDir(): string {
101
+ return resolve(outDir(), "..", "..", "..", "references");
102
+ }
103
+
104
+ /** Compares each screenshot with its reference (`<prefix><file>`), or records it. */
105
+ export function checkFrames(run: PlaytestRun, t: PlaytestChecks, files: readonly string[], prefix: string): void {
106
+ // Read only where there is a renderer: without one (tier `none`) each frame is
107
+ // reported "no renderer, frame unchecked" and every other check still runs.
108
+ t.frame(files, () => {
109
+ const refs = referencesDir();
110
+ t.ok(existsSync(refs) || process.env.OG_FX_CAPTURE !== undefined, `the references directory exists at ${refs}`);
111
+ const own = join(refs, run.tier);
112
+ const capture = process.env.OG_FX_CAPTURE !== undefined;
113
+ for (const f of files) {
114
+ const actual = join(outDir(), f);
115
+ // Each file on its own: this tier's reference where it has one, metal's otherwise.
116
+ const mine = join(own, prefix + f);
117
+ const ref = capture || existsSync(mine) ? mine : join(refs, "metal", prefix + f);
118
+ if (ref !== mine) process.stdout.write(` note: no ${run.tier} reference for ${prefix}${f}; comparing with metal\n`);
119
+ if (capture) {
120
+ mkdirSync(own, { recursive: true });
121
+ copyFileSync(actual, ref);
122
+ t.ok(true, `recorded ${ref}`);
123
+ continue;
124
+ }
125
+ if (!existsSync(ref)) {
126
+ t.ok(false, `${ref} is missing: record it with OG_FX_CAPTURE=1 og test .`);
127
+ continue;
128
+ }
129
+ const d = difference(decodePng(readFileSync(actual)), decodePng(readFileSync(ref)));
130
+ process.stdout.write(` ${f}: ${(d.outliers * 100).toFixed(3)} % outliers, RMSE ${d.rmse.toFixed(5)} against ${ref}\n`);
131
+ t.ok(d.outliers <= 0.005 && d.rmse <= 0.01, `${f} matches ${prefix}${f}: ${(d.outliers * 100).toFixed(3)} % outliers (≤ 0.5 %), RMSE ${d.rmse.toFixed(5)} (≤ 0.01)`);
132
+ }
133
+ });
134
+ }
@@ -0,0 +1,44 @@
1
+ // Jumps: at a steady 6 m/s an obstacle placed at x=1 reaches the runner
2
+ // (x=-5) one second later. A held press (a full jump, 1.9 m) clears a crate
3
+ // and a fence; a tap (the 6-tick hop, 1.1 m) clears a crate but not a fence.
4
+ import { playtest } from "@origingame/engine/playtest";
5
+ import { OVER, RUNNING, positionOf, runOf, tap } from "./lib.ts";
6
+
7
+ export default playtest({
8
+ name: "a full jump clears a crate and a fence; a hop clears a crate, not a fence",
9
+ commands: [
10
+ "0.1:set:runner.Tuning.spawnInterval=60",
11
+ "0.1:set:runner.Tuning.speedRamp=0",
12
+ tap(0.5),
13
+ // Crate 1 at t=1: arrives at t=2. Hold Space from 1.65 to 2.15: a full jump.
14
+ "1.0:place:crate:1",
15
+ "1.65:key_down:Space",
16
+ "1.9:dump_entity:runner:airborne.json",
17
+ "1.9:screenshot:jump.png",
18
+ "2.15:key_up:Space",
19
+ "2.6:dump_entity:runner:after-full.json",
20
+ // Crate 2 at t=3 arrives at t=4: a tap 12 ticks before is a hop over it.
21
+ "3.0:place:crate:1",
22
+ tap(3.8),
23
+ "4.6:dump_entity:runner:after-hop.json",
24
+ // Fence 1 at t=5: a full jump 18 ticks before its arrival clears it.
25
+ "5.0:place:fence:1",
26
+ "5.7:key_down:Space",
27
+ "6.2:key_up:Space",
28
+ "6.6:dump_entity:runner:after-fence.json",
29
+ // Fence 2 at t=7: a tap at the same moment as that full jump is a hop, too low for it.
30
+ "7.0:place:fence:1",
31
+ tap(7.7),
32
+ "8.6:dump_entity:runner:after-hop-fence.json",
33
+ "8.7:quit",
34
+ ].join(";"),
35
+ check(run, t) {
36
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
37
+ const air = positionOf(run, "airborne.json");
38
+ t.ok(air.y > 1, `the held jump is high over the crate (feet at ${air.y.toFixed(2)} m)`);
39
+ t.equal(runOf(run, "after-full.json").phase, RUNNING, "the full jump cleared crate 1");
40
+ t.equal(runOf(run, "after-hop.json").phase, RUNNING, "the hop cleared crate 2");
41
+ t.equal(runOf(run, "after-fence.json").phase, RUNNING, "the full jump cleared fence 1");
42
+ t.equal(runOf(run, "after-hop-fence.json").phase, OVER, "the hop did not clear fence 2");
43
+ },
44
+ });
@@ -0,0 +1,42 @@
1
+ // Shared readers for the runner's playtests: the runner row's components as
2
+ // `dump_entity:runner:<file>` writes them.
3
+ import type { PlaytestRun } from "@origingame/engine/playtest";
4
+
5
+ export interface RunDump {
6
+ phase: number;
7
+ phaseTicks: number;
8
+ speed: number;
9
+ distance: number;
10
+ coins: number;
11
+ score: number;
12
+ best: number;
13
+ rounds: number;
14
+ grounded: boolean | number;
15
+ }
16
+
17
+ interface EntityDump {
18
+ components: Record<string, Record<string, unknown>>;
19
+ }
20
+
21
+ /** The runner's Run component from a dump_entity file. */
22
+ export function runOf(run: PlaytestRun, file: string): RunDump {
23
+ const dump = run.json<EntityDump>(file);
24
+ const r = dump.components["Run"];
25
+ if (!r) throw new Error(`${file} has no Run component: ${Object.keys(dump.components).join(", ")}`);
26
+ return r as unknown as RunDump;
27
+ }
28
+
29
+ /** The runner's position (its feet; the hit box is centred 0.8125 m above) from a dump_entity file. */
30
+ export function positionOf(run: PlaytestRun, file: string): { x: number; y: number } {
31
+ const dump = run.json<EntityDump>(file);
32
+ const t = (dump.components["og.Transform"] ?? dump.components["Transform"]) as { position: [number, number, number] } | undefined;
33
+ if (!t) throw new Error(`${file} has no Transform`);
34
+ return { x: t.position[0], y: t.position[1] };
35
+ }
36
+
37
+ export const TITLE = 0;
38
+ export const RUNNING = 1;
39
+ export const OVER = 2;
40
+
41
+ /** A press of Space at t seconds (down, then up two ticks later): a tap, which is a hop. */
42
+ export const tap = (t: number) => `${t}:key_down:Space;${(t + 0.034).toFixed(3)}:key_up:Space`;
@@ -0,0 +1,43 @@
1
+ // The runner on og.platform (here the native host's local store, in
2
+ // memory for each run): the first tick asks the store for the best score,
3
+ // a crash submits the score to the `main` board, files a `round.over`
4
+ // event and, being a new best, saves it; `dump_platform` shows each call,
5
+ // its tick and its answer.
6
+ import { playtest } from "@origingame/engine/playtest";
7
+ import { OVER, runOf, tap } from "./lib.ts";
8
+
9
+ interface PlatformDump {
10
+ host: string;
11
+ calls: Array<{ method: string; args: Record<string, unknown>; tick: number; state: string; result?: { ok: boolean; data: Record<string, unknown> } }>;
12
+ }
13
+
14
+ export default playtest({
15
+ name: "the best score is read from the store, and a crash submits the score and saves the new best",
16
+ commands: [
17
+ tap(0.5),
18
+ "0.6:set:runner.Tuning.spawnInterval=60",
19
+ "2.2:place:crate:3",
20
+ "3.6:dump_entity:runner:over.json",
21
+ "3.7:dump_platform:platform.json",
22
+ "3.8:quit",
23
+ ].join(";"),
24
+ check(run, t) {
25
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
26
+ const over = runOf(run, "over.json");
27
+ t.equal(over.phase, OVER, "the crate ended the round");
28
+ const p = run.json<PlatformDump>("platform.json");
29
+ t.equal(p.host, "local", "og run answers from its local store");
30
+ const of = (m: string) => p.calls.filter((c) => c.method === m);
31
+ const get = of("store.get")[0];
32
+ t.ok(get?.tick === 0 && get.args["key"] === "best", "tick 0 asks the store for `best`");
33
+ t.equal(get?.result?.data["value"], null, "nothing was stored before this run");
34
+ const submit = of("leaderboard.submit")[0];
35
+ t.equal(submit?.args["score"], over.score, `the crash submitted the score (${over.score})`);
36
+ t.equal(submit?.result?.data["rank"], 1, "the only run on the local board ranks first");
37
+ const set = of("store.set")[0];
38
+ t.equal(set?.args["value"], over.score, "the new best was saved");
39
+ t.equal(set?.result?.data["revision"], 1, "as the key's first revision");
40
+ t.equal(of("telemetry")[0]?.args["name"], "round.over", "a round.over event was filed");
41
+ t.equal(of("telemetry")[0]?.state, "sent", "one-way: nothing answers it");
42
+ },
43
+ });
@@ -0,0 +1,36 @@
1
+ // Determinism: the same script twice, in fresh processes, ends on the same
2
+ // world hash. It covers what the feel added to the world state: dice-made
3
+ // patterns, jumps (stretch and squash tweens), a coin's pickup (its pop and
4
+ // floating text), the run clip's footfalls (dust puffs), a crash (hit stop,
5
+ // shake, knock-back, the flash) and a second round.
6
+ import { playtest } from "@origingame/engine/playtest";
7
+ import { OVER, RUNNING, runOf, tap } from "./lib.ts";
8
+
9
+ export default playtest({
10
+ name: "replay: two runs of jumps, coins and a crash end on one hash",
11
+ runs: 2,
12
+ commands: [
13
+ tap(0.5),
14
+ "1.0:place:coin:-2",
15
+ "2.0:place:crate:1",
16
+ tap(2.8),
17
+ "3.6:dump_entity:runner:round1.json",
18
+ "4.0:place:fence:1",
19
+ "5.2:dump_entity:runner:crashed.json",
20
+ tap(5.8),
21
+ "6.4:key_down:Space",
22
+ "6.7:key_up:Space",
23
+ tap(7.6),
24
+ "9.0:dump_entity:runner:round2.json",
25
+ "9.1:quit",
26
+ ].join(";"),
27
+ check(run, t) {
28
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
29
+ const round1 = runOf(run, "round1.json");
30
+ t.ok(round1.phase === RUNNING && round1.coins >= 1, `round one jumped the crate and took the coin (${round1.coins} coins)`);
31
+ t.equal(runOf(run, "crashed.json").phase, OVER, "the fence ended round one");
32
+ t.equal(runOf(run, "round2.json").rounds, 2, "round two started");
33
+ t.equal(run.hashes.length, 2, "the script ran twice");
34
+ t.equal(run.hashes[1], run.hashes[0], `both runs end on the same world hash (${run.hashes.join(" vs ")})`);
35
+ },
36
+ });
@@ -0,0 +1,43 @@
1
+ // Sounds: the title is silent; a round's start, a jump, a coin and a crash
2
+ // each play their own voice (the sfx-<bit> entity holds an og.AudioPlayback
3
+ // while it plays), and the crash is heard in the mix.
4
+ import { playtest } from "@origingame/engine/playtest";
5
+ import { tap } from "./lib.ts";
6
+
7
+ interface EntityDump {
8
+ components: Record<string, Record<string, unknown>>;
9
+ }
10
+
11
+ const VOICES = [
12
+ ["start.json", "the round's start"],
13
+ ["jump.json", "the jump"],
14
+ ["coin.json", "the coin"],
15
+ ["crash.json", "the crash"],
16
+ ] as const;
17
+
18
+ export default playtest({
19
+ name: "a round's start, a jump, a coin and a crash each play their sound",
20
+ commands: [
21
+ "0.1:set:runner.Tuning.spawnInterval=60",
22
+ "0.45:listen:title.wav:0.3",
23
+ tap(0.5),
24
+ "0.7:dump_entity:sfx-8:start.json",
25
+ tap(1.2),
26
+ "1.25:dump_entity:sfx-1:jump.json",
27
+ "2.0:place:coin:-4.6",
28
+ "2.15:dump_entity:sfx-2:coin.json",
29
+ "2.6:place:crate:-4.6",
30
+ "2.8:dump_entity:sfx-4:crash.json",
31
+ "2.9:listen:crash.wav:0.3",
32
+ "3.0:quit",
33
+ ].join(";"),
34
+ check(run, t) {
35
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
36
+ t.ok(run.wav("title.wav").peak < 0.001, `the title is silent (peak ${run.wav("title.wav").peak})`);
37
+ for (const [file, what] of VOICES) {
38
+ const d = run.json<EntityDump>(file);
39
+ t.ok("og.AudioPlayback" in d.components, `${what} plays its voice (${file}: ${Object.keys(d.components).join(", ")})`);
40
+ }
41
+ t.ok(run.wav("crash.wav").peak > 0.05, `the crash is heard (peak ${run.wav("crash.wav").peak})`);
42
+ },
43
+ });
@@ -0,0 +1,36 @@
1
+ // Tune writes through the schema: `set:runner.Tuning.speed` changes the
2
+ // start speed of the next round, `jumpHeight` and `timeToApex` the arc of a
3
+ // full jump (og.PlatformerController's designer units).
4
+ import { playtest } from "@origingame/engine/playtest";
5
+ import { RUNNING, positionOf, runOf, tap } from "./lib.ts";
6
+
7
+ export default playtest({
8
+ name: "set writes Tuning: start speed and jump height change the run",
9
+ commands: [
10
+ "0.1:set:runner.Tuning.spawnInterval=60",
11
+ "0.1:set:runner.Tuning.speedRamp=0",
12
+ "0.1:set:runner.Tuning.speed=10",
13
+ "0.1:set:runner.Tuning.jumpHeight=4",
14
+ "0.1:set:runner.Tuning.timeToApex=0.667",
15
+ "0.1:dump_entity:runner:tuning.json",
16
+ tap(0.5),
17
+ "1.5:dump_entity:runner:fast.json",
18
+ "1.6:key_down:Space",
19
+ // A full jump of height 4 m peaks after about 0.67 s.
20
+ "2.27:dump_entity:runner:apex.json",
21
+ "2.4:key_up:Space",
22
+ "2.5:quit",
23
+ ].join(";"),
24
+ check(run, t) {
25
+ t.equal(run.warnings.join("; "), "", "the script ran without warnings");
26
+ const tuning = run.json<{ components: { Tuning: { speed: number; jumpHeight: number } } }>("tuning.json").components.Tuning;
27
+ t.equal(tuning.speed, 10, "the start speed was set");
28
+ t.equal(tuning.jumpHeight, 4, "the jump height was set");
29
+ const fast = runOf(run, "fast.json");
30
+ t.equal(fast.phase, RUNNING, "running");
31
+ t.near(fast.speed, 10, 1e-4, "the round starts at the tuned speed");
32
+ t.near(fast.distance, 10, 0.4, `about 10 m in the first second (${fast.distance.toFixed(2)})`);
33
+ const apex = positionOf(run, "apex.json").y;
34
+ t.near(apex, 4, 0.15, `the jump peaks near the tuned 4 m (${apex.toFixed(2)} m)`);
35
+ },
36
+ });