gamesteel 0.2.0 → 0.3.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 (469) hide show
  1. package/README.md +6 -5
  2. package/dist/gamesteel.js +123138 -1609
  3. package/dist/pkgs/art/catalogue.json +153 -0
  4. package/dist/pkgs/art/library/new-platformer/License.txt +28 -0
  5. package/dist/pkgs/art/library/new-platformer/bee.png +0 -0
  6. package/dist/pkgs/art/library/new-platformer/block-bang.png +0 -0
  7. package/dist/pkgs/art/library/new-platformer/block-coin.png +0 -0
  8. package/dist/pkgs/art/library/new-platformer/block.png +0 -0
  9. package/dist/pkgs/art/library/new-platformer/bomb.png +0 -0
  10. package/dist/pkgs/art/library/new-platformer/bush.png +0 -0
  11. package/dist/pkgs/art/library/new-platformer/cactus.png +0 -0
  12. package/dist/pkgs/art/library/new-platformer/clouds.png +0 -0
  13. package/dist/pkgs/art/library/new-platformer/coin-bronze.png +0 -0
  14. package/dist/pkgs/art/library/new-platformer/coin-silver.png +0 -0
  15. package/dist/pkgs/art/library/new-platformer/coin.png +0 -0
  16. package/dist/pkgs/art/library/new-platformer/crate.png +0 -0
  17. package/dist/pkgs/art/library/new-platformer/desert.png +0 -0
  18. package/dist/pkgs/art/library/new-platformer/dirt.png +0 -0
  19. package/dist/pkgs/art/library/new-platformer/fireball.png +0 -0
  20. package/dist/pkgs/art/library/new-platformer/fish.png +0 -0
  21. package/dist/pkgs/art/library/new-platformer/flag.png +0 -0
  22. package/dist/pkgs/art/library/new-platformer/fly.png +0 -0
  23. package/dist/pkgs/art/library/new-platformer/frog.png +0 -0
  24. package/dist/pkgs/art/library/new-platformer/gem-blue.png +0 -0
  25. package/dist/pkgs/art/library/new-platformer/gem-green.png +0 -0
  26. package/dist/pkgs/art/library/new-platformer/gem-red.png +0 -0
  27. package/dist/pkgs/art/library/new-platformer/gem-yellow.png +0 -0
  28. package/dist/pkgs/art/library/new-platformer/grass.png +0 -0
  29. package/dist/pkgs/art/library/new-platformer/heart.png +0 -0
  30. package/dist/pkgs/art/library/new-platformer/hero-beige.png +0 -0
  31. package/dist/pkgs/art/library/new-platformer/hero-green.png +0 -0
  32. package/dist/pkgs/art/library/new-platformer/hero-pink.png +0 -0
  33. package/dist/pkgs/art/library/new-platformer/hero-purple.png +0 -0
  34. package/dist/pkgs/art/library/new-platformer/hero-yellow.png +0 -0
  35. package/dist/pkgs/art/library/new-platformer/hills.png +0 -0
  36. package/dist/pkgs/art/library/new-platformer/key-blue.png +0 -0
  37. package/dist/pkgs/art/library/new-platformer/key-yellow.png +0 -0
  38. package/dist/pkgs/art/library/new-platformer/ladder.png +0 -0
  39. package/dist/pkgs/art/library/new-platformer/ladybug.png +0 -0
  40. package/dist/pkgs/art/library/new-platformer/lever.png +0 -0
  41. package/dist/pkgs/art/library/new-platformer/lock-blue.png +0 -0
  42. package/dist/pkgs/art/library/new-platformer/mouse.png +0 -0
  43. package/dist/pkgs/art/library/new-platformer/mushroom.png +0 -0
  44. package/dist/pkgs/art/library/new-platformer/mushrooms.png +0 -0
  45. package/dist/pkgs/art/library/new-platformer/purple.png +0 -0
  46. package/dist/pkgs/art/library/new-platformer/rock.png +0 -0
  47. package/dist/pkgs/art/library/new-platformer/sand.png +0 -0
  48. package/dist/pkgs/art/library/new-platformer/saw.png +0 -0
  49. package/dist/pkgs/art/library/new-platformer/sign-exit.png +0 -0
  50. package/dist/pkgs/art/library/new-platformer/sign-left.png +0 -0
  51. package/dist/pkgs/art/library/new-platformer/sign-right.png +0 -0
  52. package/dist/pkgs/art/library/new-platformer/sky.png +0 -0
  53. package/dist/pkgs/art/library/new-platformer/slime-fire.png +0 -0
  54. package/dist/pkgs/art/library/new-platformer/slime-spike.png +0 -0
  55. package/dist/pkgs/art/library/new-platformer/slime.png +0 -0
  56. package/dist/pkgs/art/library/new-platformer/snail.png +0 -0
  57. package/dist/pkgs/art/library/new-platformer/snow.png +0 -0
  58. package/dist/pkgs/art/library/new-platformer/spikes.png +0 -0
  59. package/dist/pkgs/art/library/new-platformer/spring.png +0 -0
  60. package/dist/pkgs/art/library/new-platformer/star.png +0 -0
  61. package/dist/pkgs/art/library/new-platformer/stone.png +0 -0
  62. package/dist/pkgs/art/library/new-platformer/torch.png +0 -0
  63. package/dist/pkgs/art/library/new-platformer/trees.png +0 -0
  64. package/dist/pkgs/art/library/new-platformer/worm.png +0 -0
  65. package/dist/pkgs/art/library/pixel-platformer/License.txt +28 -0
  66. package/dist/pkgs/art/library/pixel-platformer/angry-block.png +0 -0
  67. package/dist/pkgs/art/library/pixel-platformer/astronaut-beige.png +0 -0
  68. package/dist/pkgs/art/library/pixel-platformer/astronaut-blue.png +0 -0
  69. package/dist/pkgs/art/library/pixel-platformer/astronaut-green.png +0 -0
  70. package/dist/pkgs/art/library/pixel-platformer/astronaut-pink.png +0 -0
  71. package/dist/pkgs/art/library/pixel-platformer/astronaut-yellow.png +0 -0
  72. package/dist/pkgs/art/library/pixel-platformer/bat.png +0 -0
  73. package/dist/pkgs/art/library/pixel-platformer/block-bang.png +0 -0
  74. package/dist/pkgs/art/library/pixel-platformer/block-coin.png +0 -0
  75. package/dist/pkgs/art/library/pixel-platformer/block-yellow.png +0 -0
  76. package/dist/pkgs/art/library/pixel-platformer/cactus.png +0 -0
  77. package/dist/pkgs/art/library/pixel-platformer/coin.png +0 -0
  78. package/dist/pkgs/art/library/pixel-platformer/crate.png +0 -0
  79. package/dist/pkgs/art/library/pixel-platformer/crawler-bot.png +0 -0
  80. package/dist/pkgs/art/library/pixel-platformer/desert.png +0 -0
  81. package/dist/pkgs/art/library/pixel-platformer/drill-bot.png +0 -0
  82. package/dist/pkgs/art/library/pixel-platformer/flag.png +0 -0
  83. package/dist/pkgs/art/library/pixel-platformer/forest.png +0 -0
  84. package/dist/pkgs/art/library/pixel-platformer/gem.png +0 -0
  85. package/dist/pkgs/art/library/pixel-platformer/gold-imp.png +0 -0
  86. package/dist/pkgs/art/library/pixel-platformer/grass.png +0 -0
  87. package/dist/pkgs/art/library/pixel-platformer/heart-empty.png +0 -0
  88. package/dist/pkgs/art/library/pixel-platformer/heart-half.png +0 -0
  89. package/dist/pkgs/art/library/pixel-platformer/heart.png +0 -0
  90. package/dist/pkgs/art/library/pixel-platformer/key.png +0 -0
  91. package/dist/pkgs/art/library/pixel-platformer/ladder.png +0 -0
  92. package/dist/pkgs/art/library/pixel-platformer/lever.png +0 -0
  93. package/dist/pkgs/art/library/pixel-platformer/mushroom.png +0 -0
  94. package/dist/pkgs/art/library/pixel-platformer/sand.png +0 -0
  95. package/dist/pkgs/art/library/pixel-platformer/sign-left.png +0 -0
  96. package/dist/pkgs/art/library/pixel-platformer/sign-right.png +0 -0
  97. package/dist/pkgs/art/library/pixel-platformer/sky.png +0 -0
  98. package/dist/pkgs/art/library/pixel-platformer/snow.png +0 -0
  99. package/dist/pkgs/art/library/pixel-platformer/snowman.png +0 -0
  100. package/dist/pkgs/art/library/pixel-platformer/spikes.png +0 -0
  101. package/dist/pkgs/art/library/pixel-platformer/spiky-ball.png +0 -0
  102. package/dist/pkgs/art/library/pixel-platformer/spring.png +0 -0
  103. package/dist/pkgs/art/library/pixel-platformer/sprout.png +0 -0
  104. package/dist/pkgs/art/library/pixel-platformer/tank-bot.png +0 -0
  105. package/dist/pkgs/art/library/pixel-platformer/tree.png +0 -0
  106. package/dist/pkgs/art/library/puzzle/License.txt +21 -0
  107. package/dist/pkgs/art/library/puzzle/ball-blue.png +0 -0
  108. package/dist/pkgs/art/library/puzzle/ball-grey.png +0 -0
  109. package/dist/pkgs/art/library/puzzle/brick-blue.png +0 -0
  110. package/dist/pkgs/art/library/puzzle/brick-green.png +0 -0
  111. package/dist/pkgs/art/library/puzzle/brick-grey.png +0 -0
  112. package/dist/pkgs/art/library/puzzle/brick-purple.png +0 -0
  113. package/dist/pkgs/art/library/puzzle/brick-red.png +0 -0
  114. package/dist/pkgs/art/library/puzzle/brick-yellow.png +0 -0
  115. package/dist/pkgs/art/library/puzzle/diamond-blue.png +0 -0
  116. package/dist/pkgs/art/library/puzzle/diamond-green.png +0 -0
  117. package/dist/pkgs/art/library/puzzle/diamond-grey.png +0 -0
  118. package/dist/pkgs/art/library/puzzle/diamond-purple.png +0 -0
  119. package/dist/pkgs/art/library/puzzle/diamond-red.png +0 -0
  120. package/dist/pkgs/art/library/puzzle/diamond-yellow.png +0 -0
  121. package/dist/pkgs/art/library/puzzle/paddle-blue.png +0 -0
  122. package/dist/pkgs/art/library/puzzle/paddle-red.png +0 -0
  123. package/dist/pkgs/art/library/puzzle/star.png +0 -0
  124. package/dist/pkgs/art/library/tiny-dungeon/License.txt +22 -0
  125. package/dist/pkgs/art/library/tiny-dungeon/adventurer.png +0 -0
  126. package/dist/pkgs/art/library/tiny-dungeon/axe.png +0 -0
  127. package/dist/pkgs/art/library/tiny-dungeon/barrel.png +0 -0
  128. package/dist/pkgs/art/library/tiny-dungeon/bat.png +0 -0
  129. package/dist/pkgs/art/library/tiny-dungeon/chest-open.png +0 -0
  130. package/dist/pkgs/art/library/tiny-dungeon/chest.png +0 -0
  131. package/dist/pkgs/art/library/tiny-dungeon/cyclops.png +0 -0
  132. package/dist/pkgs/art/library/tiny-dungeon/dagger.png +0 -0
  133. package/dist/pkgs/art/library/tiny-dungeon/dark-wizard.png +0 -0
  134. package/dist/pkgs/art/library/tiny-dungeon/demon.png +0 -0
  135. package/dist/pkgs/art/library/tiny-dungeon/elder.png +0 -0
  136. package/dist/pkgs/art/library/tiny-dungeon/ghost.png +0 -0
  137. package/dist/pkgs/art/library/tiny-dungeon/guard.png +0 -0
  138. package/dist/pkgs/art/library/tiny-dungeon/hammer.png +0 -0
  139. package/dist/pkgs/art/library/tiny-dungeon/knight.png +0 -0
  140. package/dist/pkgs/art/library/tiny-dungeon/mimic.png +0 -0
  141. package/dist/pkgs/art/library/tiny-dungeon/monk.png +0 -0
  142. package/dist/pkgs/art/library/tiny-dungeon/orc.png +0 -0
  143. package/dist/pkgs/art/library/tiny-dungeon/potion-blue.png +0 -0
  144. package/dist/pkgs/art/library/tiny-dungeon/potion-green.png +0 -0
  145. package/dist/pkgs/art/library/tiny-dungeon/potion-red.png +0 -0
  146. package/dist/pkgs/art/library/tiny-dungeon/princess.png +0 -0
  147. package/dist/pkgs/art/library/tiny-dungeon/shield.png +0 -0
  148. package/dist/pkgs/art/library/tiny-dungeon/slime.png +0 -0
  149. package/dist/pkgs/art/library/tiny-dungeon/snake.png +0 -0
  150. package/dist/pkgs/art/library/tiny-dungeon/soldier.png +0 -0
  151. package/dist/pkgs/art/library/tiny-dungeon/spider.png +0 -0
  152. package/dist/pkgs/art/library/tiny-dungeon/staff.png +0 -0
  153. package/dist/pkgs/art/library/tiny-dungeon/stone-wall.png +0 -0
  154. package/dist/pkgs/art/library/tiny-dungeon/sword.png +0 -0
  155. package/dist/pkgs/art/library/tiny-dungeon/viking.png +0 -0
  156. package/dist/pkgs/art/library/tiny-dungeon/villager.png +0 -0
  157. package/dist/pkgs/art/library/tiny-dungeon/wizard.png +0 -0
  158. package/dist/pkgs/art/library/tiny-dungeon/worm.png +0 -0
  159. package/dist/pkgs/artgen/dist/draw-worker.js +1574 -0
  160. package/dist/pkgs/audio/dist/worker.js +76965 -0
  161. package/dist/pkgs/fonts/files/bungee.ttf +0 -0
  162. package/dist/pkgs/fonts/files/cinzel.ttf +0 -0
  163. package/dist/pkgs/fonts/files/fredoka.ttf +0 -0
  164. package/dist/pkgs/fonts/files/inter.ttf +0 -0
  165. package/dist/pkgs/fonts/files/lilita-one.ttf +0 -0
  166. package/dist/pkgs/fonts/files/luckiest-guy.ttf +0 -0
  167. package/dist/pkgs/fonts/files/medievalsharp.ttf +0 -0
  168. package/dist/pkgs/fonts/files/orbitron.ttf +0 -0
  169. package/dist/pkgs/fonts/files/patrick-hand.ttf +0 -0
  170. package/dist/pkgs/fonts/files/pixelify.ttf +0 -0
  171. package/dist/pkgs/fonts/files/press-start.ttf +0 -0
  172. package/dist/pkgs/fonts/files/russo-one.ttf +0 -0
  173. package/dist/pkgs/fonts/files/silkscreen.ttf +0 -0
  174. package/dist/pkgs/fonts/files/varela-round.ttf +0 -0
  175. package/dist/pkgs/fonts/licences/bungee.txt +93 -0
  176. package/dist/pkgs/fonts/licences/cinzel.txt +94 -0
  177. package/dist/pkgs/fonts/licences/fredoka.txt +93 -0
  178. package/dist/pkgs/fonts/licences/inter.txt +92 -0
  179. package/dist/pkgs/fonts/licences/lilita-one.txt +94 -0
  180. package/dist/pkgs/fonts/licences/luckiest-guy.txt +202 -0
  181. package/dist/pkgs/fonts/licences/medievalsharp.txt +105 -0
  182. package/dist/pkgs/fonts/licences/orbitron.txt +105 -0
  183. package/dist/pkgs/fonts/licences/patrick-hand.txt +93 -0
  184. package/dist/pkgs/fonts/licences/pixelify.txt +93 -0
  185. package/dist/pkgs/fonts/licences/press-start.txt +93 -0
  186. package/dist/pkgs/fonts/licences/russo-one.txt +93 -0
  187. package/dist/pkgs/fonts/licences/silkscreen.txt +93 -0
  188. package/dist/pkgs/fonts/licences/varela-round.txt +93 -0
  189. package/dist/pkgs/instruments/licences/musescore-general.txt +92 -0
  190. package/dist/pkgs/model/blender/builder.py +741 -0
  191. package/dist/pkgs/model/dist/worker.js +58006 -0
  192. package/dist/pkgs/paint/dist/worker.js +56328 -0
  193. package/dist/pkgs/soundlib/catalogue.json +2606 -0
  194. package/dist/pkgs/soundlib/library/kenney-digital/high-down.wav +0 -0
  195. package/dist/pkgs/soundlib/library/kenney-digital/high-up.wav +0 -0
  196. package/dist/pkgs/soundlib/library/kenney-digital/laser-1.wav +0 -0
  197. package/dist/pkgs/soundlib/library/kenney-digital/laser-2.wav +0 -0
  198. package/dist/pkgs/soundlib/library/kenney-digital/laser-3.wav +0 -0
  199. package/dist/pkgs/soundlib/library/kenney-digital/low-down.wav +0 -0
  200. package/dist/pkgs/soundlib/library/kenney-digital/low-random.wav +0 -0
  201. package/dist/pkgs/soundlib/library/kenney-digital/low-three-tone.wav +0 -0
  202. package/dist/pkgs/soundlib/library/kenney-digital/pep-sound-1.wav +0 -0
  203. package/dist/pkgs/soundlib/library/kenney-digital/pep-sound-2.wav +0 -0
  204. package/dist/pkgs/soundlib/library/kenney-digital/pep-sound-3.wav +0 -0
  205. package/dist/pkgs/soundlib/library/kenney-digital/phase-jump-1.wav +0 -0
  206. package/dist/pkgs/soundlib/library/kenney-digital/phase-jump-2.wav +0 -0
  207. package/dist/pkgs/soundlib/library/kenney-digital/phase-jump-3.wav +0 -0
  208. package/dist/pkgs/soundlib/library/kenney-digital/phaser-down-1.wav +0 -0
  209. package/dist/pkgs/soundlib/library/kenney-digital/phaser-down-2.wav +0 -0
  210. package/dist/pkgs/soundlib/library/kenney-digital/phaser-down-3.wav +0 -0
  211. package/dist/pkgs/soundlib/library/kenney-digital/phaser-up-1.wav +0 -0
  212. package/dist/pkgs/soundlib/library/kenney-digital/phaser-up-2.wav +0 -0
  213. package/dist/pkgs/soundlib/library/kenney-digital/phaser-up-3.wav +0 -0
  214. package/dist/pkgs/soundlib/library/kenney-digital/power-up-1.wav +0 -0
  215. package/dist/pkgs/soundlib/library/kenney-digital/power-up-10.wav +0 -0
  216. package/dist/pkgs/soundlib/library/kenney-digital/power-up-11.wav +0 -0
  217. package/dist/pkgs/soundlib/library/kenney-digital/space-trash-1.wav +0 -0
  218. package/dist/pkgs/soundlib/library/kenney-digital/space-trash-2.wav +0 -0
  219. package/dist/pkgs/soundlib/library/kenney-digital/space-trash-3.wav +0 -0
  220. package/dist/pkgs/soundlib/library/kenney-digital/three-tone-1.wav +0 -0
  221. package/dist/pkgs/soundlib/library/kenney-digital/three-tone-2.wav +0 -0
  222. package/dist/pkgs/soundlib/library/kenney-digital/tone-1.wav +0 -0
  223. package/dist/pkgs/soundlib/library/kenney-digital/two-tone-1.wav +0 -0
  224. package/dist/pkgs/soundlib/library/kenney-digital/two-tone-2.wav +0 -0
  225. package/dist/pkgs/soundlib/library/kenney-digital/zap-1.wav +0 -0
  226. package/dist/pkgs/soundlib/library/kenney-digital/zap-2.wav +0 -0
  227. package/dist/pkgs/soundlib/library/kenney-digital/zap-three-tone-down.wav +0 -0
  228. package/dist/pkgs/soundlib/library/kenney-digital/zap-three-tone-up.wav +0 -0
  229. package/dist/pkgs/soundlib/library/kenney-digital/zap-two-tone-2.wav +0 -0
  230. package/dist/pkgs/soundlib/library/kenney-digital/zap-two-tone.wav +0 -0
  231. package/dist/pkgs/soundlib/library/kenney-impact/footstep-carpet-000.wav +0 -0
  232. package/dist/pkgs/soundlib/library/kenney-impact/footstep-carpet-001.wav +0 -0
  233. package/dist/pkgs/soundlib/library/kenney-impact/footstep-carpet-002.wav +0 -0
  234. package/dist/pkgs/soundlib/library/kenney-impact/footstep-concrete-000.wav +0 -0
  235. package/dist/pkgs/soundlib/library/kenney-impact/footstep-concrete-001.wav +0 -0
  236. package/dist/pkgs/soundlib/library/kenney-impact/footstep-concrete-002.wav +0 -0
  237. package/dist/pkgs/soundlib/library/kenney-impact/footstep-grass-000.wav +0 -0
  238. package/dist/pkgs/soundlib/library/kenney-impact/footstep-grass-001.wav +0 -0
  239. package/dist/pkgs/soundlib/library/kenney-impact/footstep-grass-002.wav +0 -0
  240. package/dist/pkgs/soundlib/library/kenney-impact/footstep-snow-000.wav +0 -0
  241. package/dist/pkgs/soundlib/library/kenney-impact/footstep-snow-001.wav +0 -0
  242. package/dist/pkgs/soundlib/library/kenney-impact/footstep-snow-002.wav +0 -0
  243. package/dist/pkgs/soundlib/library/kenney-impact/footstep-wood-000.wav +0 -0
  244. package/dist/pkgs/soundlib/library/kenney-impact/footstep-wood-001.wav +0 -0
  245. package/dist/pkgs/soundlib/library/kenney-impact/footstep-wood-002.wav +0 -0
  246. package/dist/pkgs/soundlib/library/kenney-impact/impact-bell-heavy-000.wav +0 -0
  247. package/dist/pkgs/soundlib/library/kenney-impact/impact-bell-heavy-001.wav +0 -0
  248. package/dist/pkgs/soundlib/library/kenney-impact/impact-bell-heavy-002.wav +0 -0
  249. package/dist/pkgs/soundlib/library/kenney-impact/impact-generic-light-000.wav +0 -0
  250. package/dist/pkgs/soundlib/library/kenney-impact/impact-generic-light-001.wav +0 -0
  251. package/dist/pkgs/soundlib/library/kenney-impact/impact-generic-light-002.wav +0 -0
  252. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-heavy-000.wav +0 -0
  253. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-heavy-001.wav +0 -0
  254. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-heavy-002.wav +0 -0
  255. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-light-000.wav +0 -0
  256. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-light-001.wav +0 -0
  257. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-light-002.wav +0 -0
  258. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-medium-000.wav +0 -0
  259. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-medium-001.wav +0 -0
  260. package/dist/pkgs/soundlib/library/kenney-impact/impact-glass-medium-002.wav +0 -0
  261. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-heavy-000.wav +0 -0
  262. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-heavy-001.wav +0 -0
  263. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-heavy-002.wav +0 -0
  264. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-light-000.wav +0 -0
  265. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-light-001.wav +0 -0
  266. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-light-002.wav +0 -0
  267. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-medium-000.wav +0 -0
  268. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-medium-001.wav +0 -0
  269. package/dist/pkgs/soundlib/library/kenney-impact/impact-metal-medium-002.wav +0 -0
  270. package/dist/pkgs/soundlib/library/kenney-impact/impact-mining-000.wav +0 -0
  271. package/dist/pkgs/soundlib/library/kenney-impact/impact-mining-001.wav +0 -0
  272. package/dist/pkgs/soundlib/library/kenney-impact/impact-mining-002.wav +0 -0
  273. package/dist/pkgs/soundlib/library/kenney-impact/impact-plank-medium-000.wav +0 -0
  274. package/dist/pkgs/soundlib/library/kenney-impact/impact-plank-medium-001.wav +0 -0
  275. package/dist/pkgs/soundlib/library/kenney-impact/impact-plank-medium-002.wav +0 -0
  276. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-heavy-000.wav +0 -0
  277. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-heavy-001.wav +0 -0
  278. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-heavy-002.wav +0 -0
  279. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-light-000.wav +0 -0
  280. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-light-001.wav +0 -0
  281. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-light-002.wav +0 -0
  282. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-medium-000.wav +0 -0
  283. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-medium-001.wav +0 -0
  284. package/dist/pkgs/soundlib/library/kenney-impact/impact-plate-medium-002.wav +0 -0
  285. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-heavy-000.wav +0 -0
  286. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-heavy-001.wav +0 -0
  287. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-heavy-002.wav +0 -0
  288. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-medium-000.wav +0 -0
  289. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-medium-001.wav +0 -0
  290. package/dist/pkgs/soundlib/library/kenney-impact/impact-punch-medium-002.wav +0 -0
  291. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-heavy-000.wav +0 -0
  292. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-heavy-001.wav +0 -0
  293. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-heavy-002.wav +0 -0
  294. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-medium-000.wav +0 -0
  295. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-medium-001.wav +0 -0
  296. package/dist/pkgs/soundlib/library/kenney-impact/impact-soft-medium-002.wav +0 -0
  297. package/dist/pkgs/soundlib/library/kenney-impact/impact-tin-medium-000.wav +0 -0
  298. package/dist/pkgs/soundlib/library/kenney-impact/impact-tin-medium-001.wav +0 -0
  299. package/dist/pkgs/soundlib/library/kenney-impact/impact-tin-medium-002.wav +0 -0
  300. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-heavy-000.wav +0 -0
  301. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-heavy-001.wav +0 -0
  302. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-heavy-002.wav +0 -0
  303. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-light-000.wav +0 -0
  304. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-light-001.wav +0 -0
  305. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-light-002.wav +0 -0
  306. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-medium-000.wav +0 -0
  307. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-medium-001.wav +0 -0
  308. package/dist/pkgs/soundlib/library/kenney-impact/impact-wood-medium-002.wav +0 -0
  309. package/dist/pkgs/soundlib/library/kenney-interface/back-001.wav +0 -0
  310. package/dist/pkgs/soundlib/library/kenney-interface/back-002.wav +0 -0
  311. package/dist/pkgs/soundlib/library/kenney-interface/back-003.wav +0 -0
  312. package/dist/pkgs/soundlib/library/kenney-interface/bong-001.wav +0 -0
  313. package/dist/pkgs/soundlib/library/kenney-interface/click-001.wav +0 -0
  314. package/dist/pkgs/soundlib/library/kenney-interface/click-002.wav +0 -0
  315. package/dist/pkgs/soundlib/library/kenney-interface/click-003.wav +0 -0
  316. package/dist/pkgs/soundlib/library/kenney-interface/close-001.wav +0 -0
  317. package/dist/pkgs/soundlib/library/kenney-interface/close-002.wav +0 -0
  318. package/dist/pkgs/soundlib/library/kenney-interface/close-003.wav +0 -0
  319. package/dist/pkgs/soundlib/library/kenney-interface/confirmation-001.wav +0 -0
  320. package/dist/pkgs/soundlib/library/kenney-interface/confirmation-002.wav +0 -0
  321. package/dist/pkgs/soundlib/library/kenney-interface/confirmation-003.wav +0 -0
  322. package/dist/pkgs/soundlib/library/kenney-interface/drop-001.wav +0 -0
  323. package/dist/pkgs/soundlib/library/kenney-interface/drop-002.wav +0 -0
  324. package/dist/pkgs/soundlib/library/kenney-interface/drop-003.wav +0 -0
  325. package/dist/pkgs/soundlib/library/kenney-interface/error-001.wav +0 -0
  326. package/dist/pkgs/soundlib/library/kenney-interface/error-002.wav +0 -0
  327. package/dist/pkgs/soundlib/library/kenney-interface/error-003.wav +0 -0
  328. package/dist/pkgs/soundlib/library/kenney-interface/glass-001.wav +0 -0
  329. package/dist/pkgs/soundlib/library/kenney-interface/glass-002.wav +0 -0
  330. package/dist/pkgs/soundlib/library/kenney-interface/glass-003.wav +0 -0
  331. package/dist/pkgs/soundlib/library/kenney-interface/glitch-001.wav +0 -0
  332. package/dist/pkgs/soundlib/library/kenney-interface/glitch-002.wav +0 -0
  333. package/dist/pkgs/soundlib/library/kenney-interface/glitch-003.wav +0 -0
  334. package/dist/pkgs/soundlib/library/kenney-interface/maximize-001.wav +0 -0
  335. package/dist/pkgs/soundlib/library/kenney-interface/maximize-002.wav +0 -0
  336. package/dist/pkgs/soundlib/library/kenney-interface/maximize-003.wav +0 -0
  337. package/dist/pkgs/soundlib/library/kenney-interface/minimize-001.wav +0 -0
  338. package/dist/pkgs/soundlib/library/kenney-interface/minimize-002.wav +0 -0
  339. package/dist/pkgs/soundlib/library/kenney-interface/minimize-003.wav +0 -0
  340. package/dist/pkgs/soundlib/library/kenney-interface/open-001.wav +0 -0
  341. package/dist/pkgs/soundlib/library/kenney-interface/open-002.wav +0 -0
  342. package/dist/pkgs/soundlib/library/kenney-interface/open-003.wav +0 -0
  343. package/dist/pkgs/soundlib/library/kenney-interface/pluck-001.wav +0 -0
  344. package/dist/pkgs/soundlib/library/kenney-interface/pluck-002.wav +0 -0
  345. package/dist/pkgs/soundlib/library/kenney-interface/question-001.wav +0 -0
  346. package/dist/pkgs/soundlib/library/kenney-interface/question-002.wav +0 -0
  347. package/dist/pkgs/soundlib/library/kenney-interface/question-003.wav +0 -0
  348. package/dist/pkgs/soundlib/library/kenney-interface/scratch-001.wav +0 -0
  349. package/dist/pkgs/soundlib/library/kenney-interface/scratch-002.wav +0 -0
  350. package/dist/pkgs/soundlib/library/kenney-interface/scratch-003.wav +0 -0
  351. package/dist/pkgs/soundlib/library/kenney-interface/scroll-001.wav +0 -0
  352. package/dist/pkgs/soundlib/library/kenney-interface/scroll-002.wav +0 -0
  353. package/dist/pkgs/soundlib/library/kenney-interface/scroll-003.wav +0 -0
  354. package/dist/pkgs/soundlib/library/kenney-interface/select-001.wav +0 -0
  355. package/dist/pkgs/soundlib/library/kenney-interface/select-002.wav +0 -0
  356. package/dist/pkgs/soundlib/library/kenney-interface/select-003.wav +0 -0
  357. package/dist/pkgs/soundlib/library/kenney-interface/switch-001.wav +0 -0
  358. package/dist/pkgs/soundlib/library/kenney-interface/switch-002.wav +0 -0
  359. package/dist/pkgs/soundlib/library/kenney-interface/switch-003.wav +0 -0
  360. package/dist/pkgs/soundlib/library/kenney-interface/tick-001.wav +0 -0
  361. package/dist/pkgs/soundlib/library/kenney-interface/tick-002.wav +0 -0
  362. package/dist/pkgs/soundlib/library/kenney-interface/tick-004.wav +0 -0
  363. package/dist/pkgs/soundlib/library/kenney-interface/toggle-001.wav +0 -0
  364. package/dist/pkgs/soundlib/library/kenney-interface/toggle-002.wav +0 -0
  365. package/dist/pkgs/soundlib/library/kenney-interface/toggle-003.wav +0 -0
  366. package/dist/pkgs/soundlib/library/kenney-rpg/belt-handle-1.wav +0 -0
  367. package/dist/pkgs/soundlib/library/kenney-rpg/belt-handle-2.wav +0 -0
  368. package/dist/pkgs/soundlib/library/kenney-rpg/book-close.wav +0 -0
  369. package/dist/pkgs/soundlib/library/kenney-rpg/book-flip-1.wav +0 -0
  370. package/dist/pkgs/soundlib/library/kenney-rpg/book-flip-2.wav +0 -0
  371. package/dist/pkgs/soundlib/library/kenney-rpg/book-flip-3.wav +0 -0
  372. package/dist/pkgs/soundlib/library/kenney-rpg/book-open.wav +0 -0
  373. package/dist/pkgs/soundlib/library/kenney-rpg/book-place-1.wav +0 -0
  374. package/dist/pkgs/soundlib/library/kenney-rpg/book-place-2.wav +0 -0
  375. package/dist/pkgs/soundlib/library/kenney-rpg/book-place-3.wav +0 -0
  376. package/dist/pkgs/soundlib/library/kenney-rpg/chop.wav +0 -0
  377. package/dist/pkgs/soundlib/library/kenney-rpg/cloth-1.wav +0 -0
  378. package/dist/pkgs/soundlib/library/kenney-rpg/cloth-2.wav +0 -0
  379. package/dist/pkgs/soundlib/library/kenney-rpg/cloth-3.wav +0 -0
  380. package/dist/pkgs/soundlib/library/kenney-rpg/cloth-belt-2.wav +0 -0
  381. package/dist/pkgs/soundlib/library/kenney-rpg/cloth-belt.wav +0 -0
  382. package/dist/pkgs/soundlib/library/kenney-rpg/creak-1.wav +0 -0
  383. package/dist/pkgs/soundlib/library/kenney-rpg/creak-2.wav +0 -0
  384. package/dist/pkgs/soundlib/library/kenney-rpg/creak-3.wav +0 -0
  385. package/dist/pkgs/soundlib/library/kenney-rpg/door-close-1.wav +0 -0
  386. package/dist/pkgs/soundlib/library/kenney-rpg/door-close-2.wav +0 -0
  387. package/dist/pkgs/soundlib/library/kenney-rpg/door-close-3.wav +0 -0
  388. package/dist/pkgs/soundlib/library/kenney-rpg/door-open-1.wav +0 -0
  389. package/dist/pkgs/soundlib/library/kenney-rpg/door-open-2.wav +0 -0
  390. package/dist/pkgs/soundlib/library/kenney-rpg/draw-knife-1.wav +0 -0
  391. package/dist/pkgs/soundlib/library/kenney-rpg/draw-knife-2.wav +0 -0
  392. package/dist/pkgs/soundlib/library/kenney-rpg/draw-knife-3.wav +0 -0
  393. package/dist/pkgs/soundlib/library/kenney-rpg/drop-leather.wav +0 -0
  394. package/dist/pkgs/soundlib/library/kenney-rpg/footstep-00.wav +0 -0
  395. package/dist/pkgs/soundlib/library/kenney-rpg/footstep-01.wav +0 -0
  396. package/dist/pkgs/soundlib/library/kenney-rpg/footstep-02.wav +0 -0
  397. package/dist/pkgs/soundlib/library/kenney-rpg/handle-coins-2.wav +0 -0
  398. package/dist/pkgs/soundlib/library/kenney-rpg/handle-coins.wav +0 -0
  399. package/dist/pkgs/soundlib/library/kenney-rpg/handle-small-leather-2.wav +0 -0
  400. package/dist/pkgs/soundlib/library/kenney-rpg/handle-small-leather.wav +0 -0
  401. package/dist/pkgs/soundlib/library/kenney-rpg/knife-slice-2.wav +0 -0
  402. package/dist/pkgs/soundlib/library/kenney-rpg/knife-slice.wav +0 -0
  403. package/dist/pkgs/soundlib/library/kenney-rpg/metal-click.wav +0 -0
  404. package/dist/pkgs/soundlib/library/kenney-rpg/metal-latch.wav +0 -0
  405. package/dist/pkgs/soundlib/library/kenney-rpg/metal-pot-1.wav +0 -0
  406. package/dist/pkgs/soundlib/library/kenney-rpg/metal-pot-2.wav +0 -0
  407. package/dist/pkgs/soundlib/library/kenney-rpg/metal-pot-3.wav +0 -0
  408. package/dist/pkgs/soundlib/library/kenney-scifi/computer-noise-000.wav +0 -0
  409. package/dist/pkgs/soundlib/library/kenney-scifi/computer-noise-001.wav +0 -0
  410. package/dist/pkgs/soundlib/library/kenney-scifi/computer-noise-002.wav +0 -0
  411. package/dist/pkgs/soundlib/library/kenney-scifi/door-close-000.wav +0 -0
  412. package/dist/pkgs/soundlib/library/kenney-scifi/door-close-001.wav +0 -0
  413. package/dist/pkgs/soundlib/library/kenney-scifi/door-close-002.wav +0 -0
  414. package/dist/pkgs/soundlib/library/kenney-scifi/door-open-000.wav +0 -0
  415. package/dist/pkgs/soundlib/library/kenney-scifi/door-open-001.wav +0 -0
  416. package/dist/pkgs/soundlib/library/kenney-scifi/door-open-002.wav +0 -0
  417. package/dist/pkgs/soundlib/library/kenney-scifi/explosion-crunch-000.wav +0 -0
  418. package/dist/pkgs/soundlib/library/kenney-scifi/explosion-crunch-001.wav +0 -0
  419. package/dist/pkgs/soundlib/library/kenney-scifi/explosion-crunch-002.wav +0 -0
  420. package/dist/pkgs/soundlib/library/kenney-scifi/force-field-000.wav +0 -0
  421. package/dist/pkgs/soundlib/library/kenney-scifi/force-field-001.wav +0 -0
  422. package/dist/pkgs/soundlib/library/kenney-scifi/force-field-002.wav +0 -0
  423. package/dist/pkgs/soundlib/library/kenney-scifi/impact-metal-000.wav +0 -0
  424. package/dist/pkgs/soundlib/library/kenney-scifi/impact-metal-001.wav +0 -0
  425. package/dist/pkgs/soundlib/library/kenney-scifi/impact-metal-002.wav +0 -0
  426. package/dist/pkgs/soundlib/library/kenney-scifi/laser-large-000.wav +0 -0
  427. package/dist/pkgs/soundlib/library/kenney-scifi/laser-large-001.wav +0 -0
  428. package/dist/pkgs/soundlib/library/kenney-scifi/laser-large-002.wav +0 -0
  429. package/dist/pkgs/soundlib/library/kenney-scifi/laser-retro-000.wav +0 -0
  430. package/dist/pkgs/soundlib/library/kenney-scifi/laser-retro-001.wav +0 -0
  431. package/dist/pkgs/soundlib/library/kenney-scifi/laser-retro-002.wav +0 -0
  432. package/dist/pkgs/soundlib/library/kenney-scifi/laser-small-000.wav +0 -0
  433. package/dist/pkgs/soundlib/library/kenney-scifi/laser-small-001.wav +0 -0
  434. package/dist/pkgs/soundlib/library/kenney-scifi/laser-small-002.wav +0 -0
  435. package/dist/pkgs/soundlib/library/kenney-scifi/low-frequency-explosion-000.wav +0 -0
  436. package/dist/pkgs/soundlib/library/kenney-scifi/low-frequency-explosion-001.wav +0 -0
  437. package/dist/pkgs/soundlib/library/kenney-scifi/slime-000.wav +0 -0
  438. package/dist/pkgs/soundlib/library/kenney-scifi/slime-001.wav +0 -0
  439. package/dist/pkgs/soundlib/library/kenney-scifi/thruster-fire-000.wav +0 -0
  440. package/dist/pkgs/soundlib/library/kenney-scifi/thruster-fire-001.wav +0 -0
  441. package/dist/pkgs/soundlib/library/kenney-scifi/thruster-fire-002.wav +0 -0
  442. package/dist/pkgs/soundlib/library/kenney-ui/click-1.wav +0 -0
  443. package/dist/pkgs/soundlib/library/kenney-ui/click-2.wav +0 -0
  444. package/dist/pkgs/soundlib/library/kenney-ui/click-3.wav +0 -0
  445. package/dist/pkgs/soundlib/library/kenney-ui/mouseclick-1.wav +0 -0
  446. package/dist/pkgs/soundlib/library/kenney-ui/mouserelease-1.wav +0 -0
  447. package/dist/pkgs/soundlib/library/kenney-ui/rollover-1.wav +0 -0
  448. package/dist/pkgs/soundlib/library/kenney-ui/rollover-2.wav +0 -0
  449. package/dist/pkgs/soundlib/library/kenney-ui/rollover-3.wav +0 -0
  450. package/dist/pkgs/soundlib/library/kenney-ui/switch-1.wav +0 -0
  451. package/dist/pkgs/soundlib/library/kenney-ui/switch-10.wav +0 -0
  452. package/dist/pkgs/soundlib/library/kenney-ui/switch-11.wav +0 -0
  453. package/dist/pkgs/soundlib/library/kenney-ui/switch-12.wav +0 -0
  454. package/dist/pkgs/soundlib/library/kenney-ui/switch-13.wav +0 -0
  455. package/dist/pkgs/soundlib/library/kenney-ui/switch-14.wav +0 -0
  456. package/dist/pkgs/soundlib/licences/kenney-digital.txt +21 -0
  457. package/dist/pkgs/soundlib/licences/kenney-impact.txt +23 -0
  458. package/dist/pkgs/soundlib/licences/kenney-interface.txt +22 -0
  459. package/dist/pkgs/soundlib/licences/kenney-rpg.txt +21 -0
  460. package/dist/pkgs/soundlib/licences/kenney-scifi.txt +22 -0
  461. package/dist/pkgs/soundlib/licences/kenney-ui.txt +21 -0
  462. package/dist/pkgs/studio/dist/exported-player.js +67012 -0
  463. package/dist/pkgs/studio/dist/scripting.js +2435 -0
  464. package/dist/pkgs/studio/dist/server/playtest-worker.js +90348 -0
  465. package/dist/resolved/@fontsource-variable/geist/files/geist-latin-wght-normal.woff2 +0 -0
  466. package/dist/resolved/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  467. package/dist/resolved/@fontsource-variable/plus-jakarta-sans/files/plus-jakarta-sans-latin-wght-normal.woff2 +0 -0
  468. package/dist/resolved/@gamesteel/site/package.json +17 -0
  469. package/package.json +29 -15
@@ -0,0 +1,1574 @@
1
+ import { fileURLToPath as __gamesteelPath } from 'node:url';
2
+ import { createRequire as __gamesteelRequire } from 'node:module';
3
+ const __gamesteelRoot = new URL("../../../", import.meta.url);
4
+ const __gamesteelResolve = (spec) => __gamesteelPath(new URL('resolved/' + spec, __gamesteelRoot));
5
+ const require = __gamesteelRequire(import.meta.url);
6
+
7
+ // ../artgen/dist/draw-worker.js
8
+ import { parentPort } from "node:worker_threads";
9
+
10
+ // ../artgen/dist/raster.js
11
+ var CLEAR = [0, 0, 0, 0];
12
+ var Raster = class {
13
+ w;
14
+ h;
15
+ d;
16
+ constructor(w, h) {
17
+ this.w = w;
18
+ this.h = h;
19
+ this.d = new Float32Array(w * h * 4);
20
+ }
21
+ get(x, y) {
22
+ const i = (y * this.w + x) * 4;
23
+ return [this.d[i] ?? 0, this.d[i + 1] ?? 0, this.d[i + 2] ?? 0, this.d[i + 3] ?? 0];
24
+ }
25
+ set(x, y, c) {
26
+ if (x < 0 || y < 0 || x >= this.w || y >= this.h)
27
+ return;
28
+ const i = (y * this.w + x) * 4;
29
+ this.d[i] = c[0];
30
+ this.d[i + 1] = c[1];
31
+ this.d[i + 2] = c[2];
32
+ this.d[i + 3] = c[3];
33
+ }
34
+ /** Source over. */
35
+ over(x, y, c) {
36
+ if (x < 0 || y < 0 || x >= this.w || y >= this.h || c[3] <= 0)
37
+ return;
38
+ const b = this.get(x, y);
39
+ const a = c[3] + b[3] * (1 - c[3]);
40
+ if (a <= 0)
41
+ return;
42
+ const k = b[3] * (1 - c[3]);
43
+ this.set(x, y, [(c[0] * c[3] + b[0] * k) / a, (c[1] * c[3] + b[1] * k) / a, (c[2] * c[3] + b[2] * k) / a, a]);
44
+ }
45
+ blit(src, x, y) {
46
+ for (let sy = 0; sy < src.h; sy++)
47
+ for (let sx = 0; sx < src.w; sx++)
48
+ this.over(x + sx, y + sy, src.get(sx, sy));
49
+ }
50
+ /** Every pixel from a shader. One sample is crisp, for pixel art; more
51
+ * samples average sub-pixel positions, for smooth edges. */
52
+ paint(f, samples2) {
53
+ for (let y = 0; y < this.h; y++)
54
+ for (let x = 0; x < this.w; x++) {
55
+ if (samples2 === 1) {
56
+ this.set(x, y, f(x + 0.5, y + 0.5));
57
+ continue;
58
+ }
59
+ let r = 0, g = 0, b = 0, a = 0;
60
+ for (let j = 0; j < samples2; j++)
61
+ for (let i = 0; i < samples2; i++) {
62
+ const c = f(x + (i + 0.5) / samples2, y + (j + 0.5) / samples2);
63
+ r += c[0] * c[3];
64
+ g += c[1] * c[3];
65
+ b += c[2] * c[3];
66
+ a += c[3];
67
+ }
68
+ this.set(x, y, a > 0 ? [r / a, g / a, b / a, a / (samples2 * samples2)] : CLEAR);
69
+ }
70
+ return this;
71
+ }
72
+ /** RGBA bytes, row-major: what a canvas or a PNG takes. */
73
+ toBytes() {
74
+ const out = new Uint8ClampedArray(this.w * this.h * 4);
75
+ for (let i = 0; i < out.length; i++)
76
+ out[i] = Math.round((this.d[i] ?? 0) * 255);
77
+ return out;
78
+ }
79
+ };
80
+
81
+ // ../artgen/dist/math.js
82
+ var clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
83
+ function smooth(e0, e1, x) {
84
+ const t = clamp((x - e0) / (e1 - e0));
85
+ return t * t * (3 - 2 * t);
86
+ }
87
+ function hash(x, y, seed) {
88
+ let h = Math.imul(x | 0, 374761393) + Math.imul(y | 0, 668265263) + Math.imul(seed | 0, 2147483647) | 0;
89
+ h = Math.imul(h ^ h >>> 13, 1274126177);
90
+ return ((h ^ h >>> 16) >>> 0) / 4294967296;
91
+ }
92
+ var wrap = (a, p) => (a % p + p) % p;
93
+ function noise(x, y, px, py, seed) {
94
+ const ix = Math.floor(x), iy = Math.floor(y);
95
+ const fx = x - ix, fy = y - iy;
96
+ const u = fx * fx * (3 - 2 * fx), v = fy * fy * (3 - 2 * fy);
97
+ const a = hash(wrap(ix, px), wrap(iy, py), seed), b = hash(wrap(ix + 1, px), wrap(iy, py), seed);
98
+ const c = hash(wrap(ix, px), wrap(iy + 1, py), seed), d = hash(wrap(ix + 1, px), wrap(iy + 1, py), seed);
99
+ return a + (b - a) * u + (c - a) * v + (a - b - c + d) * u * v;
100
+ }
101
+ function fbm(x, y, cells, seed, octaves = 4) {
102
+ let sum = 0, amp = 0.5, norm = 0, c = cells;
103
+ for (let o = 0; o < octaves; o++) {
104
+ sum += amp * noise(x * c, y * c, c, c, seed + o * 101);
105
+ norm += amp;
106
+ amp *= 0.5;
107
+ c *= 2;
108
+ }
109
+ return sum / norm;
110
+ }
111
+ function voronoi(x, y, cells, seed) {
112
+ const gx = (x - Math.floor(x)) * cells, gy = (y - Math.floor(y)) * cells;
113
+ const ix = Math.floor(gx), iy = Math.floor(gy);
114
+ let d1 = 9, d2 = 9, id = 0;
115
+ for (let j = -1; j <= 1; j++)
116
+ for (let i = -1; i <= 1; i++) {
117
+ const cx = ix + i, cy = iy + j;
118
+ const wx = wrap(cx, cells), wy = wrap(cy, cells);
119
+ const px = cx + 0.15 + 0.7 * hash(wx, wy, seed), py = cy + 0.15 + 0.7 * hash(wx, wy, seed + 7);
120
+ const d = Math.hypot(px - gx, py - gy);
121
+ if (d < d1) {
122
+ d2 = d1;
123
+ d1 = d;
124
+ id = wx * 131 + wy;
125
+ } else if (d < d2)
126
+ d2 = d;
127
+ }
128
+ return { d1, d2, id };
129
+ }
130
+ var sdCircle = (x, y, r) => Math.hypot(x, y) - r;
131
+ function sdBox(x, y, hw, hh, r = 0) {
132
+ const qx = Math.abs(x) - hw + r, qy = Math.abs(y) - hh + r;
133
+ return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - r;
134
+ }
135
+ function sdTriangle(x, y, hw, h) {
136
+ const px = Math.abs(x), py = y;
137
+ const t = clamp((px * hw + py * h) / (hw * hw + h * h));
138
+ const ax = px - hw * t, ay = py - h * t;
139
+ const bx = px - hw * clamp(px / hw), by = py - h;
140
+ const dx = Math.min(ax * ax + ay * ay, bx * bx + by * by);
141
+ const dy = Math.min(-(px * h - py * hw), -(py - h));
142
+ return -Math.sqrt(dx) * Math.sign(dy);
143
+ }
144
+ function sdHeart(x, y) {
145
+ const px = Math.abs(x), py = -y + 0.5;
146
+ if (py + px > 1)
147
+ return Math.sqrt((px - 0.25) ** 2 + (py - 0.75) ** 2) - Math.SQRT2 / 4;
148
+ const m = Math.max(px + py, 0) * 0.5;
149
+ return Math.sqrt(Math.min(px ** 2 + (py - 1) ** 2, (px - m) ** 2 + (py - m) ** 2)) * Math.sign(px - py);
150
+ }
151
+ function sdCapsule(x, y, ax, ay, bx, by, r) {
152
+ const pax = x - ax, pay = y - ay, bax = bx - ax, bay = by - ay;
153
+ const h = clamp((pax * bax + pay * bay) / (bax * bax + bay * bay || 1));
154
+ return Math.hypot(pax - bax * h, pay - bay * h) - r;
155
+ }
156
+ var BAYER = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
157
+ var bayer = (x, y) => ((BAYER[wrap(Math.floor(y), 4) * 4 + wrap(Math.floor(x), 4)] ?? 0) + 0.5) / 16;
158
+
159
+ // ../artgen/dist/color.js
160
+ var hex = (h, a = 1) => [(h >> 16 & 255) / 255, (h >> 8 & 255) / 255, (h & 255) / 255, a];
161
+ var mix = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t, a[3] + (b[3] - a[3]) * t];
162
+ var shade = (c, k) => k >= 0 ? mix(c, [1, 1, 1, c[3]], k) : mix(c, [0, 0, 0, c[3]], -k);
163
+ function hsl(h, s, l) {
164
+ const hh = (h % 360 + 360) % 360 / 60;
165
+ const c = (1 - Math.abs(2 * l - 1)) * s;
166
+ const x = c * (1 - Math.abs(hh % 2 - 1));
167
+ const [r, g, b] = hh < 1 ? [c, x, 0] : hh < 2 ? [x, c, 0] : hh < 3 ? [0, c, x] : hh < 4 ? [0, x, c] : hh < 5 ? [x, 0, c] : [c, 0, x];
168
+ const m = l - c / 2;
169
+ return [r + m, g + m, b + m, 1];
170
+ }
171
+ var lin = (v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
172
+ var luminance = (c) => 0.2126 * lin(c[0]) + 0.7152 * lin(c[1]) + 0.0722 * lin(c[2]);
173
+ function contrast(a, b) {
174
+ const la = luminance(a), lb = luminance(b);
175
+ return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
176
+ }
177
+ var ramp = (c) => [shade(c, -0.55), shade(c, -0.3), c, shade(c, 0.25), shade(c, 0.5)];
178
+
179
+ // ../artgen/dist/dna.js
180
+ var MIN_CONTRAST = { groundBackdrop: 1.35, outline: 2, heroDanger: 1.25 };
181
+ var hueOf = (h) => (h % 360 + 360) % 360;
182
+ function toward(a, b, t) {
183
+ let d = hueOf(b) - hueOf(a);
184
+ if (d > 180)
185
+ d -= 360;
186
+ if (d < -180)
187
+ d += 360;
188
+ return hueOf(a + d * t);
189
+ }
190
+ function accents(h, harmony) {
191
+ switch (harmony) {
192
+ case "complementary":
193
+ return [h + 180, h + 150];
194
+ case "analogous":
195
+ return [h + 30, h - 30];
196
+ case "triadic":
197
+ return [h + 120, h + 240];
198
+ case "split":
199
+ return [h + 150, h + 210];
200
+ case "monochrome":
201
+ return [h + 8, h - 8];
202
+ }
203
+ }
204
+ function apart(c, from, min) {
205
+ let out = c;
206
+ const up = luminance(c) >= luminance(from);
207
+ for (let i = 0; i < 24 && contrast(out, from) < min; i++)
208
+ out = shade(out, up ? 0.12 : -0.12);
209
+ if (contrast(out, from) < min) {
210
+ out = c;
211
+ for (let i = 0; i < 24 && contrast(out, from) < min; i++)
212
+ out = shade(out, up ? -0.12 : 0.12);
213
+ }
214
+ return out;
215
+ }
216
+ function paletteOf(dna) {
217
+ const { hue: h, saturation: s, brightness: b } = dna;
218
+ const [a1, a2] = accents(h, dna.harmony);
219
+ const role = {
220
+ ground: hsl(toward(a2, 30, 0.55), 0.3 + 0.3 * s, 0.33 + 0.14 * b),
221
+ groundDark: [0, 0, 0, 1],
222
+ surface: hsl(a1, 0.4 + 0.45 * s, 0.42 + 0.2 * b),
223
+ foliage: hsl(a1 - 12, 0.35 + 0.4 * s, 0.32 + 0.15 * b),
224
+ skyTop: hsl(toward(h + 190, 215, 0.45), 0.45 + 0.35 * s, 0.48 + 0.15 * b),
225
+ skyHorizon: hsl(toward(h + 190, 215, 0.45), 0.35 + 0.3 * s, 0.8 + 0.1 * b),
226
+ far: [0, 0, 0, 1],
227
+ near: hsl(a1 - 20, 0.3 + 0.35 * s, 0.5 + 0.12 * b),
228
+ outline: hsl(h, 0.35, 0.1),
229
+ hero: hsl(a1 + 70, 0.65 + 0.3 * s, 0.55),
230
+ danger: hsl(toward(355, h, 0.08), 0.7 + 0.25 * s, 0.5),
231
+ treasure: hsl(toward(46, h, 0.06), 0.85, 0.56),
232
+ wood: hsl(toward(28, h, 0.1), 0.4 + 0.2 * s, 0.43),
233
+ stone: hsl(h, 0.06 + 0.1 * s, 0.52 + 0.1 * b),
234
+ metal: hsl(toward(215, h, 0.2), 0.12, 0.7),
235
+ water: hsl(toward(200, h + 190, 0.3), 0.55 + 0.3 * s, 0.5),
236
+ light: hsl(toward(52, h, 0.1), 0.7, 0.88)
237
+ };
238
+ role.groundDark = shade(role.ground, -0.35);
239
+ role.far = shade(hsl(toward(h + 200, 230, 0.3), 0.18 + 0.2 * s, 0.6 + 0.1 * b), 0);
240
+ role.far = apart(role.far, role.ground, MIN_CONTRAST.groundBackdrop);
241
+ role.near = apart(role.near, role.ground, MIN_CONTRAST.groundBackdrop);
242
+ role.skyHorizon = apart(role.skyHorizon, role.ground, MIN_CONTRAST.groundBackdrop);
243
+ for (const k of ["ground", "surface", "hero", "danger"]) {
244
+ if (contrast(role.outline, role[k]) < MIN_CONTRAST.outline)
245
+ role.outline = shade(role.outline, -0.9);
246
+ if (contrast(role.outline, role[k]) < MIN_CONTRAST.outline)
247
+ role[k] = apart(role[k], role.outline, MIN_CONTRAST.outline);
248
+ }
249
+ for (let i = 0; i < 6 && !distinct(role.hero, role.danger); i++)
250
+ role.hero = hsl(a1 + 70 + 40 * (i + 1), 0.7 + 0.25 * s, 0.55);
251
+ if (!distinct(role.hero, role.danger))
252
+ role.hero = apart(role.hero, role.danger, MIN_CONTRAST.heroDanger);
253
+ const warnings = [];
254
+ for (const [k, v] of Object.entries(dna.overrides))
255
+ role[k] = hex(v);
256
+ const set = new Set(Object.keys(dna.overrides));
257
+ const warn = (k, other, min, what) => {
258
+ if ((set.has(k) || set.has(other)) && contrast(role[k], role[other]) < min)
259
+ warnings.push(`${k} is hard to tell from ${other}: ${what}`);
260
+ };
261
+ warn("far", "ground", MIN_CONTRAST.groundBackdrop, "the backdrop may hide where the player can stand");
262
+ warn("near", "ground", MIN_CONTRAST.groundBackdrop, "the backdrop may hide where the player can stand");
263
+ for (const k of ["ground", "surface", "hero", "danger"])
264
+ warn("outline", k, MIN_CONTRAST.outline, "outlines may not show");
265
+ if ((set.has("hero") || set.has("danger")) && !distinct(role.hero, role.danger))
266
+ warnings.push("hero is hard to tell from danger");
267
+ return { ...role, warnings };
268
+ }
269
+ function hueOfColour(c) {
270
+ const [r, g, b] = c;
271
+ const mx = Math.max(r, g, b), mn = Math.min(r, g, b);
272
+ if (mx === mn)
273
+ return 0;
274
+ const d = mx - mn;
275
+ const raw = mx === r ? (g - b) / d % 6 : mx === g ? (b - r) / d + 2 : (r - g) / d + 4;
276
+ return (raw * 60 + 360) % 360;
277
+ }
278
+ function distinct(a, b) {
279
+ const d = Math.abs(hueOfColour(a) - hueOfColour(b)) % 360;
280
+ return Math.min(d, 360 - d) >= 60 || contrast(a, b) >= MIN_CONTRAST.heroDanger;
281
+ }
282
+
283
+ // ../artgen/dist/shape.js
284
+ var tileSize = (dna) => dna.pixel ? dna.pixelsPerTile : 128;
285
+ var lightVector = (dna) => {
286
+ const t = dna.light * Math.PI / 180;
287
+ return [Math.sin(t), -Math.cos(t)];
288
+ };
289
+ function outlineWidth(dna, size) {
290
+ if (dna.outline === "none")
291
+ return 0;
292
+ if (dna.pixel)
293
+ return dna.outline === "thick" && size >= 24 ? 2 : 1;
294
+ return (dna.outline === "thick" ? 2.6 : 1.3) * (size / 64);
295
+ }
296
+ function toneColour(base, tone, dna, x, y) {
297
+ const r = ramp(base);
298
+ const t = dna.shading === "flat" ? 0.5 : dna.shading === "banded" ? tone < 0.42 ? 0.25 : tone < 0.7 ? 0.5 : 0.75 : tone;
299
+ const f = Math.max(0, Math.min(r.length - 1.0001, t * (r.length - 1)));
300
+ const i = Math.floor(f), k = f - i;
301
+ const a = r[i] ?? base, b = r[i + 1] ?? base;
302
+ if (dna.pixel)
303
+ return k > (dna.shading === "soft" ? bayer(x, y) : 0.5) ? b : a;
304
+ return [a[0] + (b[0] - a[0]) * k, a[1] + (b[1] - a[1]) * k, a[2] + (b[2] - a[2]) * k, 1];
305
+ }
306
+ function shapeShader(sd, base, dna, palette, size, opts = {}) {
307
+ const unit = 2 / size;
308
+ const ow = outlineWidth(dna, size) * unit;
309
+ const [lx, ly] = lightVector(dna);
310
+ return (x, y) => {
311
+ const u = x / size * 2 - 1, v = y / size * 2 - 1;
312
+ const d = sd(u, v);
313
+ if (d > 0)
314
+ return CLEAR;
315
+ if (ow > 0 && d > -ow)
316
+ return palette.outline;
317
+ const e = 0.02;
318
+ const gx = sd(u + e, v) - sd(u - e, v), gy = sd(u, v + e) - sd(u, v - e);
319
+ const gl = Math.hypot(gx, gy) || 1;
320
+ const lit = gx / gl * lx + gy / gl * ly;
321
+ const rim = Math.max(0, 1 - -d / 0.32);
322
+ let tone = 0.55 + 0.32 * lit * rim;
323
+ const custom = opts.detail?.(u, v, d, tone);
324
+ if (custom !== null && custom !== void 0)
325
+ return custom;
326
+ if (opts.gloss === true && Math.hypot((u - lx * 0.4) / 1.3, v - ly * 0.42) < 0.15)
327
+ return shade(base, 0.7);
328
+ tone = Math.max(0, Math.min(1, tone));
329
+ return toneColour(base, tone, dna, x, y);
330
+ };
331
+ }
332
+
333
+ // ../artgen/dist/recipes/registry.js
334
+ var recipes = /* @__PURE__ */ new Map();
335
+ function register(...list) {
336
+ for (const r of list)
337
+ recipes.set(r.name, r);
338
+ }
339
+ function checkOptionsFor(recipe, raw) {
340
+ if (raw !== void 0 && (typeof raw !== "object" || raw === null || Array.isArray(raw))) {
341
+ return { ok: false, reason: "options are an object of option names and values" };
342
+ }
343
+ const given = raw ?? {};
344
+ const names = Object.keys(recipe.options);
345
+ for (const key of Object.keys(given)) {
346
+ if (!names.includes(key)) {
347
+ return { ok: false, reason: `'${key}' is not an option of ${recipe.name}; its options are ${names.length === 0 ? "none" : names.join(", ")}` };
348
+ }
349
+ }
350
+ const out = {};
351
+ for (const [name, spec] of Object.entries(recipe.options)) {
352
+ const v = given[name];
353
+ if (v === void 0) {
354
+ out[name] = spec.default;
355
+ continue;
356
+ }
357
+ if (spec.kind === "enum") {
358
+ if (typeof v !== "string" || !spec.values.includes(v)) {
359
+ return { ok: false, reason: `${name} '${String(v)}' is not one of ${spec.values.join(", ")}` };
360
+ }
361
+ out[name] = v;
362
+ } else {
363
+ if (typeof v !== "number" || !(v >= spec.min && v <= spec.max)) {
364
+ return { ok: false, reason: `${name} is a number from ${String(spec.min)} to ${String(spec.max)}` };
365
+ }
366
+ out[name] = v;
367
+ }
368
+ }
369
+ return { ok: true, options: out };
370
+ }
371
+ function drawWith(recipe, raw, dna, seed) {
372
+ const checked = checkOptionsFor(recipe, raw);
373
+ if (!checked.ok)
374
+ return checked;
375
+ const drawn = recipe.render(checked.options, dna, paletteOf(dna), seed);
376
+ const { raster } = drawn;
377
+ return {
378
+ ok: true,
379
+ w: raster.w,
380
+ h: raster.h,
381
+ bytes: raster.toBytes(),
382
+ entry: {
383
+ kind: recipe.kind,
384
+ tags: [recipe.family, recipe.name],
385
+ pixel: dna.pixel,
386
+ image: { w: raster.w, h: raster.h },
387
+ frame: drawn.frame,
388
+ ...drawn.clips === void 0 ? {} : { clips: drawn.clips },
389
+ ...drawn.fps === void 0 ? {} : { fps: drawn.fps },
390
+ ...drawn.pieces === void 0 ? {} : { pieces: drawn.pieces },
391
+ ...drawn.oneWay === void 0 ? {} : { oneWay: drawn.oneWay },
392
+ made: { by: "code", recipe: recipe.name, options: checked.options, seed, dna: dna.version }
393
+ }
394
+ };
395
+ }
396
+ function draw(recipe, options, dna, seed) {
397
+ const r = recipes.get(recipe);
398
+ if (r === void 0)
399
+ return { ok: false, reason: `there is no recipe '${recipe}'; the recipes are ${[...recipes.keys()].join(", ")}` };
400
+ return drawWith(r, options, dna, seed);
401
+ }
402
+
403
+ // ../artgen/dist/recipes/ground.js
404
+ var SURFACES = ["grass", "snow", "sand", "moss", "crystal", "none"];
405
+ var FILLS = ["dirt", "stone", "cobble", "bricks", "ice", "wood", "metal"];
406
+ var LEDGES = ["plank", "stone", "cloud"];
407
+ var WALLS = ["stone", "bricks", "wood", "metal", "hedge"];
408
+ var samplesFor = (dna) => dna.pixel ? 1 : 2;
409
+ function pick(r, t, x, y, dna) {
410
+ const f = Math.max(0, Math.min(r.length - 1.0001, t * (r.length - 1)));
411
+ const i = Math.floor(f), k = f - i;
412
+ const a = r[i], b = r[i + 1];
413
+ if (dna.pixel)
414
+ return k > bayer(x, y) ? b : a;
415
+ return mix(a, b, k);
416
+ }
417
+ var steps = (c) => [shade(c, -0.32), shade(c, -0.15), c, shade(c, 0.14)];
418
+ function fillColour(fill, p, dna, fx, fy, x, y, seed) {
419
+ const busy = 0.4 + 0.6 * dna.texture;
420
+ switch (fill) {
421
+ case "stone": {
422
+ const row = Math.floor(fy * 3);
423
+ const off = row % 2 * 0.5;
424
+ const by = (fy * 3 + 0.5) % 1, bx = (fx + off + 0.27) % 1;
425
+ if (by < 0.07 || bx < 0.035)
426
+ return shade(p.stone, -0.4);
427
+ return pick(steps(p.stone), 0.3 + 0.4 * fbm(fx, fy, 3, seed) * busy + (by < 0.2 ? 0.25 : 0), x, y, dna);
428
+ }
429
+ case "cobble": {
430
+ const v = voronoi(fx, fy, 2 + Math.round(2 * dna.texture), seed);
431
+ if (v.d2 - v.d1 < 0.09)
432
+ return shade(p.stone, -0.45);
433
+ return pick(steps(p.stone), 0.3 + 0.35 * hash(v.id, 1, seed) + 0.3 * (1 - v.d1), x, y, dna);
434
+ }
435
+ case "bricks": {
436
+ const brick = mix(p.ground, p.danger, 0.45);
437
+ const row = Math.floor(fy * 4), off = row % 2 ? 0.25 : 0;
438
+ const bx = ((fx + off) * 2 + 0.3) % 1, by = (fy * 4 + 0.5) % 1;
439
+ if (by < 0.13 || bx < 0.06)
440
+ return shade(p.stone, -0.35);
441
+ return pick(steps(brick), 0.35 + 0.3 * hash(Math.floor((fx + off) * 2 + 0.3) % 2, row, seed) + (by < 0.3 ? 0.25 : 0), x, y, dna);
442
+ }
443
+ case "ice": {
444
+ const ice = mix(p.water, [1, 1, 1, 1], 0.55);
445
+ const streak = Math.abs((fx + fy * 0.6) * 3 % 1 - 0.5) < 0.04 ? 0.35 : 0;
446
+ return pick(steps(ice), 0.4 + 0.3 * fbm(fx, fy, 2, seed) + streak, x, y, dna);
447
+ }
448
+ case "wood": {
449
+ const col = Math.floor(fx * 4 + 0.5) % 4;
450
+ if ((fx * 4 + 0.5) % 1 < 0.06)
451
+ return shade(p.wood, -0.45);
452
+ return pick(steps(p.wood), 0.3 + 0.45 * noise(fx * 8, fy * 10 + col * 3, 8, 10, seed) * busy, x, y, dna);
453
+ }
454
+ case "metal": {
455
+ const px = (fx * 2 + 0.5) % 1, py = (fy * 2 + 0.5) % 1;
456
+ if (px < 0.04 || py < 0.04)
457
+ return shade(p.metal, -0.4);
458
+ if (Math.hypot(px - 0.14, py - 0.14) < 0.05 || Math.hypot(px - 0.86, py - 0.86) < 0.05)
459
+ return shade(p.metal, 0.35);
460
+ return pick(steps(p.metal), 0.45 + 0.2 * (1 - py), x, y, dna);
461
+ }
462
+ default: {
463
+ const v = voronoi(fx, fy, 4 + Math.round(3 * dna.texture), seed + 3);
464
+ if (v.d1 < 0.15 && hash(v.id, 9, seed) < 0.25 + 0.3 * dna.texture)
465
+ return hash(v.id, 4, seed) < 0.5 ? shade(p.ground, 0.2) : p.groundDark;
466
+ return pick(steps(p.ground), 0.2 + 0.7 * fbm(fx, fy, 3, seed) * busy + 0.15 * (1 - busy), x, y, dna);
467
+ }
468
+ }
469
+ }
470
+ function surfaceColour(surface, p) {
471
+ switch (surface) {
472
+ case "snow":
473
+ return mix(p.skyHorizon, [1, 1, 1, 1], 0.75);
474
+ case "sand":
475
+ return mix(p.treasure, p.ground, 0.45);
476
+ case "moss":
477
+ return p.foliage;
478
+ case "crystal":
479
+ return mix(p.water, [1, 1, 1, 1], 0.3);
480
+ default:
481
+ return p.surface;
482
+ }
483
+ }
484
+ function capDepth(u, dna, seed) {
485
+ const base = 4.2;
486
+ if (dna.edges === "straight")
487
+ return base;
488
+ if (dna.edges === "spiky")
489
+ return base + 1.3 * (Math.abs(u / 16 * 8 % 1 - 0.5) * 2 - 0.5);
490
+ return base + 1.1 * Math.sin(u / 16 * Math.PI * 4 + seed) + 1.1 * (noise(u / 16 * 4, 0.5, 4, 1, seed + 5) - 0.5);
491
+ }
492
+ var outlineUnits = (dna, S) => dna.outline === "none" ? 0 : dna.pixel ? 16 / S * (dna.outline === "thick" && S >= 32 ? 2 : 1) : dna.outline === "thick" ? 1.3 : 0.75;
493
+ function openDistance(u, v, mask, r) {
494
+ const up = (mask & 1) !== 0, right = (mask & 2) !== 0, down = (mask & 4) !== 0, left = (mask & 8) !== 0;
495
+ let d = 99;
496
+ if (!up)
497
+ d = Math.min(d, v);
498
+ if (!down)
499
+ d = Math.min(d, 16 - v);
500
+ if (!left)
501
+ d = Math.min(d, u);
502
+ if (!right)
503
+ d = Math.min(d, 16 - u);
504
+ const corners = [
505
+ [!up && !left, r, r],
506
+ [!up && !right, 16 - r, r],
507
+ [!down && !left, r, 16 - r],
508
+ [!down && !right, 16 - r, 16 - r]
509
+ ];
510
+ for (const [open, cx, cy] of corners) {
511
+ if (!open || r <= 0)
512
+ continue;
513
+ if (!((cx < 8 ? u < cx : u > cx) && (cy < 8 ? v < cy : v > cy)))
514
+ continue;
515
+ const dc = r - Math.hypot(u - cx, v - cy);
516
+ if (dc < 0)
517
+ return -1;
518
+ d = Math.min(d, dc);
519
+ }
520
+ return d;
521
+ }
522
+ function solidPiece(o, dna, p, mask, S, seed) {
523
+ const g = S / 16;
524
+ const r = 0.6 + 3.6 * dna.roundness;
525
+ const ow = outlineUnits(dna, S);
526
+ const surface = o["surface"] === "none" ? null : surfaceColour(String(o["surface"]), p);
527
+ const up = (mask & 1) !== 0;
528
+ return new Raster(S, S).paint((x, y) => {
529
+ const u = x / g, v = y / g;
530
+ const d = openDistance(u, v, mask, r);
531
+ if (d < 0)
532
+ return CLEAR;
533
+ if (d < ow)
534
+ return p.outline;
535
+ let c = fillColour(String(o["fill"]), p, dna, x / S, y / S, x, y, seed);
536
+ if (surface !== null && !up) {
537
+ const depth = capDepth(u, dna, seed);
538
+ if (v < depth) {
539
+ const cap = steps(surface);
540
+ const k = v < 1.6 ? 0.98 : v > depth - 1.1 ? 0.15 : 0.55 + 0.3 * (noise(u * 1.2, v * 1.2, 64, 64, seed + 8) - 0.5) * dna.texture;
541
+ c = pick(cap, k, x, y, dna);
542
+ } else if (v < depth + 1)
543
+ c = shade(c, -0.28);
544
+ }
545
+ if (d < 3 && dna.shading !== "flat") {
546
+ const k = (3 - d) / 3;
547
+ const lit = !up && v < 3 || (mask & 8) === 0 && u < 3;
548
+ c = shade(c, lit ? 0.1 * k : -0.18 * k);
549
+ }
550
+ return c;
551
+ }, samplesFor(dna));
552
+ }
553
+ function ledgePiece(o, dna, p, ends, S, seed) {
554
+ const g = S / 16;
555
+ const ow = outlineUnits(dna, S);
556
+ const ledge = String(o["ledge"]);
557
+ const base = ledge === "stone" ? p.stone : ledge === "cloud" ? mix(p.skyHorizon, [1, 1, 1, 1], 0.8) : p.wood;
558
+ const openL = ends === "left" || ends === "single", openR = ends === "right" || ends === "single";
559
+ const height = ledge === "cloud" ? 6.5 : 6;
560
+ return new Raster(S, S).paint((x, y) => {
561
+ const u = x / g, v = y / g;
562
+ if (v > height + 0.5)
563
+ return CLEAR;
564
+ const rr = ledge === "cloud" ? 3 : 1 + 2 * dna.roundness;
565
+ let d = Math.min(v, height - v);
566
+ for (const [open, cx] of [[openL, rr], [openR, 16 - rr]]) {
567
+ if (!open || !(cx < 8 ? u < cx : u > cx))
568
+ continue;
569
+ const dist = Math.hypot(u - cx, Math.max(0, Math.abs(v - height / 2) - (height / 2 - rr)));
570
+ if (dist > rr)
571
+ return CLEAR;
572
+ d = Math.min(d, rr - dist);
573
+ }
574
+ if (ledge === "cloud") {
575
+ const bump = 0.9 * Math.sin(u / 16 * Math.PI * 6 + seed);
576
+ if (v < 1 - bump * 0.6)
577
+ return CLEAR;
578
+ }
579
+ if (openL)
580
+ d = Math.min(d, u);
581
+ if (openR)
582
+ d = Math.min(d, 16 - u);
583
+ if (d < ow)
584
+ return p.outline;
585
+ if (ledge === "plank" && (Math.abs(u - 3.5) < 0.8 || Math.abs(u - 12.5) < 0.8) && Math.abs(v - 3) < 0.8)
586
+ return shade(base, -0.5);
587
+ let c = v < 1.8 ? shade(base, 0.25) : pick(steps(base), 0.35 + 0.45 * noise(u * 0.3, v * 1.5, 64, 64, seed + 11), x, y, dna);
588
+ if (v > height - 1.4)
589
+ c = shade(c, -0.25);
590
+ return c;
591
+ }, samplesFor(dna));
592
+ }
593
+ function floorPiece(o, dna, p, S, seed) {
594
+ const tuft = o["surface"] === "grass" || o["surface"] === "moss" ? surfaceColour(String(o["surface"]), p) : null;
595
+ const snow = o["surface"] === "snow";
596
+ return new Raster(S, S).paint((x, y) => {
597
+ const fx = x / S, fy = y / S;
598
+ if (tuft !== null) {
599
+ const v = voronoi(fx, fy, 5, seed + 21);
600
+ if (v.d1 < 0.14 && hash(v.id, 2, seed) < 0.5)
601
+ return shade(tuft, 0.15);
602
+ return pick(steps(tuft), 0.35 + 0.4 * fbm(fx, fy, 3, seed), x, y, dna);
603
+ }
604
+ const c = fillColour(String(o["fill"]), p, dna, fx, fy, x, y, seed);
605
+ return snow ? mix(c, [1, 1, 1, 1], 0.55) : c;
606
+ }, samplesFor(dna));
607
+ }
608
+ function wallPiece(o, dna, p, mask, S, seed) {
609
+ const g = S / 16;
610
+ const ow = outlineUnits(dna, S);
611
+ const material = String(o["material"]);
612
+ const down = (mask & 4) !== 0;
613
+ const fill = material === "hedge" ? null : material === "wood" ? "wood" : material === "metal" ? "metal" : material === "bricks" ? "bricks" : "stone";
614
+ return new Raster(S, S).paint((x, y) => {
615
+ const u = x / g, v = y / g;
616
+ const d = openDistance(u, v, mask, 0.5 + 2 * dna.roundness);
617
+ if (d < 0)
618
+ return CLEAR;
619
+ if (d < ow)
620
+ return p.outline;
621
+ const face = !down && v > 10;
622
+ const c = fill === null ? pick(steps(p.foliage), 0.3 + 0.5 * fbm(x / S, y / S, 4, seed), x, y, dna) : fillColour(fill, p, dna, x / S, y / S, x, y, seed);
623
+ if (face)
624
+ return shade(c, -0.35 - (v > 14 ? 0.1 : 0));
625
+ return shade(c, v < 2 && (mask & 1) === 0 ? 0.18 : 0.08);
626
+ }, samplesFor(dna));
627
+ }
628
+ function sheetOf(pieces, S, rows) {
629
+ const out = new Raster(4 * S, rows * S);
630
+ pieces.forEach((piece, i) => {
631
+ out.blit(piece, i % 4 * S, Math.floor(i / 4) * S);
632
+ });
633
+ return out;
634
+ }
635
+ var MASKS = Object.fromEntries(Array.from({ length: 16 }, (_, m) => [m, m]));
636
+ register({
637
+ name: "ground",
638
+ family: "ground",
639
+ kind: "tileset",
640
+ description: "Ground blocks: a surface (grass, snow...) over a fill (dirt, stone...), and ledges you can jump up through. view top makes a floor seen from above.",
641
+ options: {
642
+ view: { kind: "enum", values: ["side", "top"], default: "side", note: "side for platformers, top for floors seen from above" },
643
+ surface: { kind: "enum", values: SURFACES, default: "grass", note: "what grows on top" },
644
+ fill: { kind: "enum", values: FILLS, default: "dirt", note: "what the block is made of" },
645
+ ledge: { kind: "enum", values: LEDGES, default: "plank", note: "the one-way platforms (side view)" }
646
+ },
647
+ render: (o, dna, p, seed) => {
648
+ const S = tileSize(dna);
649
+ if (o["view"] === "top") {
650
+ const floor = floorPiece(o, dna, p, S, seed);
651
+ return { raster: sheetOf(Array.from({ length: 16 }, () => floor), S, 4), frame: { w: S, h: S }, pieces: MASKS };
652
+ }
653
+ const solids = Array.from({ length: 16 }, (_, m) => solidPiece(o, dna, p, m, S, seed));
654
+ const ledges = ["left", "middle", "right", "single"].map((e) => ledgePiece(o, dna, p, e, S, seed));
655
+ return {
656
+ raster: sheetOf([...solids, ...ledges], S, 5),
657
+ frame: { w: S, h: S },
658
+ pieces: MASKS,
659
+ oneWay: { left: 16, middle: 17, right: 18, single: 19 }
660
+ };
661
+ }
662
+ }, {
663
+ name: "wall",
664
+ family: "ground",
665
+ kind: "tileset",
666
+ description: "Walls seen from above, for top-down games: a lit top and a darker front face where nothing is below.",
667
+ options: {
668
+ material: { kind: "enum", values: WALLS, default: "stone", note: "what the wall is made of" }
669
+ },
670
+ render: (o, dna, p, seed) => {
671
+ const S = tileSize(dna);
672
+ return { raster: sheetOf(Array.from({ length: 16 }, (_, m) => wallPiece(o, dna, p, m, S, seed)), S, 4), frame: { w: S, h: S }, pieces: MASKS };
673
+ }
674
+ });
675
+
676
+ // ../artgen/dist/recipes/backdrop.js
677
+ var sideSize = (dna) => {
678
+ const h = dna.pixel ? dna.pixelsPerTile * 9 : 540;
679
+ return { w: h * 3, h };
680
+ };
681
+ function ridge(x, cells, seed, octaves = 4) {
682
+ let s = 0, a = 0.5, n = 0, c = cells;
683
+ for (let o = 0; o < octaves; o++) {
684
+ s += a * noise(x * c, 0.5, c, 1, seed + o * 31);
685
+ n += a;
686
+ a *= 0.5;
687
+ c *= 2;
688
+ }
689
+ return s / n;
690
+ }
691
+ var around = (a, b) => {
692
+ const d = a - b;
693
+ return d - Math.round(d);
694
+ };
695
+ function band(a, b, t, x, y, dna, steps2 = 6) {
696
+ if (!dna.pixel)
697
+ return mix(a, b, t);
698
+ const f = t * steps2, i = Math.floor(f);
699
+ return mix(a, b, Math.min(1, (i + (f - i > bayer(x, y) ? 1 : 0)) / steps2));
700
+ }
701
+ function skyColours(time, p) {
702
+ if (time === "night")
703
+ return { top: shade(p.skyTop, -0.72), horizon: shade(p.skyTop, -0.42) };
704
+ if (time === "dusk")
705
+ return { top: shade(mix(p.skyTop, p.danger, 0.3), -0.35), horizon: mix(p.treasure, p.danger, 0.35) };
706
+ return { top: p.skyTop, horizon: p.skyHorizon };
707
+ }
708
+ function sky(o, dna, p, seed) {
709
+ const { w: W, h: H } = sideSize(dna);
710
+ const time = String(o["time"]), clouds = String(o["clouds"]), kind = String(o["ridge"]);
711
+ const { top, horizon } = skyColours(time, p);
712
+ const sun = time === "night" ? mix(p.light, [1, 1, 1, 1], 0.5) : time === "dusk" ? mix(p.treasure, p.light, 0.5) : p.light;
713
+ const cloudCount = clouds === "none" ? 0 : clouds === "few" ? 3 : 6;
714
+ const cloudColour = time === "night" ? shade(p.skyTop, -0.5) : time === "dusk" ? mix(p.treasure, [1, 1, 1, 1], 0.55) : mix(p.skyHorizon, [1, 1, 1, 1], 0.7);
715
+ const far = time === "night" ? shade(p.far, -0.55) : time === "dusk" ? mix(p.far, p.danger, 0.25) : p.far;
716
+ const raster = new Raster(W, H).paint((x, y) => {
717
+ const fx = x / W, fy = y / H;
718
+ let c = band(top, horizon, smooth(0, 0.8, fy), x, y, dna, 8);
719
+ if (time === "night" && hash(x, y, seed) > 0.9975 && fy < 0.6)
720
+ c = mix(c, [1, 1, 1, 1], 0.6 + 0.4 * hash(y, x, seed));
721
+ const ds = Math.hypot(around(fx, 0.72) * W / H, fy - 0.24);
722
+ if (ds < 0.07)
723
+ c = sun;
724
+ else
725
+ c = mix(c, sun, 0.3 * Math.max(0, 1 - (ds - 0.07) / 0.18) ** 2);
726
+ for (let k = 0; k < cloudCount; k++) {
727
+ const cx = (k + 0.4 * hash(k, 5, seed)) / cloudCount, cy = 0.1 + 0.18 * hash(k, 7, seed);
728
+ const ax = around(fx, cx) * W / H, bottom = cy + 0.045;
729
+ let d = 9;
730
+ for (let b = 0; b < 5; b++) {
731
+ const r = (0.04 + 0.03 * hash(k * 7 + b, 3, seed + 6) + (b === 2 ? 0.02 : 0)) * (0.8 + 0.4 * dna.roundness);
732
+ d = Math.min(d, Math.hypot(ax - (b - 2) * 0.05, fy - (bottom - r * 0.9)) - r);
733
+ }
734
+ d = Math.max(d, fy - bottom);
735
+ if (d < 0)
736
+ c = shade(cloudColour, fy > bottom - 0.02 ? -0.1 : d > -8e-3 ? -0.04 : 0.03);
737
+ }
738
+ if (kind !== "none") {
739
+ let hF;
740
+ if (kind === "mesas")
741
+ hF = 0.5 + 0.18 * (Math.round((1 - ridge(fx, 3, seed + 5)) * 4) / 4) - 0.08;
742
+ else if (kind === "skyline") {
743
+ const col = Math.floor(fx * 40);
744
+ hF = 0.42 + 0.22 * hash(col, 1, seed + 9);
745
+ if (fy > hF && time === "night" && Math.floor(fx * 160) % 2 === 1 && Math.floor(fy * 60) % 2 === 1 && hash(Math.floor(fx * 160), Math.floor(fy * 60), seed) > 0.6)
746
+ return p.light;
747
+ } else
748
+ hF = 0.4 + 0.24 * (1 - ridge(fx, 3, seed + 5));
749
+ if (fy > hF) {
750
+ const snow = kind === "mountains" && fy < hF + 0.025 && hF < 0.48 && time !== "dusk";
751
+ c = snow ? shade(far, 0.55) : band(mix(far, horizon, 0.3), far, smooth(hF, 0.95, fy), x, y, dna, 4);
752
+ }
753
+ }
754
+ return c;
755
+ }, 1);
756
+ return { raster, frame: { w: W, h: H } };
757
+ }
758
+ function scenery(kind, dx, fy, base, size) {
759
+ switch (kind) {
760
+ case "pines":
761
+ return sdTriangle(dx, fy - (base - size), size * 0.42, size);
762
+ case "round-trees":
763
+ return Math.min(sdCircle(dx, fy - (base - size * 0.75), size * 0.38), sdBox(dx, fy - (base - size * 0.2), size * 0.06, size * 0.22));
764
+ case "rocks":
765
+ return Math.max(Math.hypot(dx / 1.5, fy - base) - size * 0.4, fy - base);
766
+ case "cacti":
767
+ return Math.min(sdCapsule(dx, fy, 0, base, 0, base - size * 0.9, size * 0.09), sdCapsule(dx, fy, 0, base - size * 0.45, size * 0.22, base - size * 0.45, size * 0.07), sdCapsule(dx, fy, size * 0.22, base - size * 0.45, size * 0.22, base - size * 0.7, size * 0.07));
768
+ case "mushrooms":
769
+ return Math.min(sdBox(dx, fy - (base - size * 0.25), size * 0.07, size * 0.25), Math.max(sdCircle(dx, fy - (base - size * 0.5), size * 0.32), fy - (base - size * 0.5)));
770
+ case "houses":
771
+ return Math.min(sdBox(dx, fy - (base - size * 0.3), size * 0.32, size * 0.3), sdTriangle(dx, fy - (base - size * 0.95), size * 0.42, size * 0.35));
772
+ default:
773
+ return 9;
774
+ }
775
+ }
776
+ function hills(o, dna, p, seed) {
777
+ const { w: W, h: H } = sideSize(dna);
778
+ const kind = String(o["scenery"]);
779
+ const lift = o["height"] === "high" ? -0.1 : o["height"] === "low" ? 0.08 : 0;
780
+ const mid = p.near, near = shade(p.foliage, -0.05);
781
+ const line = (fx, k, amp, cells, s) => 0.64 + lift + k + amp * Math.sin(fx * Math.PI * 2 * 3 + seed) + amp * (ridge(fx, cells, seed + s, 3) - 0.5);
782
+ const count = 14;
783
+ const raster = new Raster(W, H).paint((x, y) => {
784
+ const fx = x / W, fy = y / H;
785
+ let c = CLEAR;
786
+ const hM = line(fx, 0, 0.05, 6, 9);
787
+ for (let k = 0; k < count; k++) {
788
+ const tx = k === 0 ? 8e-3 : (k + 0.35 * (hash(k, 1, seed + 2) - 0.5)) / count;
789
+ const dx = around(fx, tx) * W / H;
790
+ if (Math.abs(dx) > 0.2)
791
+ continue;
792
+ const size = 0.08 + 0.05 * hash(k, 3, seed + 4);
793
+ const d = scenery(kind, dx, fy, line(tx, 0, 0.05, 6, 9) + 0.01, size);
794
+ if (d < 0)
795
+ c = d > -4e-3 ? shade(mid, -0.35) : shade(kind === "houses" || kind === "mushrooms" ? mix(mid, p.danger, 0.25) : mid, dx < 0 ? 0.06 : -0.16);
796
+ }
797
+ if (fy > hM)
798
+ c = fy < hM + 0.012 ? shade(mid, 0.2) : band(mid, shade(mid, -0.2), smooth(hM, 1, fy), x, y, dna, 3);
799
+ const hN = line(fx, 0.16, 0.04, 10, 13);
800
+ if (fy > hN)
801
+ c = fy < hN + 0.012 ? shade(near, 0.18) : band(near, shade(near, -0.25), smooth(hN, 1, fy), x, y, dna, 3);
802
+ return c;
803
+ }, 1);
804
+ return { raster, frame: { w: W, h: H } };
805
+ }
806
+ function field(o, dna, p, seed) {
807
+ const S = dna.pixel ? dna.pixelsPerTile * 8 : 512;
808
+ const pattern = String(o["pattern"]);
809
+ const raster = new Raster(S, S).paint((x, y) => {
810
+ const fx = x / S, fy = y / S;
811
+ switch (pattern) {
812
+ case "water": {
813
+ const w = Math.sin((fy * 8 + 0.3 * Math.sin(fx * Math.PI * 2 * 3)) * Math.PI * 2);
814
+ return band(shade(p.water, -0.15), shade(p.water, 0.2), 0.5 + 0.5 * w * (0.4 + 0.6 * fbm(fx, fy, 2, seed)), x, y, dna, 4);
815
+ }
816
+ case "sand": {
817
+ const ripple = Math.sin((fy * 10 + 0.6 * fbm(fx, fy, 2, seed)) * Math.PI * 2);
818
+ const sand = mix(p.treasure, p.ground, 0.5);
819
+ return band(shade(sand, -0.1), shade(sand, 0.12), 0.5 + 0.5 * ripple, x, y, dna, 4);
820
+ }
821
+ case "space": {
822
+ const base = band(shade(p.skyTop, -0.85), shade(mix(p.skyTop, p.hero, 0.4), -0.6), fbm(fx, fy, 2, seed), x, y, dna, 4);
823
+ return hash(x % S, y % S, seed) > 0.996 ? mix(base, [1, 1, 1, 1], 0.8) : base;
824
+ }
825
+ case "checker": {
826
+ const a = Math.floor(fx * 8 + 0.5) + Math.floor(fy * 8 + 0.5);
827
+ return a % 2 === 0 ? shade(p.stone, 0.1) : shade(p.stone, -0.12);
828
+ }
829
+ case "stripes":
830
+ return Math.floor(fx * 8 + 0.5) % 2 === 0 ? shade(p.near, 0.1) : shade(p.near, -0.08);
831
+ default: {
832
+ const g = p.surface;
833
+ const t = fbm(fx, fy, 4, seed);
834
+ const tuft = hash(Math.floor(fx * 32 + 0.5) % 32, Math.floor(fy * 32 + 0.5) % 32, seed) > 0.92;
835
+ return tuft ? shade(g, 0.2) : band(shade(g, -0.15), shade(g, 0.1), t, x, y, dna, 4);
836
+ }
837
+ }
838
+ }, 1);
839
+ return { raster, frame: { w: S, h: S } };
840
+ }
841
+ register({
842
+ name: "sky",
843
+ family: "backdrop",
844
+ kind: "background",
845
+ description: "The far backdrop for side-view games: a sky by time of day, clouds, and a far ridge. Opaque; use parallax 0 to 0.2.",
846
+ options: {
847
+ time: { kind: "enum", values: ["day", "dusk", "night"], default: "day", note: "time of day" },
848
+ clouds: { kind: "enum", values: ["none", "few", "many"], default: "few", note: "how many clouds" },
849
+ ridge: { kind: "enum", values: ["none", "mountains", "mesas", "skyline"], default: "mountains", note: "what stands far away" }
850
+ },
851
+ render: sky
852
+ }, {
853
+ name: "hills",
854
+ family: "backdrop",
855
+ kind: "background",
856
+ description: "A near backdrop layer for side-view games: rolling hills with scenery on them, see-through above. Use parallax 0.3 to 0.6 over a sky.",
857
+ options: {
858
+ scenery: { kind: "enum", values: ["none", "pines", "round-trees", "rocks", "cacti", "mushrooms", "houses"], default: "pines", note: "what stands on the hills" },
859
+ height: { kind: "enum", values: ["low", "mid", "high"], default: "mid", note: "how high the hills reach" }
860
+ },
861
+ render: hills
862
+ }, {
863
+ name: "field",
864
+ family: "backdrop",
865
+ kind: "background",
866
+ description: "A backdrop for top-down and single-screen games that repeats in both directions.",
867
+ options: {
868
+ pattern: { kind: "enum", values: ["grass", "water", "sand", "space", "checker", "stripes"], default: "grass", note: "what the field is" }
869
+ },
870
+ render: field
871
+ });
872
+
873
+ // ../artgen/dist/recipes/things.js
874
+ var samples = (dna) => dna.pixel ? 1 : 3;
875
+ function picture(sd, base, dna, p, tw = 1, th = 1, opts = {}) {
876
+ const S = tileSize(dna);
877
+ const W = Math.round(S * tw), H = Math.round(S * th);
878
+ const s = Math.min(W, H);
879
+ const k = 0.9 + 0.06 * hash(variant, 1, 41), a = 1 + 0.08 * (hash(variant, 2, 41) - 0.5);
880
+ const fx = k * a, fy = k / a;
881
+ const scaled = (u, v) => sd(u / fx, v / fy) * Math.min(fx, fy);
882
+ const detail = opts.detail;
883
+ const shaded = detail === void 0 ? opts : { ...opts, detail: (u, v, d, tone) => detail(u / fx, v / fy, d, tone) };
884
+ const shader = shapeShader(scaled, base, dna, p, s, shaded);
885
+ const tint = 0.14 * (hash(variant, 3, 41) - 0.5);
886
+ const sh = (x, y) => {
887
+ const c = shader(x, y);
888
+ return c[3] === 0 ? c : shade(c, tint);
889
+ };
890
+ return new Raster(W, H).paint((x, y) => sh(x - (W - s) / 2, y - (H - s) / 2), samples(dna));
891
+ }
892
+ var variant = 1;
893
+ var seeded = (r) => ({
894
+ ...r,
895
+ render: (o, dna, p, seed) => {
896
+ variant = seed;
897
+ try {
898
+ return r.render(o, dna, p, seed);
899
+ } finally {
900
+ variant = 1;
901
+ }
902
+ }
903
+ });
904
+ function strip(frames, fps) {
905
+ const f = frames[0];
906
+ const out = new Raster(f.w * frames.length, f.h);
907
+ frames.forEach((r, i) => {
908
+ out.blit(r, i * f.w, 0);
909
+ });
910
+ return { raster: out, frame: { w: f.w, h: f.h }, clips: { idle: frames.map((_, i) => i) }, fps };
911
+ }
912
+ var one = (r) => ({ raster: r, frame: { w: r.w, h: r.h } });
913
+ var union = (...ds) => Math.min(...ds);
914
+ function sdStar(u, v, outer, inner) {
915
+ const a = Math.atan2(u, -v);
916
+ const k = Math.abs((a / (2 * Math.PI) * 5 % 1 + 1) % 1 - 0.5) * 2;
917
+ return Math.hypot(u, v) - (inner + (outer - inner) * k ** 1.6);
918
+ }
919
+ var wobble = (u, v, r, seed, amount) => {
920
+ const a = Math.atan2(v, u) / (2 * Math.PI) + 0.5;
921
+ return Math.hypot(u, v) - r * (1 + amount * (noise(a * 6, 0.5, 6, 1, seed) - 0.5));
922
+ };
923
+ var lightTint = (c) => shade(c, 0.25);
924
+ var PICKUPS = [
925
+ {
926
+ name: "coin",
927
+ family: "pickup",
928
+ kind: "animation",
929
+ description: "A coin that spins, in the treasure colour.",
930
+ options: {},
931
+ render: (_o, dna, p) => strip([1, 0.62, 0.2, 0.62].map((sx, i) => picture((u, v) => (Math.hypot(u / (0.72 * sx), v / 0.72) - 1) * 0.72 * sx, p.treasure, dna, p, 1, 1, {
932
+ gloss: i === 0,
933
+ detail: (u, v, d) => i === 0 && d < -0.17 && d > -0.24 ? shade(p.treasure, -0.3) : i === 0 && sdBox(u, v, 0.08, 0.28) < 0 ? shade(p.treasure, 0.35) : null
934
+ })), 8)
935
+ },
936
+ {
937
+ name: "gem",
938
+ family: "pickup",
939
+ kind: "picture",
940
+ description: "A cut gem in the treasure accent.",
941
+ options: { cut: { kind: "enum", values: ["round", "square", "diamond", "tear"], default: "diamond", note: "the cut" } },
942
+ render: (o, dna, p) => {
943
+ const cut = String(o["cut"]);
944
+ const base = mix(p.treasure, p.hero, 0.55);
945
+ const sd = cut === "round" ? (u, v) => sdCircle(u, v, 0.66) : cut === "square" ? (u, v) => sdBox(u, v, 0.58, 0.58, 0.08) : cut === "tear" ? (u, v) => union(sdCircle(u, v - 0.18, 0.48), sdTriangle(u, v + 0.75, 0.36, 0.6)) : (u, v) => Math.max((Math.abs(u) / 0.78 + Math.abs(v + 0.05) / 0.82 - 1) * 0.55, -(v + 0.48));
946
+ return one(picture(sd, base, dna, p, 1, 1, {
947
+ gloss: true,
948
+ detail: (u, v) => {
949
+ if (cut !== "diamond")
950
+ return null;
951
+ const face = v < -0.2 ? Math.abs(u) < 0.28 ? 0.92 : 0.75 : u < 0 ? 0.55 : 0.32;
952
+ return face > 0.8 ? shade(base, 0.4) : face > 0.6 ? shade(base, 0.15) : face > 0.45 ? base : shade(base, -0.25);
953
+ }
954
+ }));
955
+ }
956
+ },
957
+ {
958
+ name: "heart",
959
+ family: "pickup",
960
+ kind: "picture",
961
+ description: "A heart, a life.",
962
+ options: {},
963
+ render: (_o, dna, p) => one(picture((u, v) => sdHeart(u * 0.72, v * 0.68 + 0.02), lightTint(p.danger), dna, p, 1, 1, { gloss: true }))
964
+ },
965
+ {
966
+ name: "key",
967
+ family: "pickup",
968
+ kind: "picture",
969
+ description: "A key, in the treasure colour.",
970
+ options: {},
971
+ render: (_o, dna, p) => {
972
+ const k = dna.pixel ? 1.6 : 1;
973
+ return one(picture((u, v) => union(Math.abs(sdCircle(u + 0.42, v, 0.3)) - 0.11 * k, sdBox(u - 0.2, v, 0.5, 0.09 * k), sdBox(u - 0.56, v - 0.2, 0.08 * k, 0.14), sdBox(u - 0.3, v - 0.17, 0.07 * k, 0.1)), p.treasure, dna, p));
974
+ }
975
+ },
976
+ {
977
+ name: "star",
978
+ family: "pickup",
979
+ kind: "picture",
980
+ description: "A star, a bonus.",
981
+ options: {},
982
+ render: (_o, dna, p) => one(picture((u, v) => sdStar(u, v, 0.8, 0.36), p.treasure, dna, p, 1, 1, { gloss: true }))
983
+ },
984
+ {
985
+ name: "potion",
986
+ family: "pickup",
987
+ kind: "picture",
988
+ description: "A bottle with something to drink.",
989
+ options: {},
990
+ render: (_o, dna, p) => one(picture((u, v) => union(sdCircle(u, v - 0.22, 0.5), sdBox(u, v + 0.42, 0.16, 0.24), sdBox(u, v + 0.7, 0.2, 0.08)), p.metal, dna, p, 1, 1, {
991
+ gloss: true,
992
+ detail: (u, v, d) => v > 0.02 && d < -0.06 ? v < 0.1 ? shade(p.danger, 0.3) : p.danger : v < -0.62 && Math.abs(u) < 0.2 ? p.wood : null
993
+ }))
994
+ },
995
+ {
996
+ name: "orb",
997
+ family: "pickup",
998
+ kind: "picture",
999
+ description: "A glowing orb, a power-up.",
1000
+ options: {},
1001
+ render: (_o, dna, p) => one(picture((u, v) => sdCircle(u, v, 0.66), p.hero, dna, p, 1, 1, { gloss: true }))
1002
+ },
1003
+ {
1004
+ name: "ring",
1005
+ family: "pickup",
1006
+ kind: "picture",
1007
+ description: "A ring with a stone.",
1008
+ options: {},
1009
+ render: (_o, dna, p) => one(picture((u, v) => union(Math.abs(sdCircle(u, v + 0.08, 0.48)) - 0.11, sdCircle(u, v + 0.62, 0.18)), p.treasure, dna, p, 1, 1, {
1010
+ detail: (u, v, d) => v < -0.44 && d < -0.03 ? mix(p.treasure, p.hero, 0.7) : null
1011
+ }))
1012
+ },
1013
+ {
1014
+ name: "chest",
1015
+ family: "pickup",
1016
+ kind: "picture",
1017
+ description: "A treasure chest, closed or open.",
1018
+ options: { open: { kind: "enum", values: ["no", "yes"], default: "no", note: "open shows the gold inside" } },
1019
+ render: (o, dna, p) => {
1020
+ const open = o["open"] === "yes";
1021
+ const sd = open ? (u, v) => union(sdBox(u, v - 0.3, 0.72, 0.42, 0.06), sdBox(u, v + 0.42, 0.72, 0.16, 0.08)) : (u, v) => union(sdBox(u, v - 0.22, 0.72, 0.5, 0.06), Math.max(sdCircle(u * 0.6, v + 0.1, 0.44), v + 0.1 - 0.6));
1022
+ return one(picture(sd, p.wood, dna, p, 1, 1, {
1023
+ detail: (u, v, d) => {
1024
+ if (open && v > -0.12 && v < 0.02 && Math.abs(u) < 0.66)
1025
+ return lightTint(p.treasure);
1026
+ if (Math.abs(u) < 0.1 && Math.abs(v - 0.05) < 0.12)
1027
+ return p.treasure;
1028
+ if (d > -0.12 || Math.abs(v + (open ? 0 : 0.28)) < 0.05)
1029
+ return shade(p.treasure, -0.15);
1030
+ return null;
1031
+ }
1032
+ }));
1033
+ }
1034
+ },
1035
+ {
1036
+ name: "clock",
1037
+ family: "pickup",
1038
+ kind: "picture",
1039
+ description: "A clock, more time.",
1040
+ options: {},
1041
+ render: (_o, dna, p) => one(picture((u, v) => sdCircle(u, v, 0.7), p.treasure, dna, p, 1, 1, {
1042
+ detail: (u, v, d) => {
1043
+ if (d > -0.14)
1044
+ return null;
1045
+ if (sdCapsule(u, v, 0, 0, 0, -0.38, 0.05) < 0 || sdCapsule(u, v, 0, 0, 0.26, 0.1, 0.05) < 0)
1046
+ return p.outline;
1047
+ return p.light;
1048
+ }
1049
+ }))
1050
+ }
1051
+ ];
1052
+ var PROPS = [
1053
+ {
1054
+ name: "crate",
1055
+ family: "prop",
1056
+ kind: "picture",
1057
+ description: "A wooden crate.",
1058
+ options: {},
1059
+ render: (_o, dna, p) => one(picture((u, v) => sdBox(u, v, 0.8, 0.8, 0.06 + 0.1 * dna.roundness), p.wood, dna, p, 1, 1, {
1060
+ detail: (u, v, d) => d > -0.18 ? shade(p.wood, 0.12) : Math.abs(u - v) < 0.12 ? shade(p.wood, 0.12) : Math.abs(u - v) < 0.18 ? shade(p.wood, -0.3) : null
1061
+ }))
1062
+ },
1063
+ {
1064
+ name: "barrel",
1065
+ family: "prop",
1066
+ kind: "picture",
1067
+ description: "A barrel with metal hoops.",
1068
+ options: {},
1069
+ render: (_o, dna, p) => one(picture((u, v) => sdBox(u * (1 + 0.25 * v * v), v, 0.58, 0.8, 0.2), p.wood, dna, p, 1, 1, {
1070
+ detail: (_u, v) => Math.abs(Math.abs(v) - 0.5) < 0.07 ? p.metal : null
1071
+ }))
1072
+ },
1073
+ {
1074
+ name: "door",
1075
+ family: "prop",
1076
+ kind: "picture",
1077
+ description: "A door, one tile wide and two high.",
1078
+ options: {},
1079
+ render: (_o, dna, p) => one(picture((u, v) => union(sdBox(u, v - 0.3, 0.86, 1.62), sdCircle(u, v + 1.12, 0.86)), p.wood, dna, p, 1, 2, {
1080
+ detail: (u, v, d) => d > -0.14 ? shade(p.wood, -0.3) : Math.hypot(u - 0.48, v - 0.3) < 0.1 ? p.treasure : Math.abs(u + 0.28) < 0.04 || Math.abs(u - 0.28) < 0.04 ? shade(p.wood, -0.3) : null
1081
+ }))
1082
+ },
1083
+ {
1084
+ name: "sign",
1085
+ family: "prop",
1086
+ kind: "picture",
1087
+ description: "A signpost.",
1088
+ options: {},
1089
+ render: (_o, dna, p) => one(picture((u, v) => union(sdBox(u, v + 0.15, 0.72, 0.36, 0.06), sdBox(u, v - 0.5, 0.09, 0.38)), p.wood, dna, p, 1, 1, {
1090
+ detail: (u, v) => v < 0.1 && v > -0.4 && Math.abs(v + 0.15) < 0.04 && Math.abs(u) < 0.5 ? shade(p.wood, -0.4) : null
1091
+ }))
1092
+ },
1093
+ {
1094
+ name: "rock",
1095
+ family: "prop",
1096
+ kind: "picture",
1097
+ description: "A rock; each one a little different.",
1098
+ options: {},
1099
+ render: (_o, dna, p, seed) => one(picture((u, v) => Math.max(wobble(u, v - 0.18, 0.66, seed, 0.35), v - 0.82), p.stone, dna, p))
1100
+ },
1101
+ {
1102
+ name: "bush",
1103
+ family: "prop",
1104
+ kind: "picture",
1105
+ description: "A bush; each one a little different.",
1106
+ options: {},
1107
+ render: (_o, dna, p, seed) => one(picture((u, v) => {
1108
+ let d = 9;
1109
+ for (let i = 0; i < 4; i++)
1110
+ d = Math.min(d, sdCircle(u - (i - 1.5) * 0.36, v - 0.25 + 0.2 * hash(i, 1, seed), 0.34 + 0.12 * hash(i, 2, seed)));
1111
+ return Math.max(d, v - 0.8);
1112
+ }, p.foliage, dna, p))
1113
+ },
1114
+ {
1115
+ name: "tree",
1116
+ family: "prop",
1117
+ kind: "picture",
1118
+ description: "A tree, one tile wide and two high; each one a little different.",
1119
+ options: {},
1120
+ render: (_o, dna, p, seed) => one(picture((u, v) => {
1121
+ let crown = 9;
1122
+ for (let i = 0; i < 5; i++)
1123
+ crown = Math.min(crown, sdCircle(u - 0.5 * (hash(i, 3, seed) - 0.5), v + 1.05 - 0.6 * hash(i, 4, seed), 0.52 + 0.14 * hash(i, 5, seed)));
1124
+ return union(crown, sdBox(u, v - 0.9, 0.15, 1));
1125
+ }, p.foliage, dna, p, 1, 2, {
1126
+ detail: (_u, v, d) => v > 0 && d < -0.02 ? p.wood : null
1127
+ }))
1128
+ },
1129
+ {
1130
+ name: "mushroom",
1131
+ family: "prop",
1132
+ kind: "picture",
1133
+ description: "A spotted mushroom.",
1134
+ options: {},
1135
+ render: (_o, dna, p) => one(picture((u, v) => union(sdBox(u, v - 0.45, 0.2, 0.36, 0.08), Math.max(sdCircle(u, v - 0.1, 0.72), v - 0.08)), p.danger, dna, p, 1, 1, {
1136
+ detail: (u, v) => v > 0.1 ? p.light : Math.hypot(u + 0.3, v + 0.3) < 0.12 || Math.hypot(u - 0.25, v + 0.42) < 0.1 ? p.light : null
1137
+ }))
1138
+ },
1139
+ {
1140
+ name: "fence",
1141
+ family: "prop",
1142
+ kind: "picture",
1143
+ description: "A fence section that joins the next one.",
1144
+ options: {},
1145
+ render: (_o, dna, p) => one(picture((u, v) => union(sdBox(u + 0.55, v - 0.15, 0.13, 0.75, 0.04), sdBox(u - 0.55, v - 0.15, 0.13, 0.75, 0.04), sdBox(u, v + 0.15, 1.02, 0.08), sdBox(u, v - 0.4, 1.02, 0.08)), p.wood, dna, p))
1146
+ },
1147
+ {
1148
+ name: "torch",
1149
+ family: "prop",
1150
+ kind: "animation",
1151
+ description: "A torch whose flame flickers.",
1152
+ options: {},
1153
+ render: (_o, dna, p) => strip([0, 1, 2, 3].map((f) => picture((u, v) => {
1154
+ const lean = 0.08 * Math.sin(f * 1.7);
1155
+ const flame = union(sdCircle(u - lean * (v + 0.6), v + 0.38, 0.32 + 0.03 * Math.cos(f)), sdTriangle(u - lean * 1.5, v + 0.92, 0.24, 0.6));
1156
+ return union(sdBox(u, v - 0.35, 0.14, 0.5), flame);
1157
+ }, p.wood, dna, p, 1, 1, {
1158
+ detail: (_u, v) => v < -0.1 ? v < -0.45 ? p.light : mix(p.treasure, p.danger, 0.4) : null
1159
+ })), 10)
1160
+ },
1161
+ {
1162
+ name: "flag",
1163
+ family: "prop",
1164
+ kind: "animation",
1165
+ description: "A flag waving on its pole, a goal.",
1166
+ options: {},
1167
+ render: (_o, dna, p) => strip([0, 1, 2, 3].map((f) => picture((u, v) => {
1168
+ const wave = 0.08 * Math.sin(u * 4 + f * Math.PI / 2);
1169
+ return union(sdBox(u + 0.62, v, 0.06, 0.82), sdBox(u - 0.05, v + 0.45 - wave, 0.58, 0.26));
1170
+ }, p.hero, dna, p, 1, 1, {
1171
+ detail: (u) => u < -0.52 ? p.metal : null
1172
+ })), 6)
1173
+ },
1174
+ {
1175
+ name: "spikes",
1176
+ family: "prop",
1177
+ kind: "picture",
1178
+ description: "Spikes, a hazard.",
1179
+ options: {},
1180
+ render: (_o, dna, p) => one(picture((u, v) => union(...dna.pixel ? [sdTriangle(u + 0.42, v + 0.55, 0.4, 1.25), sdTriangle(u - 0.42, v + 0.55, 0.4, 1.25)] : [sdTriangle(u + 0.56, v + 0.5, 0.26, 1.15), sdTriangle(u, v + 0.5, 0.26, 1.15), sdTriangle(u - 0.56, v + 0.5, 0.26, 1.15)], sdBox(u, v - 0.75, 0.88, 0.1, 0.03)), mix(p.metal, p.danger, 0.25), dna, p))
1181
+ }
1182
+ ];
1183
+ var ARCADE = [
1184
+ {
1185
+ name: "brick",
1186
+ family: "arcade",
1187
+ kind: "picture",
1188
+ description: "A brick to break, two tiles wide when long; cracked by damage.",
1189
+ options: {
1190
+ shape: { kind: "enum", values: ["long", "square", "round"], default: "long", note: "its shape" },
1191
+ damage: { kind: "enum", values: ["0", "1", "2"], default: "0", note: "how cracked it is" }
1192
+ },
1193
+ render: (o, dna, p, seed) => {
1194
+ const long = o["shape"] === "long", round = o["shape"] === "round";
1195
+ const cracks = Number(o["damage"]);
1196
+ return one(picture((u, v) => round ? sdBox(u, v, long ? 1.9 : 0.9, 0.8, 0.6) : sdBox(u, v, long ? 1.96 : 0.96, 0.88, 0.12), mix(p.hero, p.danger, 0.3), dna, p, long ? 2 : 1, 1, {
1197
+ gloss: false,
1198
+ detail: (u, v) => {
1199
+ for (let c = 0; c < cracks; c++) {
1200
+ const x0 = (hash(c, 1, seed) - 0.5) * 1.2;
1201
+ if (Math.abs(u - x0 - 0.35 * Math.sin(v * 5 + c)) < 0.04)
1202
+ return p.outline;
1203
+ }
1204
+ return null;
1205
+ }
1206
+ }));
1207
+ }
1208
+ },
1209
+ {
1210
+ name: "paddle",
1211
+ family: "arcade",
1212
+ kind: "picture",
1213
+ description: "A paddle, three tiles wide.",
1214
+ options: {},
1215
+ render: (_o, dna, p) => one(picture((u, v) => sdCapsule(u, v, -2.7, 0, 2.7, 0, 0.4), p.hero, dna, p, 3, 1, { gloss: true }))
1216
+ },
1217
+ {
1218
+ name: "ball",
1219
+ family: "arcade",
1220
+ kind: "picture",
1221
+ description: "A ball.",
1222
+ options: {},
1223
+ render: (_o, dna, p) => one(picture((u, v) => sdCircle(u, v, 0.7), p.light, dna, p, 1, 1, { gloss: true }))
1224
+ },
1225
+ {
1226
+ name: "bumper",
1227
+ family: "arcade",
1228
+ kind: "picture",
1229
+ description: "A round bumper.",
1230
+ options: {},
1231
+ render: (_o, dna, p) => one(picture((u, v) => sdCircle(u, v, 0.78), p.danger, dna, p, 1, 1, {
1232
+ detail: (_u, _v, d) => d < -0.3 ? lightTint(p.danger) : d < -0.22 ? p.light : null
1233
+ }))
1234
+ },
1235
+ {
1236
+ name: "bar",
1237
+ family: "arcade",
1238
+ kind: "picture",
1239
+ description: "A wall bar, two tiles wide and half a tile high.",
1240
+ options: {},
1241
+ render: (_o, dna, p) => one(picture((u, v) => sdBox(u, v, 4, 0.94, 0.15), p.metal, dna, p, 2, 0.5))
1242
+ },
1243
+ {
1244
+ name: "target",
1245
+ family: "arcade",
1246
+ kind: "picture",
1247
+ description: "A target with rings.",
1248
+ options: {},
1249
+ render: (_o, dna, p) => one(picture((u, v) => sdCircle(u, v, 0.78), p.light, dna, p, 1, 1, {
1250
+ detail: (u, v) => {
1251
+ const r = Math.hypot(u, v);
1252
+ return r < 0.2 ? p.danger : r < 0.38 ? p.light : r < 0.56 ? p.danger : null;
1253
+ }
1254
+ }))
1255
+ }
1256
+ ];
1257
+ register(...[...PICKUPS, ...PROPS, ...ARCADE].map(seeded));
1258
+
1259
+ // ../artgen/dist/recipes/effects.js
1260
+ function frame(sd, base, dna, p, alpha = 1, opts = {}) {
1261
+ const S = tileSize(dna);
1262
+ const sh = shapeShader(sd, base, dna, p, S, opts);
1263
+ return new Raster(S, S).paint((x, y) => {
1264
+ const c = sh(x, y);
1265
+ return [c[0], c[1], c[2], c[3] * alpha];
1266
+ }, dna.pixel ? 1 : 3);
1267
+ }
1268
+ function strip2(frames, fps) {
1269
+ const f = frames[0];
1270
+ const out = new Raster(f.w * frames.length, f.h);
1271
+ frames.forEach((r, i) => {
1272
+ out.blit(r, i * f.w, 0);
1273
+ });
1274
+ return { raster: out, frame: { w: f.w, h: f.h }, clips: { idle: frames.map((_, i) => i) }, fps };
1275
+ }
1276
+ var FOUR = [0, 1, 2, 3];
1277
+ var EFFECTS = [
1278
+ {
1279
+ name: "bullet",
1280
+ family: "effect",
1281
+ kind: "animation",
1282
+ seeded: false,
1283
+ description: "A bullet, flying right.",
1284
+ options: {},
1285
+ render: (_o, dna, p) => strip2([0, 1].map((f) => frame((u, v) => sdCapsule(u, v, -0.3, 0, 0.3, 0, 0.16 + 0.02 * f), p.treasure, dna, p, 1, { gloss: true })), 12)
1286
+ },
1287
+ {
1288
+ name: "laser",
1289
+ family: "effect",
1290
+ kind: "animation",
1291
+ seeded: false,
1292
+ description: "A laser bolt, flying right.",
1293
+ options: {},
1294
+ render: (_o, dna, p) => strip2([0, 1].map((f) => frame((u, v) => sdCapsule(u, v, -0.75, 0, 0.75, 0, 0.09 + 0.03 * f), p.hero, dna, p, 1, {
1295
+ detail: (_u, _v, d) => d < -0.05 ? mix(p.hero, [1, 1, 1, 1], 0.7) : null
1296
+ })), 16)
1297
+ },
1298
+ {
1299
+ name: "fireball",
1300
+ family: "effect",
1301
+ kind: "animation",
1302
+ seeded: false,
1303
+ description: "A fireball, flying right.",
1304
+ options: {},
1305
+ render: (_o, dna, p) => strip2(FOUR.map((f) => frame((u, v) => Math.min(sdCircle(u - 0.25, v, 0.34), sdTriangle(v + 1e-4, -(u - 0.15) + 1e-4, 0.26 + 0.04 * Math.sin(f * 1.6), 0.75 + 0.08 * Math.cos(f))), mix(p.treasure, p.danger, 0.5), dna, p, 1, {
1306
+ detail: (u, _v, d) => d < -0.12 && u > 0.05 ? p.light : null
1307
+ })), 12)
1308
+ },
1309
+ {
1310
+ name: "arrow",
1311
+ family: "effect",
1312
+ kind: "animation",
1313
+ seeded: false,
1314
+ description: "An arrow, flying right.",
1315
+ options: {},
1316
+ render: (_o, dna, p) => strip2([frame((u, v) => Math.min(sdBox(u, v, 0.62, 0.05), sdTriangle(v, -(u - 0.82), 0.16, 0.28), sdBox(u + 0.62, v, 0.12, 0.13)), p.wood, dna, p, 1, { detail: (u) => u > 0.55 ? p.metal : u < -0.48 ? p.light : null })], 1)
1317
+ },
1318
+ {
1319
+ name: "sparkle",
1320
+ family: "effect",
1321
+ kind: "animation",
1322
+ seeded: false,
1323
+ description: "A sparkle that twinkles.",
1324
+ options: {},
1325
+ render: (_o, dna, p) => strip2(FOUR.map((f) => {
1326
+ const k = [0.45, 0.8, 0.55, 0.25][f] ?? 0.5;
1327
+ return frame((u, v) => Math.min(sdBox(u, v, 0.08, 0.75 * k, 0.05), sdBox(u, v, 0.75 * k, 0.08, 0.05)), p.light, dna, p);
1328
+ }), 10)
1329
+ },
1330
+ {
1331
+ name: "puff",
1332
+ family: "effect",
1333
+ kind: "animation",
1334
+ description: "A puff of smoke that spreads and fades.",
1335
+ options: {},
1336
+ render: (_o, dna, p, seed) => strip2([0, 1, 2, 3, 4].map((f) => frame((u, v) => {
1337
+ let d = 9;
1338
+ for (let i = 0; i < 4; i++) {
1339
+ const a = i / 4 * Math.PI * 2 + hash(i, 1, seed);
1340
+ d = Math.min(d, sdCircle(u - Math.cos(a) * 0.12 * (f + 1), v - Math.sin(a) * 0.1 * (f + 1), 0.22 + 0.04 * f));
1341
+ }
1342
+ return d;
1343
+ }, shade(p.stone, 0.35), dna, p, 1 - f * 0.18)), 10)
1344
+ },
1345
+ {
1346
+ name: "explosion",
1347
+ family: "effect",
1348
+ kind: "animation",
1349
+ seeded: false,
1350
+ description: "An explosion that grows, then fades.",
1351
+ options: {},
1352
+ render: (_o, dna, p) => strip2([0, 1, 2, 3, 4, 5].map((f) => {
1353
+ const r = [0.25, 0.45, 0.62, 0.72, 0.78, 0.8][f] ?? 0.8;
1354
+ const colour = f < 2 ? p.light : f < 4 ? mix(p.treasure, p.danger, 0.5) : shade(p.stone, -0.1);
1355
+ return frame((u, v) => sdCircle(u, v, r), colour, dna, p, f < 4 ? 1 : 1 - (f - 3) * 0.4, {
1356
+ detail: (u, v, d) => f >= 2 && f < 4 && d < -0.25 ? p.light : f >= 4 && Math.hypot(u, v) < r * 0.5 ? shade(p.stone, 0.2) : null
1357
+ });
1358
+ }), 14)
1359
+ },
1360
+ {
1361
+ name: "flash",
1362
+ family: "effect",
1363
+ kind: "animation",
1364
+ seeded: false,
1365
+ description: "A hit flash.",
1366
+ options: {},
1367
+ render: (_o, dna, p) => strip2([0, 1, 2].map((f) => frame((u, v) => sdCircle(u, v, 0.7 - f * 0.2), p.light, dna, p, 1 - f * 0.3)), 20)
1368
+ }
1369
+ ];
1370
+ register(...EFFECTS);
1371
+
1372
+ // ../artgen/dist/recipes/creatures.js
1373
+ var GROUND = 0.88;
1374
+ var POSES = [
1375
+ { sx: 1, sy: 1, lean: 0, step: 0, flap: 0 },
1376
+ { sx: 1.05, sy: 0.94, lean: 0, step: 0, flap: 1 },
1377
+ { sx: 0.96, sy: 1.04, lean: 0.16, step: 1, flap: 0 },
1378
+ { sx: 1.06, sy: 0.92, lean: 0.22, step: 2, flap: 1 },
1379
+ { sx: 0.95, sy: 1.05, lean: 0.16, step: 3, flap: 0 },
1380
+ { sx: 1.04, sy: 0.94, lean: 0.2, step: 4, flap: 1 },
1381
+ { sx: 0.88, sy: 1.12, lean: 0.06, step: 0, flap: 1 },
1382
+ { sx: 1.1, sy: 0.9, lean: -0.04, step: 0, flap: 0 },
1383
+ { sx: 0.94, sy: 1.02, lean: -0.34, step: 0, flap: 0, eyes: "shut" },
1384
+ { sx: 1.14, sy: 0.9, lean: 0.44, step: 2, flap: 1 },
1385
+ { sx: 1.22, sy: 0.64, lean: 0, step: 0, flap: 0, eyes: "dead", fallen: true }
1386
+ ];
1387
+ var BODIES = {
1388
+ blob: { bw: 0.62, bh: 0.48 },
1389
+ round: { bw: 0.52, bh: 0.52 },
1390
+ bean: { bw: 0.4, bh: 0.64 },
1391
+ square: { bw: 0.52, bh: 0.5 },
1392
+ flyer: { bw: 0.44, bh: 0.44 },
1393
+ bug: { bw: 0.68, bh: 0.34 }
1394
+ };
1395
+ function creatureFrame(o, dna, p, pose, S, seed) {
1396
+ const body = String(o["body"]), eyes = String(o["eyes"]), mouth = String(o["mouth"]);
1397
+ const extra = String(o["extra"]), feet = body === "flyer" || pose.fallen === true ? "none" : String(o["feet"]);
1398
+ const j = (k) => hash(seed, k, 31) - 0.5;
1399
+ const colour = shade(o["role"] === "enemy" ? p.danger : p.hero, 0.14 * j(1));
1400
+ const kind = BODIES[body] ?? { bw: 0.5, bh: 0.5 };
1401
+ const dims = { bw: kind.bw * (1 + 0.16 * j(2)), bh: kind.bh * (1 + 0.12 * j(3)) };
1402
+ const bw = dims.bw * pose.sx, bh = dims.bh * pose.sy;
1403
+ const flying = body === "flyer" && pose.fallen !== true;
1404
+ const bottom = flying ? 0.25 + 0.04 * Math.sin(pose.flap * Math.PI) : feet === "legs" ? GROUND - 0.2 : feet === "stubs" ? GROUND - 0.07 : GROUND;
1405
+ const cy = bottom - bh;
1406
+ const lean = pose.lean;
1407
+ const lx = (u, v) => u - lean * (bottom - v) * 0.5;
1408
+ const round = 0.1 + 0.25 * dna.roundness;
1409
+ const bodySd = body === "square" ? (u, v) => sdBox(lx(u, v), v - cy, bw, bh, round) : (u, v) => {
1410
+ const e = (Math.hypot(lx(u, v) / bw, (v - cy) / bh) - 1) * Math.min(bw, bh);
1411
+ return flying ? e : Math.max(e, v - bottom);
1412
+ };
1413
+ const parts = [];
1414
+ const at = (fx, fy) => [fx * bw + lean * (bottom - (cy + fy * bh)) * 0.5, cy + fy * bh];
1415
+ if (extra === "tail") {
1416
+ const [ax, ay] = at(-0.85, 0.3), [bx, by] = at(-1.25, -0.25);
1417
+ parts.push({ sd: (u, v) => sdCapsule(u, v, ax, ay, bx, by, 0.07), base: shade(colour, -0.15) });
1418
+ }
1419
+ if (flying || extra === "wings") {
1420
+ const angle = pose.flap === 1 ? -0.7 : 0.15;
1421
+ const [wx, wy] = at(-0.7, -0.85);
1422
+ const c = Math.cos(angle), s = Math.sin(angle);
1423
+ parts.push({
1424
+ sd: (u, v) => {
1425
+ const du = u - wx, dv = v - wy;
1426
+ const ru = du * c - dv * s, rv = du * s + dv * c;
1427
+ return (Math.hypot(ru / 0.4, rv / 0.2) - 1) * 0.2;
1428
+ },
1429
+ base: mix(p.light, colour, 0.25)
1430
+ });
1431
+ }
1432
+ if (feet === "legs") {
1433
+ for (const side of [-1, 1]) {
1434
+ const swing = pose.step === 0 ? 0 : 0.12 * Math.sin(pose.step / 4 * Math.PI * 2 + (side > 0 ? 0 : Math.PI));
1435
+ const hx = side * 0.22 * dims.bw;
1436
+ parts.push({ sd: (u, v) => sdCapsule(u, v, hx, bottom - 0.04, hx + swing, GROUND - 0.06, 0.06), base: shade(colour, -0.3) });
1437
+ }
1438
+ }
1439
+ if (feet === "stubs") {
1440
+ for (const side of [-1, 1]) {
1441
+ const hx = side * 0.3 * dims.bw + (pose.step % 2 === 1 ? 0.03 * side : 0);
1442
+ parts.push({ sd: (u, v) => (Math.hypot((u - hx) / 0.15, (v - (GROUND - 0.07)) / 0.07) - 1) * 0.07, base: shade(colour, -0.3) });
1443
+ }
1444
+ }
1445
+ parts.push({
1446
+ sd: bodySd,
1447
+ base: colour,
1448
+ opts: {
1449
+ gloss: dna.shading !== "flat",
1450
+ ...body === "bug" ? { detail: (u, v, d) => d < -0.03 && Math.abs((lx(u, v) / bw + 1) * 2.5 % 1 - 0.5) > 0.46 ? shade(colour, -0.3) : null } : {}
1451
+ }
1452
+ });
1453
+ if (extra === "shell") {
1454
+ const [sx, sy] = at(-0.25, -0.15);
1455
+ parts.push({
1456
+ sd: (u, v) => Math.max((Math.hypot((u - sx) / (bw * 0.75), (v - sy) / (bh * 0.85)) - 1) * bh * 0.8, v - (cy + bh * 0.55)),
1457
+ base: mix(p.wood, p.treasure, 0.4),
1458
+ opts: { detail: (u, v, d) => d < -0.04 && Math.abs(Math.hypot(u - sx, v - sy) % 0.14 - 0.07) < 0.012 ? shade(mix(p.wood, p.treasure, 0.4), -0.35) : null }
1459
+ });
1460
+ }
1461
+ if (extra === "spikes") {
1462
+ for (const k of [-0.55, -0.2, 0.15]) {
1463
+ const [tx, ty] = at(k, -0.92);
1464
+ parts.push({ sd: (u, v) => sdTriangle(u - tx, v - (ty - 0.2), 0.08, 0.22), base: p.light });
1465
+ }
1466
+ }
1467
+ if (extra === "horns" || extra === "ears") {
1468
+ for (const k of [-0.4, 0.25]) {
1469
+ const [tx, ty] = at(k, -0.85);
1470
+ parts.push(extra === "horns" ? { sd: (u, v) => sdTriangle(u - tx, v - (ty - 0.24), 0.07, 0.26), base: p.light } : { sd: (u, v) => sdTriangle(u - tx, v - (ty - 0.22), 0.13, 0.26) - 0.03, base: shade(colour, -0.1) });
1471
+ }
1472
+ }
1473
+ if (extra === "antennae") {
1474
+ for (const k of [-0.25, 0.3]) {
1475
+ const [tx, ty] = at(k, -0.9);
1476
+ const ex = tx + 0.12, ey = ty - 0.3;
1477
+ parts.push({ sd: (u, v) => Math.min(sdCapsule(u, v, tx, ty, ex, ey, 0.025), sdCircle(u - ex, v - ey, 0.06)), base: p.outline });
1478
+ }
1479
+ }
1480
+ if (extra === "hat") {
1481
+ const [hx, hy] = at(0.05, -0.86);
1482
+ parts.push({ sd: (u, v) => Math.min(sdBox(u - hx, v - (hy - 0.16), 0.26, 0.18, 0.04), sdBox(u - hx, v - (hy + 0.02), 0.42, 0.045, 0.02)), base: shade(p.outline, 0.35) });
1483
+ }
1484
+ const gap = 0.12 * j(4), size = 1 + 0.3 * j(5);
1485
+ const eyeSpots = eyes === "cyclops" ? [[0.3, 0.26 * size]] : [[0.02 - gap, 0.18 * size], [0.5 + gap, 0.18 * size]];
1486
+ for (const [ex, er] of eyeSpots) {
1487
+ const [x0, y0] = at(ex, -0.25);
1488
+ const r = er * Math.min(dims.bw, dims.bh) / 0.52;
1489
+ const stroke = Math.max(0.03, r * 0.28);
1490
+ if (pose.eyes === "shut") {
1491
+ parts.push({ sd: (u, v) => sdCapsule(u, v, x0 - r, y0, x0 + r, y0, stroke), base: p.outline });
1492
+ continue;
1493
+ }
1494
+ if (pose.eyes === "dead") {
1495
+ parts.push({
1496
+ sd: (u, v) => Math.min(sdCapsule(u, v, x0 - r, y0 - r, x0 + r, y0 + r, stroke), sdCapsule(u, v, x0 - r, y0 + r, x0 + r, y0 - r, stroke)),
1497
+ base: p.outline
1498
+ });
1499
+ continue;
1500
+ }
1501
+ parts.push({
1502
+ sd: (u, v) => sdCircle(u - x0, v - y0, r),
1503
+ base: [1, 1, 1, 1],
1504
+ opts: {
1505
+ detail: (u, v) => {
1506
+ if (eyes === "sleepy" && v < y0)
1507
+ return shade(colour, -0.08);
1508
+ if (Math.hypot(u - x0 - r * 0.3, v - y0) < r * 0.48)
1509
+ return p.outline;
1510
+ return [1, 1, 1, 1];
1511
+ }
1512
+ }
1513
+ });
1514
+ if (eyes === "angry") {
1515
+ parts.push({ sd: (u, v) => sdCapsule(u, v, x0 - r * 1.1, y0 - r * 1.35, x0 + r * 1.1, y0 - r * 0.9, Math.max(0.035, r * 0.22)), base: p.outline });
1516
+ }
1517
+ }
1518
+ const [mx, my] = at(0.32, 0.25);
1519
+ if (mouth === "smile" || mouth === "fangs") {
1520
+ parts.push({ sd: (u, v) => Math.max(Math.abs(Math.hypot(u - mx, v - (my - 0.1)) - 0.13) - 0.03, -(v - (my - 0.04))), base: p.outline });
1521
+ if (mouth === "fangs") {
1522
+ for (const k of [-0.06, 0.06])
1523
+ parts.push({ sd: (u, v) => sdTriangle(u - (mx + k), v - (my + 0.02), 0.035, -1e-4 + 0.09), base: [1, 1, 1, 1] });
1524
+ }
1525
+ }
1526
+ if (mouth === "beak") {
1527
+ const [bx, by] = at(0.85, 0.05);
1528
+ parts.push({ sd: (u, v) => Math.max(Math.abs(v - by) - (bx + 0.24 - u) * 0.45, bx - 0.04 - u, u - (bx + 0.24)), base: p.treasure });
1529
+ }
1530
+ const shaders = parts.map((part) => ({ sd: part.sd, sh: shapeShader(part.sd, part.base, dna, p, S, part.opts) }));
1531
+ return new Raster(S, S).paint((x, y) => {
1532
+ const u = x / S * 2 - 1, v = y / S * 2 - 1;
1533
+ for (let i = shaders.length - 1; i >= 0; i--) {
1534
+ const s = shaders[i];
1535
+ if (s.sd(u, v) <= 0)
1536
+ return s.sh(x, y);
1537
+ }
1538
+ return CLEAR;
1539
+ }, dna.pixel ? 1 : 3);
1540
+ }
1541
+ register({
1542
+ name: "creature",
1543
+ family: "creature",
1544
+ kind: "animation",
1545
+ description: "A creature built from parts, with idle, run, jump and fall, and hurt, attack and death for a script to play. role hero for the player, enemy for enemies.",
1546
+ options: {
1547
+ body: { kind: "enum", values: ["blob", "round", "bean", "square", "flyer", "bug"], default: "blob", note: "its body; flyer floats and flaps" },
1548
+ eyes: { kind: "enum", values: ["round", "angry", "sleepy", "cyclops"], default: "round", note: "its eyes" },
1549
+ mouth: { kind: "enum", values: ["smile", "fangs", "beak", "none"], default: "smile", note: "its mouth" },
1550
+ extra: { kind: "enum", values: ["none", "horns", "ears", "antennae", "wings", "spikes", "shell", "hat", "tail"], default: "none", note: "one extra part" },
1551
+ feet: { kind: "enum", values: ["none", "stubs", "legs"], default: "stubs", note: "its feet; flyers have none" },
1552
+ role: { kind: "enum", values: ["hero", "enemy"], default: "hero", note: "hero takes the hero colour, enemy the danger colour" }
1553
+ },
1554
+ render: (o, dna, p, seed) => {
1555
+ const S = tileSize(dna);
1556
+ const frames = POSES.map((pose) => creatureFrame(o, dna, p, pose, S, seed));
1557
+ const out = new Raster(S * frames.length, S);
1558
+ frames.forEach((f, i) => {
1559
+ out.blit(f, i * S, 0);
1560
+ });
1561
+ return { raster: out, frame: { w: S, h: S }, clips: { idle: [0, 1], run: [2, 3, 4, 5], jump: [6], fall: [7], hurt: [8], attack: [9], death: [10] }, fps: 8 };
1562
+ }
1563
+ });
1564
+
1565
+ // ../artgen/dist/draw-worker.js
1566
+ parentPort?.on("message", (m) => {
1567
+ let result;
1568
+ try {
1569
+ result = draw(m.recipe, m.options, m.dna, m.seed);
1570
+ } catch (error) {
1571
+ result = { ok: false, reason: `the piece could not be drawn: ${error.message}` };
1572
+ }
1573
+ parentPort?.postMessage({ id: m.id, result }, result.ok ? [result.bytes.buffer] : []);
1574
+ });