@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,285 @@
1
+ """A tiny, standard-library-only sprite kit for Origin Engine archetypes.
2
+
3
+ It draws antialiased vector shapes into RGBA images (4x4 supersampling),
4
+ writes PNGs, packs sprites into one glTF binary (.glb) of unit quads, one
5
+ mesh and one emissive, alpha-masked material per sprite, and writes 16-bit
6
+ WAV sounds. Everything is a pure function of its inputs, so the assets it
7
+ makes are byte-for-byte reproducible.
8
+
9
+ A sprite quad lies in the xy plane facing +z, 1 x 1 units, centred on the
10
+ origin, with uv (0,0) at the image's top left. Its material is black base
11
+ colour (alpha from the image, for the mask), roughness 1, and the image as
12
+ the emissive texture: with no light, no environment and tone mapping off,
13
+ the frame shows the image's colours exactly.
14
+ """
15
+ import json, math, struct, wave, zlib
16
+
17
+ SS = 4 # supersamples per axis
18
+
19
+
20
+ def hex_rgb(h):
21
+ h = h.lstrip("#")
22
+ return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4))
23
+
24
+
25
+ class Canvas:
26
+ """An RGBA canvas; shapes are painted in order with coverage antialiasing.
27
+ Coordinates are in pixels, origin top left, y down."""
28
+
29
+ def __init__(self, w, h):
30
+ self.w, self.h = w, h
31
+ self.px = [[0.0, 0.0, 0.0, 0.0] for _ in range(w * h)] # premultiplied
32
+
33
+ def _paint(self, inside, bbox, colour, alpha=1.0):
34
+ r, g, b = (c / 255.0 for c in hex_rgb(colour))
35
+ x0, y0, x1, y1 = bbox
36
+ x0 = max(0, int(math.floor(x0))); y0 = max(0, int(math.floor(y0)))
37
+ x1 = min(self.w, int(math.ceil(x1))); y1 = min(self.h, int(math.ceil(y1)))
38
+ n = SS * SS
39
+ for y in range(y0, y1):
40
+ for x in range(x0, x1):
41
+ hits = 0
42
+ for sy in range(SS):
43
+ py = y + (sy + 0.5) / SS
44
+ for sx in range(SS):
45
+ if inside(x + (sx + 0.5) / SS, py):
46
+ hits += 1
47
+ if hits == 0:
48
+ continue
49
+ a = alpha * hits / n
50
+ p = self.px[y * self.w + x]
51
+ p[0] = r * a + p[0] * (1 - a)
52
+ p[1] = g * a + p[1] * (1 - a)
53
+ p[2] = b * a + p[2] * (1 - a)
54
+ p[3] = a + p[3] * (1 - a)
55
+
56
+ def rect(self, x, y, w, h, colour, radius=0.0, alpha=1.0):
57
+ rad = min(radius, w / 2, h / 2)
58
+
59
+ def inside(px, py):
60
+ if px < x or px > x + w or py < y or py > y + h:
61
+ return False
62
+ if rad <= 0:
63
+ return True
64
+ cx = min(max(px, x + rad), x + w - rad)
65
+ cy = min(max(py, y + rad), y + h - rad)
66
+ return (px - cx) ** 2 + (py - cy) ** 2 <= rad * rad
67
+
68
+ self._paint(inside, (x, y, x + w, y + h), colour, alpha)
69
+
70
+ def circle(self, cx, cy, r, colour, alpha=1.0):
71
+ self.ellipse(cx, cy, r, r, colour, alpha)
72
+
73
+ def ellipse(self, cx, cy, rx, ry, colour, alpha=1.0):
74
+ def inside(px, py):
75
+ return ((px - cx) / rx) ** 2 + ((py - cy) / ry) ** 2 <= 1.0
76
+
77
+ self._paint(inside, (cx - rx, cy - ry, cx + rx, cy + ry), colour, alpha)
78
+
79
+ def ring(self, cx, cy, r, width, colour, alpha=1.0):
80
+ def inside(px, py):
81
+ d = math.hypot(px - cx, py - cy)
82
+ return r - width <= d <= r
83
+
84
+ self._paint(inside, (cx - r, cy - r, cx + r, cy + r), colour, alpha)
85
+
86
+ def poly(self, pts, colour, alpha=1.0):
87
+ xs = [p[0] for p in pts]; ys = [p[1] for p in pts]
88
+
89
+ def inside(px, py):
90
+ c = False
91
+ j = len(pts) - 1
92
+ for i in range(len(pts)):
93
+ xi, yi = pts[i]; xj, yj = pts[j]
94
+ if (yi > py) != (yj > py) and px < (xj - xi) * (py - yi) / (yj - yi) + xi:
95
+ c = not c
96
+ j = i
97
+ return c
98
+
99
+ self._paint(inside, (min(xs), min(ys), max(xs), max(ys)), colour, alpha)
100
+
101
+ def line(self, x0, y0, x1, y1, width, colour, alpha=1.0):
102
+ dx, dy = x1 - x0, y1 - y0
103
+ ln = math.hypot(dx, dy) or 1.0
104
+ nx, ny = -dy / ln * width / 2, dx / ln * width / 2
105
+ self.poly([(x0 + nx, y0 + ny), (x1 + nx, y1 + ny), (x1 - nx, y1 - ny), (x0 - nx, y0 - ny)], colour, alpha)
106
+ self.circle(x0, y0, width / 2, colour, alpha)
107
+ self.circle(x1, y1, width / 2, colour, alpha)
108
+
109
+ def rgba(self):
110
+ """Straight-alpha RGBA8 rows. Transparent pixels take the colour of
111
+ the nearest painted pixel (a few dilation passes), so filtering and
112
+ mips never pull a dark fringe into the edge."""
113
+ w, h = self.w, self.h
114
+ col = [None] * (w * h)
115
+ for i, p in enumerate(self.px):
116
+ if p[3] > 0:
117
+ col[i] = (p[0] / p[3], p[1] / p[3], p[2] / p[3])
118
+ for _ in range(8):
119
+ nxt = list(col)
120
+ changed = False
121
+ for y in range(h):
122
+ for x in range(w):
123
+ i = y * w + x
124
+ if col[i] is not None:
125
+ continue
126
+ for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
127
+ xx, yy = x + dx, y + dy
128
+ if 0 <= xx < w and 0 <= yy < h and col[yy * w + xx] is not None:
129
+ nxt[i] = col[yy * w + xx]
130
+ changed = True
131
+ break
132
+ col = nxt
133
+ if not changed:
134
+ break
135
+ rows = []
136
+ for y in range(h):
137
+ row = bytearray()
138
+ for x in range(w):
139
+ i = y * w + x
140
+ c = col[i] or (0.0, 0.0, 0.0)
141
+ a = self.px[i][3]
142
+ row += bytes([round(min(1, max(0, c[0])) * 255), round(min(1, max(0, c[1])) * 255),
143
+ round(min(1, max(0, c[2])) * 255), round(min(1, max(0, a)) * 255)])
144
+ rows.append(bytes(row))
145
+ return rows
146
+
147
+
148
+ def png_bytes(w, h, rows):
149
+ raw = b"".join(b"\x00" + r for r in rows)
150
+
151
+ def chunk(t, d):
152
+ return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xFFFFFFFF)
153
+
154
+ return (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0))
155
+ + chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
156
+
157
+
158
+ def write_glb(path, sprites):
159
+ """sprites: list of (name, png bytes, masked). One quad mesh per sprite,
160
+ in list order: GltfInfo.geometries[i] and materials[i] are sprite i."""
161
+ bin_ = bytearray()
162
+
163
+ def add(data, align=4):
164
+ while len(bin_) % align:
165
+ bin_.append(0)
166
+ off = len(bin_)
167
+ bin_.extend(data)
168
+ return off, len(data)
169
+
170
+ pos = struct.pack("<12f", -0.5, -0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, 0.5, 0)
171
+ nrm = struct.pack("<12f", *([0, 0, 1] * 4))
172
+ uv = struct.pack("<8f", 0, 1, 1, 1, 1, 0, 0, 0)
173
+ idx = struct.pack("<6H", 0, 1, 2, 0, 2, 3)
174
+ views, accessors = [], []
175
+ for data, target in ((pos, 34962), (nrm, 34962), (uv, 34962), (idx, 34963)):
176
+ o, n = add(data)
177
+ views.append({"buffer": 0, "byteOffset": o, "byteLength": n, "target": target})
178
+ accessors = [
179
+ {"bufferView": 0, "componentType": 5126, "count": 4, "type": "VEC3", "min": [-0.5, -0.5, 0], "max": [0.5, 0.5, 0]},
180
+ {"bufferView": 1, "componentType": 5126, "count": 4, "type": "VEC3"},
181
+ {"bufferView": 2, "componentType": 5126, "count": 4, "type": "VEC2"},
182
+ {"bufferView": 3, "componentType": 5123, "count": 6, "type": "SCALAR"},
183
+ ]
184
+ images, textures, materials, meshes, nodes = [], [], [], [], []
185
+ for i, (name, data, masked) in enumerate(sprites):
186
+ o, n = add(data)
187
+ views.append({"buffer": 0, "byteOffset": o, "byteLength": n})
188
+ images.append({"bufferView": len(views) - 1, "mimeType": "image/png", "name": name})
189
+ textures.append({"source": i, "sampler": 0})
190
+ m = {
191
+ "name": name,
192
+ "pbrMetallicRoughness": {"baseColorFactor": [0, 0, 0, 1], "baseColorTexture": {"index": i},
193
+ "metallicFactor": 0, "roughnessFactor": 1},
194
+ "emissiveTexture": {"index": i},
195
+ "emissiveFactor": [1, 1, 1],
196
+ }
197
+ if masked:
198
+ m["alphaMode"] = "MASK"
199
+ m["alphaCutoff"] = 0.5
200
+ materials.append(m)
201
+ meshes.append({"name": name, "primitives": [{"attributes": {"POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2},
202
+ "indices": 3, "material": i}]})
203
+ nodes.append({"name": name, "mesh": i, "translation": [i * 1.2, 0, 0]})
204
+ while len(bin_) % 4:
205
+ bin_.append(0)
206
+ doc = {
207
+ "asset": {"version": "2.0", "generator": "oglite.py"},
208
+ "scene": 0, "scenes": [{"nodes": list(range(len(nodes)))}], "nodes": nodes, "meshes": meshes,
209
+ "materials": materials, "textures": textures, "images": images,
210
+ "samplers": [{"magFilter": 9729, "minFilter": 9987, "wrapS": 33071, "wrapT": 33071}],
211
+ "accessors": accessors, "bufferViews": views, "buffers": [{"byteLength": len(bin_)}],
212
+ }
213
+ js = json.dumps(doc, separators=(",", ":")).encode()
214
+ while len(js) % 4:
215
+ js += b" "
216
+ out = struct.pack("<III", 0x46546C67, 2, 12 + 8 + len(js) + 8 + len(bin_))
217
+ out += struct.pack("<II", len(js), 0x4E4F534A) + js + struct.pack("<II", len(bin_), 0x004E4942) + bytes(bin_)
218
+ with open(path, "wb") as f:
219
+ f.write(out)
220
+
221
+
222
+ def write_wav(path, samples, rate=22050):
223
+ """samples: floats in [-1, 1], mono."""
224
+ with wave.open(path, "wb") as w:
225
+ w.setnchannels(1)
226
+ w.setsampwidth(2)
227
+ w.setframerate(rate)
228
+ w.writeframes(b"".join(struct.pack("<h", int(max(-1, min(1, s)) * 32000)) for s in samples))
229
+
230
+
231
+ def tone(seconds, f0, f1=None, rate=22050, shape="sine", attack=0.005, decay=None, gain=0.6):
232
+ """A sweep from f0 to f1 Hz with a short attack and an exponential decay."""
233
+ f1 = f0 if f1 is None else f1
234
+ n = int(seconds * rate)
235
+ out, phase = [], 0.0
236
+ decay = decay or seconds / 4
237
+ for i in range(n):
238
+ t = i / rate
239
+ f = f0 + (f1 - f0) * (i / max(1, n - 1))
240
+ phase += 2 * math.pi * f / rate
241
+ if shape == "square":
242
+ s = 1.0 if math.sin(phase) >= 0 else -1.0
243
+ s *= 0.5
244
+ elif shape == "tri":
245
+ s = 2 / math.pi * math.asin(math.sin(phase))
246
+ else:
247
+ s = math.sin(phase)
248
+ env = min(1.0, t / attack) * math.exp(-t / decay)
249
+ out.append(s * env * gain)
250
+ return out
251
+
252
+
253
+ def noise(seconds, rate=22050, decay=0.08, gain=0.5, seed=1):
254
+ x = seed & 0xFFFFFFFF
255
+ out = []
256
+ for i in range(int(seconds * rate)):
257
+ x ^= (x << 13) & 0xFFFFFFFF; x ^= x >> 17; x ^= (x << 5) & 0xFFFFFFFF
258
+ out.append(((x / 0xFFFFFFFF) * 2 - 1) * math.exp(-(i / rate) / decay) * gain)
259
+ return out
260
+
261
+
262
+ def mix(*parts):
263
+ n = max(len(p) for p in parts)
264
+ return [sum(p[i] for p in parts if i < len(p)) for i in range(n)]
265
+
266
+
267
+ def concat(*parts):
268
+ out = []
269
+ for p in parts:
270
+ out.extend(p)
271
+ return out
272
+
273
+
274
+ def subset_font(src, dst, text):
275
+ """Subset a TTF to Latin-1 plus `text` (needs fontTools)."""
276
+ from fontTools import subset
277
+ opts = subset.Options()
278
+ opts.name_IDs = ["*"]
279
+ opts.notdef_outline = True
280
+ opts.layout_features = []
281
+ font = subset.load_font(src, opts)
282
+ s = subset.Subsetter(opts)
283
+ s.populate(text="".join(chr(c) for c in range(0x20, 0x7F)) + "".join(chr(c) for c in range(0xA0, 0x100)) + text)
284
+ s.subset(font)
285
+ subset.save_font(font, dst, opts)
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022"],
7
+ "types": [],
8
+ "strict": true,
9
+ "exactOptionalPropertyTypes": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "isolatedModules": true,
12
+ "verbatimModuleSyntax": true,
13
+ "allowImportingTsExtensions": true,
14
+ "noEmit": true
15
+ },
16
+ "include": ["src/**/*.ts", "tests/**/*.ts", "host.d.ts"]
17
+ }
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+ # Prepares this Game's cloud sandbox snapshot: Origin runs it once per
3
+ # snapshot build, in the checkout, without a terminal, for at most 20 minutes,
4
+ # and saves the result for new sandboxes of the Game. Keep it idempotent; it
5
+ # never receives credentials. Only ignored output is kept: node_modules/ and
6
+ # cooked/ (og cook is incremental, so a new sandbox starts cooked).
7
+ set -eu
8
+ if [ -f bun.lock ]; then bun install --frozen-lockfile; else bun install; fi
9
+ og="${ORIGIN_OG_BIN:-og}"
10
+ if ! command -v "$og" >/dev/null 2>&1; then
11
+ echo "no og on this executor class; the first og run cooks instead"
12
+ exit 0
13
+ fi
14
+ "$og" cook .
@@ -0,0 +1,10 @@
1
+ # Asset licences
2
+
3
+ | File | Licence | Origin |
4
+ |---|---|---|
5
+ | `assets/tiles/dungeon.png`, `assets/tiles/*.ogt` | CC0 1.0 | self-made: the dungeon tileset (the wall terrain's 47 blob shapes, floor, moss, torch, door) drawn pixel by pixel by `tools/make-assets.py` (standard library only, deterministic), with its tileset and import settings |
6
+ | `assets/maps/tomb.tmj` | CC0 1.0 | self-made: the two-room Tiled map, same script |
7
+ | `assets/sprites/*.png`, `assets/sprites/*.ogt` | CC0 1.0 | self-made: the hero, slime, coin and key flipbook sheets, same script |
8
+ | `assets/audio/*.wav` | CC0 1.0 | self-made: synthesised tones and noise, same script |
9
+ | `assets/fonts/ui.ttf` | SIL Open Font License 1.1 (`assets/fonts/OFL.txt`) | Noto Sans SC Regular, subset to Latin-1 by the same script from the project template's `assets/fonts/NotoSansSC-Regular-subset.ttf` |
10
+ | `references/*/*.png` | CC0 1.0 | frames of this game recorded by `tests/frames.og.ts` |
@@ -0,0 +1,235 @@
1
+ # Tomb Room — the topdown archetype (2D)
2
+
3
+ A small Zelda-like. Two rooms of a tomb: a slime guards the west room and
4
+ the key in it, coins lie in both, and a locked door stands between them.
5
+ Walk with WASD or the arrows, swing the sword with Space, dash with Shift.
6
+ Take the key to the door and the east room opens.
7
+
8
+ 古墓房间:一个小型俯视角冒险。西边的房间里有史莱姆守着钥匙,两个房间都散落着金币,中间是一扇锁着的门。WASD 或方向键移动,空格挥剑,Shift 冲刺;拿到钥匙走到门前,东边的房间就打开了。
9
+
10
+ This is a complete Origin Engine project: `og run .` plays it headless,
11
+ `og build .` makes the play page, `og test .` runs its playtests. It shows
12
+ the 2D modules working together: a Tiled map with an auto-tiled, colliding
13
+ wall terrain; flipbook sprites with frame events; y-sorted sprites with
14
+ blob shadows; tweens, hit stop, camera trauma and kick, floating damage
15
+ numbers and afterimages; a 2D follow camera held inside each room by a
16
+ camera zone; and an enemy whose mind is data: a behaviour tree
17
+ (`assets/ai/slime.ogt`, og.ai) walking a grid made from the map's wall
18
+ collision (og.nav).
19
+
20
+ ```sh
21
+ og cook . # assets/ into cooked/ (og run and og build cook too)
22
+ og run . --headless --commands "0.2:key_down:KeyD;1.2:key_up:KeyD;1.3:screenshot:play.png;1.4:quit"
23
+ og test . # tests/*.og.ts through og run --headless --commands
24
+ og build . # dist/: the play page for the browser
25
+ ```
26
+
27
+ ## What it demonstrates, and the skills it exercises
28
+
29
+ The 2D modules together: a Tiled map with an auto-tiled, colliding wall
30
+ terrain the door opens through `og.tilemap.setTile` and reads back with
31
+ `getTile` (og-game §8), a four-direction flipbook hero on
32
+ og.CharacterController in its top-down mode whose walk steps are heard
33
+ (og-game §13; og-feel §9, §12; og-audio §1), a slime that patrols, chases,
34
+ bites and flees as og.ai data on an og.nav grid from the map (og-ai §1–§5),
35
+ hits felt five ways (hit stop, flash and squash, knockback, shake and kick,
36
+ floating damage and a crit) both ways (og-feel §3–§7), a dash with
37
+ afterimages, sorting by feet (og-feel §10), and a camera that follows with a
38
+ dead zone and scrolls between the rooms by og.CameraZone's scrollTime
39
+ (og-feel §8). `og polish .` (2026-10-19): feel 97 (taste n/a: the HUD is
40
+ screen-space text).
41
+
42
+
43
+ ## Rules
44
+
45
+ - **Moving.** WASD or the arrows move the hero at `Tuning.speed` on the
46
+ tick the keys are read; a diagonal is normalised. The hero faces the
47
+ stronger axis (a diagonal keeps the old facing when it is one of its keys).
48
+ The hero's body is `og.CharacterController` in its top-down mode
49
+ (`gravityScale` 0): a kinematic box the engine slides along the walls,
50
+ moved by `move` each tick (walk, dash and knockback summed). The slime
51
+ and the hero pass through each other.
52
+ - **The sword.** Space (or J) swings in the facing direction. The hero is
53
+ rooted for the swing's 15 ticks. Damage lands on the attack clip's strike
54
+ frame (its `"hit"` event), within `Tuning.reach` of a point one reach
55
+ ahead of the chest. Hits deal 12, 12, then a 26 crit: the slime (50 hp)
56
+ dies on the third.
57
+ - **The dash.** Shift (or K) dashes `Tuning.dashTicks` ticks at
58
+ `Tuning.dashSpeed` along the keys (or the facing), leaving afterimages;
59
+ then `Tuning.dashCooldown` ticks before the next.
60
+ - **The slime.** Its behaviour tree, `assets/ai/slime.ogt`, is re-checked
61
+ every tick, first branch first: under 30 hp, and having seen the hero in
62
+ the last 3 s, it **flees** to 5 m away; seeing the hero within 0.8 m it
63
+ **bites** (the game's `bite` command, every 0.5 s at most); seeing the
64
+ hero it **chases** at `Tuning.slimeSpeed`; having lost the hero in the
65
+ last 2 s it **searches** where it last saw it; otherwise it **patrols**
66
+ its beat (four points round the key's corner, 0.6 s at each). It sees all
67
+ round within `Tuning.slimeSight`, but not through walls (the pillar hides
68
+ the hero). og.nav walks it on the map's grid around the walls, writing its
69
+ velocity. A bite costs a heart, knocks the hero away and makes it blink
70
+ for `Tuning.iframes` ticks; the slime bounces back off the bite.
71
+ - **Pickups.** Coins and the key are taken when the hero's chest touches
72
+ them. The key is spent opening the door.
73
+ - **The door.** Without the key, walking up to it says "locked". With it,
74
+ the doorway's four wall cells clear (`og.tilemap.setTile` re-tiles their
75
+ neighbours and drops their colliders) and the hero walks into room 2.
76
+ - **Falling.** At 0 hearts the hero lies still for 90 ticks, then stands up
77
+ at the spawn with full hearts. Coins, the key and the door stay as they
78
+ are.
79
+
80
+ Everything is deterministic from the project seed: the clock is the fixed
81
+ tick, og.ai and og.nav are deterministic and in snapshots, the hovering is a triangle
82
+ wave, and `tests/replay.og.ts` replays a whole visit to the same hash.
83
+
84
+ ## How a hit feels
85
+
86
+ Each sword hit does five things at once, all in `hitSlime`
87
+ (`src/systems.ts`):
88
+
89
+ | Effect | Call | Default |
90
+ |---|---|---|
91
+ | flash and squash | `og.tween.flash`, `og.tween.squash` (their impact holds through the hit stop) | white for 0.14 s; 1.45 × 0.6 recovering in 0.28 s |
92
+ | knockback | the slime's `knockX/knockY`, decaying ×0.82 a tick | `Tuning.knockback` (9 m/s), 16 ticks stunned |
93
+ | hit stop | `og.time.hitStop` | `Tuning.hitStop` (4 ticks), 7 on the crit |
94
+ | camera | `og.camera.shake`, `og.camera.kick` | trauma `Tuning.shake` (0.25, ×1.8 on the crit); a 0.12 m kick away from the hero |
95
+ | damage number | `og.render.floatingText` | white, the crit gold and bigger |
96
+
97
+ The death is two more tweens: the scale to (1.7, 0) with `backIn` and the
98
+ sprite's opacity to 0; the slime hides 30 ticks later. Pickups pop up,
99
+ stretch and fade, and squash the hero a little.
100
+
101
+ ## The map
102
+
103
+ `assets/maps/tomb.tmj` is a Tiled map (orthogonal, 40 × 12 cells of
104
+ 16 px, uncompressed layers) over the tileset `assets/tiles/dungeon.ogt`
105
+ (Tiled's `../tiles/dungeon.tsx` reference resolves to it). One cell is one
106
+ world unit; the map's bottom-left corner is the world origin, y up.
107
+
108
+ | Layer | Kind | Holds |
109
+ |---|---|---|
110
+ | `floor` | tiles | three slab variants and moss |
111
+ | `walls` | terrain `wall` (`autotile`), `collision` | the outer walls, the dividing wall at x 19–20, three pillars; blob47 picks each cell's shape and the solid tiles collide |
112
+ | `door` | tiles | the door over the doorway's wall cells |
113
+ | `decor` | tiles, `z` = 15 | the animated torches on the north wall, drawn above the actors |
114
+ | `objects` | objects | `spawn`, `enemy` (the slime), `coin` ×6, `key`, `door` (the doorway's rectangle) and `room` ×2 (each room's rectangle) |
115
+
116
+ `start` (`src/main.ts`) reads the objects: actors spawn at their points,
117
+ the door's rectangle gives the cells to clear, and each room's rectangle
118
+ becomes an `og.CameraZone`. The hero carries `og.Follow2D` (a small dead
119
+ zone, `smoothTime` 0.12, `lookAhead` 0.15), and the orthographic view is
120
+ 12 cells tall: a whole room, as in the old top-down adventures, and the
121
+ view scrolls across to room 2 over the zones' `scrollTime` (0.45 s) when
122
+ the hero crosses the doorway (`tests/door.og.ts` samples og.Camera's zone
123
+ fields through the crossing with `get:og.Camera`).
124
+
125
+ ## State
126
+
127
+ | Type | Kind | What it holds |
128
+ |---|---|---|
129
+ | `Game` | resource | hearts, coins, the key, the door, the room, the slime's hp and hits, the hero's position and facing for the other systems, the strike of this tick, footsteps, invulnerability, knockback, the spawn, the door's cells, sound requests, the font |
130
+ | `Tuning` | resource | the knobs below |
131
+ | `Hero` | the hero | the swing and dash timers, the dash direction, dashes so far |
132
+ | `Slime` | the slime | hp, knockback, stun, bites, death, its clip indices (it also has `og.NavAgent`, `og.AiAgent` and `og.Perception`; the hero has `og.Perceivable`) |
133
+ | `Pickup` | coins and the key | kind, taken, the resting height |
134
+ | `Sfx` | one entity per sound | its `Sound.*` bit (the entity also has `og.AudioSource`) |
135
+ | `Report` | the hero | the run's facts, copied from `Game` each tick so `dump_entity:hero` shows them |
136
+
137
+ ## Systems (in tick order)
138
+
139
+ | System | Reads | Writes | Job |
140
+ |---|---|---|---|
141
+ | `Control` | `og.Input`, `Tuning`, `og.FlipbookEvent` | `Game`, `Hero`, `og.Transform`, `og.CharacterController`, `og.Flipbook`, `og.Sprite`, `og.Afterimage` | footsteps and strikes from the hero's frame events; walk, swing, dash, knockback, blinking, falling; the clip and flip |
142
+ | `Slimes` | `Tuning` | `Game`, `Slime`, `og.Transform`, `og.Velocity`, `og.Flipbook`, `og.Sprite`, `og.NavAgent`, `og.AiAgent`, `og.Perception` | take strikes (all five effects), knockback and stun (`NavAgent.drive` off meanwhile), death (the AI stops), sight from `Tuning.slimeSight` |
143
+ | `Pickups` | — | `Game`, `Pickup`, `og.Transform`, `og.Sprite` | hover, take by overlap, pop and fade |
144
+ | `Door` | — | `Game` | the room, "locked", opening the doorway |
145
+ | `Voices` | `Sfx` | `Game`, `og.AudioSource` | plays each requested sound once |
146
+ | `Hud` | `Game` | `Report` | screen text: hearts, coins, the key, the room, the controls for 5 s; the hero's `Report` |
147
+
148
+ og.ai runs before these systems (the slime's decision for the tick) and
149
+ og.nav after them (moving it). During a hit stop the systems still tick but
150
+ hold their timers, as physics, flipbooks and tweens do.
151
+
152
+ ## Tunables (`Tuning`)
153
+
154
+ | Field | Default | Range | Unit | What it changes |
155
+ |---|---|---|---|---|
156
+ | `speed` | 4.5 | 1–10 | m/s | walking pace |
157
+ | `dashSpeed` | 13 | 4–24 | m/s | the dash |
158
+ | `dashTicks` | 9 | 2–30 | ticks | the dash's length (dashSpeed × dashTicks / 60 m) |
159
+ | `dashCooldown` | 36 | 0–120 | ticks | ticks between dashes |
160
+ | `reach` | 0.75 | 0.2–2 | m | the sword's reach |
161
+ | `hitStop` | 4 | 0–12 | ticks | the freeze per hit (the crit adds 3) |
162
+ | `shake` | 0.25 | 0–1 | trauma | camera shake per hit |
163
+ | `slimeSpeed` | 1.6 | 0–6 | m/s | the slime's chase and search (the behaviour reads it; it patrols at 0.8) |
164
+ | `slimeSight` | 5 | 0–12 | m | how far the slime sees |
165
+ | `knockback` | 9 | 0–20 | m/s | both ways: the struck slime and the bitten hero |
166
+ | `iframes` | 50 | 0–180 | ticks | the hero's blinking after a bite |
167
+
168
+ They are the field defaults in `src/components.ts`.
169
+
170
+ ## What a Maker changes first
171
+
172
+ 1. **Feel**: `speed`, `dashSpeed`, `hitStop`, `shake`, `knockback` in
173
+ `Tuning`, and the damage list `DAMAGE` in `src/systems.ts`.
174
+ 2. **The level**: open `assets/maps/tomb.tmj` in Tiled. Paint the `walls`
175
+ layer with any tile (the terrain picks the shape), move the objects, add
176
+ coins (`type` coin) or rooms (`type` room). Keep the door's rectangle on
177
+ wall cells. Or change `map_layout` in `tools/make-assets.py`.
178
+ 3. **Enemies**: another `enemy` object needs its own name (the `slime`
179
+ command addresses `slime`); `Slimes` already loops over every slime.
180
+ What a slime does is `assets/ai/slime.ogt`: reorder the branches, change
181
+ the numbers, add a `wander` or a state machine (the nodes are listed in
182
+ the og-ai skill). `dump_ai:slime` shows the running node, the path to it,
183
+ the blackboard and what it sees; `dump_nav:slime` its path.
184
+ 4. **Look**: the tiles and sprites are drawn in `tools/make-assets.py`;
185
+ run `python3 tools/make-assets.py && og cook .`. The hero's clip order is
186
+ fixed (`src/art.ts` checks it).
187
+ 5. **Words**: the HUD strings in `Hud`. The font holds Latin-1 only; add
188
+ characters to `subset_font`'s text and `chars` in `ui.ttf.ogt` first.
189
+
190
+ ## Commands (for scripts and agents)
191
+
192
+ | Action | Does |
193
+ |---|---|
194
+ | `place:<x>:<y>` | puts the hero's feet at a world point, standing still |
195
+ | `slime:<x>:<y>` | moves the slime |
196
+ | `give:<key\|coin\|door>` | the key, a coin, or the doorway opened |
197
+ | `face:<down\|up\|left\|right>` | turns the hero |
198
+ | `bite:<slime>` | the behaviour's attack (og.ai queues it with the slime's handle): hurts a hero within 0.85 m |
199
+ | `dump_ai:slime[:file]`, `dump_nav:slime[:file]` | the slime's behaviour, running node, blackboard and perception; its path |
200
+ | core actions | `key_down:KeyD`/`key_up:KeyD` walk, `Space` swings, `ShiftLeft` dashes; `dump_entity:hero` shows `Report` |
201
+
202
+ `facts` (the probe's `state()`) reports `room`, `hp`, `coins`, `hasKey`,
203
+ `enemyHp`, `doorOpen`, `doorWall`, the hero's and slime's positions,
204
+ `facing`, `steps`, `swings`, `hits`, `hurts` and `dashes`.
205
+
206
+ ## Playtests (`og test .`)
207
+
208
+ | File | Proves |
209
+ |---|---|
210
+ | `tests/walk.og.ts` | one second of D walks 4.5 m; footsteps come from the walk clip's events; up and left stop at the wall terrain's colliders; facing, the side clip and its flip |
211
+ | `tests/ai.og.ts` | out of sight the slime patrols its beat on og.nav's path; the hero 3 m off is seen three ticks later and the patrol gives way to the chase at about 1.6 m/s; the bite lands through the `bite` command |
212
+ | `tests/flee.og.ts` | the pillar hides the hero 4.5 m away; below the pillar it is seen and chased; under 30 hp the slime flees and keeps over 3.5 m away |
213
+ | `tests/combat.og.ts` | a bite costs a heart and knocks the hero back; the hit stop holds the slime still, white and squashed; 12, 12, 26 kill it; it ends hidden and squashed to nothing |
214
+ | `tests/door.og.ts` | the doorway blocks without the key; walking over the key takes it; the door opens (the wall cell cleared), the key is spent, the hero reaches room 2 |
215
+ | `tests/frames.og.ts` | four frames match `references/<tier>/`: the west room at rest, the crit's freeze frame, a dash, the east room through the open doorway (`OG_FX_CAPTURE=1 og test .` records them) |
216
+ | `tests/replay.og.ts` | a whole visit, run twice in fresh processes, ends on the same world hash |
217
+
218
+ Each one fails when the behaviour it names is broken (checked by halving
219
+ the walk speed, dropping the hit's flash, leaving the doorway's walls in
220
+ place, drawing the map over the actors, and wandering by `Math.random`;
221
+ the AI ones by sight through walls, a bite that never lands and a flee
222
+ threshold of 0; `tests/evidence/E6/break-and-restore.md`).
223
+
224
+ ## Assets
225
+
226
+ `tools/make-assets.py` regenerates every asset byte for byte: the tileset
227
+ and its blob47 rules, the Tiled map, the flipbook sheets, the sounds and the
228
+ font subset. `LICENSES.md` lists them.
229
+
230
+ ## Known limits (engine gaps, not design)
231
+
232
+ - The playtests read most of the run through the hero's `Report` copy,
233
+ which predates `get:` on resources (E7); `set:Tuning.<field>=<value>`
234
+ now tunes the resource from the command channel.
235
+ - The blob shadows (0.35) barely show on the dark floor.
@@ -0,0 +1,49 @@
1
+ type behaviour
2
+ version 1
3
+ ---
4
+ # The slime (crates/og-ai/README.md has every node). og.ai runs it before
5
+ # the game's systems; the first branch that does not fail decides, and the
6
+ # tree is re-checked every tick, so seeing the hero halts the patrol at once.
7
+ name "slime"
8
+ route beat { # the west room's middle, round the key's corner
9
+ point 13.5 6.5 0
10
+ point 17.5 6.5 0
11
+ point 17.5 3.5 0
12
+ point 13.5 3.5 0
13
+ }
14
+ tree {
15
+ selector {
16
+ sequence flee { # hurt and recently threatened: keep away
17
+ check Slime.hp below 30
18
+ check sinceSeen below 3
19
+ flee {
20
+ speed 2.6
21
+ distance 5
22
+ }
23
+ }
24
+ sequence attack { # in reach: bite (the game's `bite` command)
25
+ check sees
26
+ check targetDistance below 0.8
27
+ command bite {
28
+ cooldown 0.5
29
+ }
30
+ }
31
+ sequence chase { # in sight (Perception.sight is Tuning.slimeSight)
32
+ check sees
33
+ chase {
34
+ speed Tuning.slimeSpeed
35
+ reach 0.6
36
+ }
37
+ }
38
+ sequence search { # lost it: go where it was last seen
39
+ check sinceSeen below 2
40
+ move_to lastSeen {
41
+ speed Tuning.slimeSpeed
42
+ }
43
+ }
44
+ patrol beat {
45
+ wait 0.6
46
+ speed 0.8
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,9 @@
1
+ type sfx
2
+ version 1
3
+ ---
4
+ # a short filtered noise tick: og.load.sound(world, "<this file>") plays it.
5
+ preset "footstep"
6
+ seed 0
7
+ pitch 1
8
+ length 1
9
+ volume 1