@nayan-ui/games 1.20.0 → 1.21.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 (552) hide show
  1. package/lib/module/games/arrows/Arrows.js +1 -1
  2. package/lib/module/games/arrows/ArrowsScene.js +1 -1
  3. package/lib/module/games/balloon-blaster/BalloonBlaster.js +1 -1
  4. package/lib/module/games/balloon-blaster/BalloonBlasterScene.js +1 -1
  5. package/lib/module/games/bike-racing/BikeMeshes.js +1 -1
  6. package/lib/module/games/bike-racing/BikeRacing.js +1 -1
  7. package/lib/module/games/bike-racing/BikeRacingConstants.js +1 -1
  8. package/lib/module/games/bike-racing/BikeRacingScene.js +1 -1
  9. package/lib/module/games/block-blast/BlockBlast.js +1 -1
  10. package/lib/module/games/block-blast/BlockBlastScene.js +1 -1
  11. package/lib/module/games/block-breaker/BlockBreaker.js +1 -1
  12. package/lib/module/games/block-breaker/BlockBreakerScene.js +1 -1
  13. package/lib/module/games/bluk/Bluk.js +1 -1
  14. package/lib/module/games/bluk/BlukScene.js +1 -1
  15. package/lib/module/games/bubble-shooter/BubbleShooter.js +1 -1
  16. package/lib/module/games/bubble-shooter/BubbleShooterScene.js +1 -1
  17. package/lib/module/games/candy-crush/CandyCrush.js +1 -1
  18. package/lib/module/games/candy-crush/CandyCrushScene.js +1 -1
  19. package/lib/module/games/car-racing/CarMeshes.js +1 -1
  20. package/lib/module/games/car-racing/CarRacing.js +1 -1
  21. package/lib/module/games/car-racing/CarRacingScene.js +1 -1
  22. package/lib/module/games/chameleon-run/ChameleonRun.js +1 -1
  23. package/lib/module/games/chameleon-run/ChameleonRunBackdrop.js +1 -1
  24. package/lib/module/games/chameleon-run/ChameleonRunMeshes.js +1 -1
  25. package/lib/module/games/checkers/Checkers.js +1 -1
  26. package/lib/module/games/checkers/CheckersScene.js +1 -1
  27. package/lib/module/games/color-switch/ColorSwitch.js +1 -1
  28. package/lib/module/games/color-switch/ColorSwitchScene.js +1 -1
  29. package/lib/module/games/colors-sort/ColorsSort.js +1 -1
  30. package/lib/module/games/colors-sort/ColorsSortScene.js +1 -1
  31. package/lib/module/games/connect-em-all/ConnectEmAll.js +1 -1
  32. package/lib/module/games/connect-em-all/ConnectEmAllScene.js +1 -1
  33. package/lib/module/games/crossy-road/CrossyRoad.js +1 -1
  34. package/lib/module/games/crossy-road/CrossyRoadMeshes.js +1 -1
  35. package/lib/module/games/crossy-road/CrossyRoadPerson.js +1 -1
  36. package/lib/module/games/dino-jump/DinoJump.js +1 -1
  37. package/lib/module/games/dino-jump/DinoJumpScene.js +1 -1
  38. package/lib/module/games/dots-and-boxes/DotsAndBoxes.js +1 -1
  39. package/lib/module/games/dots-and-boxes/DotsAndBoxesScene.js +1 -1
  40. package/lib/module/games/falling-sticks/FallingSticks.js +1 -1
  41. package/lib/module/games/falling-sticks/FallingSticksScene.js +1 -1
  42. package/lib/module/games/find-different-number/FindDifferentNumber.js +1 -1
  43. package/lib/module/games/find-different-number/FindDifferentNumberScene.js +1 -1
  44. package/lib/module/games/flappy-bird/FlappyBird.js +1 -1
  45. package/lib/module/games/flappy-bird/FlappyBirdScene.js +1 -1
  46. package/lib/module/games/fruit-merger/FruitMerger.js +1 -1
  47. package/lib/module/games/fruit-merger/FruitMergerScene.js +1 -1
  48. package/lib/module/games/fruit-ninja/FruitNinja.js +1 -1
  49. package/lib/module/games/fruit-ninja/FruitNinjaScene.js +1 -1
  50. package/lib/module/games/fruit-ninja/FruitNinjaWorld.js +1 -1
  51. package/lib/module/games/game-2048/Game2048.js +1 -1
  52. package/lib/module/games/game-2048/Game2048Scene.js +1 -1
  53. package/lib/module/games/knife-hit/KnifeHit.js +1 -1
  54. package/lib/module/games/knife-hit/KnifeHitScene.js +1 -1
  55. package/lib/module/games/ludo-king/LudoKing.js +1 -1
  56. package/lib/module/games/ludo-king/LudoKingScene.js +1 -1
  57. package/lib/module/games/maze-runner/MazeRunner.js +1 -1
  58. package/lib/module/games/maze-runner/MazeRunnerScene.js +1 -1
  59. package/lib/module/games/memory-match/MemoryMatch.js +1 -1
  60. package/lib/module/games/memory-match/MemoryMatchScene.js +1 -1
  61. package/lib/module/games/mine-sweeper/MineSweeper.js +1 -1
  62. package/lib/module/games/mine-sweeper/MineSweeperScene.js +1 -1
  63. package/lib/module/games/mob-control/MobControl.js +1 -1
  64. package/lib/module/games/mob-control/MobControlGame.js +1 -1
  65. package/lib/module/games/mob-control/MobControlMeshes.js +1 -1
  66. package/lib/module/games/mob-control/MobControlRenderer.js +1 -1
  67. package/lib/module/games/mob-control/MobControlRules.js +1 -1
  68. package/lib/module/games/mob-control/MobControlScene.js +1 -1
  69. package/lib/module/games/nuts-and-bolts/NutsAndBolts.js +1 -1
  70. package/lib/module/games/nuts-and-bolts/NutsAndBoltsScene.js +1 -1
  71. package/lib/module/games/pac-man/PacMan.js +1 -1
  72. package/lib/module/games/pac-man/PacManGame.js +1 -1
  73. package/lib/module/games/pac-man/PacManScene.js +1 -1
  74. package/lib/module/games/paper-io/PaperIo.js +1 -1
  75. package/lib/module/games/paper-io/PaperIoMeshes.js +1 -1
  76. package/lib/module/games/paper-io/PaperIoScene.js +1 -1
  77. package/lib/module/games/penguin-run/PenguinMeshes.js +1 -1
  78. package/lib/module/games/penguin-run/PenguinRun.js +1 -1
  79. package/lib/module/games/penguin-run/PenguinRunScene.js +1 -1
  80. package/lib/module/games/perfect-circle/PerfectCircle.js +1 -1
  81. package/lib/module/games/perfect-circle/PerfectCircleScene.js +1 -1
  82. package/lib/module/games/pipe-connect/PipeConnect.js +1 -1
  83. package/lib/module/games/pipe-connect/PipeConnectScene.js +1 -1
  84. package/lib/module/games/play-with-tua/PlayWithTua.js +1 -1
  85. package/lib/module/games/popit-fidget/PopitFidget.js +1 -1
  86. package/lib/module/games/popit-fidget/PopitFidgetScene.js +1 -1
  87. package/lib/module/games/reversi/Reversi.js +1 -1
  88. package/lib/module/games/reversi/ReversiScene.js +1 -1
  89. package/lib/module/games/search-grid/SearchGrid.js +1 -1
  90. package/lib/module/games/search-grid/SearchGridScene.js +1 -1
  91. package/lib/module/games/shared/BackdropCard.js +1 -1
  92. package/lib/module/games/shared/EngineBackdrop.js +1 -1
  93. package/lib/module/games/shared/EngineBlasts.js +1 -1
  94. package/lib/module/games/shared/EngineBlocks.js +1 -1
  95. package/lib/module/games/shared/EngineDice.js +1 -1
  96. package/lib/module/games/shared/EngineFruits.js +1 -1
  97. package/lib/module/games/shared/EngineGameLoader.js +1 -1
  98. package/lib/module/games/shared/EngineGameScreen.js +1 -1
  99. package/lib/module/games/shared/EngineGlyphs.js +1 -1
  100. package/lib/module/games/shared/EngineHud.js +1 -1
  101. package/lib/module/games/shared/EngineMeadow.js +1 -1
  102. package/lib/module/games/shared/EngineTouchSurface.js +1 -1
  103. package/lib/module/games/shared/GameActivity.js +1 -1
  104. package/lib/module/games/shared/GameLoading.js +1 -1
  105. package/lib/module/games/shared/GameLoadingTransition.js +1 -1
  106. package/lib/module/games/sliding-numbers/SlidingNumbers.js +1 -1
  107. package/lib/module/games/sliding-numbers/SlidingNumbersScene.js +1 -1
  108. package/lib/module/games/snake-3d/Snake3D.js +1 -1
  109. package/lib/module/games/snake-3d/Snake3DScene.js +1 -1
  110. package/lib/module/games/snakes-and-ladders/SnakesAndLadders.js +1 -1
  111. package/lib/module/games/snakes-and-ladders/SnakesAndLaddersScene.js +1 -1
  112. package/lib/module/games/space-fighter/SpaceFighter.js +1 -1
  113. package/lib/module/games/space-fighter/SpaceFighterScene.js +1 -1
  114. package/lib/module/games/spider-solitaire/SpiderSolitaire.js +1 -1
  115. package/lib/module/games/spider-solitaire/SpiderSolitaireScene.js +1 -1
  116. package/lib/module/games/stack-tower/StackTower.js +1 -1
  117. package/lib/module/games/stack-tower/StackTowerScene.js +1 -1
  118. package/lib/module/games/sudoku/Sudoku.js +1 -1
  119. package/lib/module/games/sudoku/SudokuScene.js +1 -1
  120. package/lib/module/games/tangram/Tangram.js +1 -1
  121. package/lib/module/games/tangram/TangramScene.js +1 -1
  122. package/lib/module/games/tank-1990/Tank1990.js +1 -1
  123. package/lib/module/games/tank-1990/Tank1990Scene.js +1 -1
  124. package/lib/module/games/tic-tac-toe/TicTacToe.js +1 -1
  125. package/lib/module/games/tic-tac-toe/TicTacToeScene.js +1 -1
  126. package/lib/module/games/tile-home/TileHome.js +1 -1
  127. package/lib/module/games/tile-home/TileHomeScene.js +1 -1
  128. package/lib/module/games/treasure-hunt/TreasureHunt.js +1 -1
  129. package/lib/module/games/treasure-hunt/TreasureHuntConstants.js +1 -1
  130. package/lib/module/games/treasure-hunt/TreasureHuntModel.js +1 -1
  131. package/lib/module/games/treasure-hunt/TreasureHuntScene.js +1 -1
  132. package/lib/module/games/whack-a-mole/WhackAMole.js +1 -1
  133. package/lib/module/games/whack-a-mole/WhackAMoleScene.js +1 -1
  134. package/lib/module/helpers/GameSettingsModal.js +1 -1
  135. package/lib/module/helpers/GameTheme.js +1 -1
  136. package/package.json +1 -2
  137. package/src/assets/fonts/Inter-SemiBold.ttf +0 -0
  138. package/src/assets/models/explorer/explorer.glb +0 -0
  139. package/src/assets/models/explorer/params.json +0 -51
  140. package/src/assets/models/explorer/source.json +0 -222
  141. package/src/assets/models/play-with-tua/play-with-tua.glb +0 -0
  142. package/src/assets/models/play-with-tua/sources.json +0 -141
  143. package/src/assets/sfx/balloon_pop.wav +0 -0
  144. package/src/assets/sfx/blocked.wav +0 -0
  145. package/src/assets/sfx/boing.wav +0 -0
  146. package/src/assets/sfx/bonus.wav +0 -0
  147. package/src/assets/sfx/boom.wav +0 -0
  148. package/src/assets/sfx/bump.wav +0 -0
  149. package/src/assets/sfx/cannon.wav +0 -0
  150. package/src/assets/sfx/capture.wav +0 -0
  151. package/src/assets/sfx/card_flip.wav +0 -0
  152. package/src/assets/sfx/card_place.wav +0 -0
  153. package/src/assets/sfx/catch.wav +0 -0
  154. package/src/assets/sfx/chime.wav +0 -0
  155. package/src/assets/sfx/chomp.wav +0 -0
  156. package/src/assets/sfx/chomp_alt.wav +0 -0
  157. package/src/assets/sfx/clack.wav +0 -0
  158. package/src/assets/sfx/clang.wav +0 -0
  159. package/src/assets/sfx/clash.wav +0 -0
  160. package/src/assets/sfx/click.wav +0 -0
  161. package/src/assets/sfx/coin.wav +0 -0
  162. package/src/assets/sfx/combo.wav +0 -0
  163. package/src/assets/sfx/crash.wav +0 -0
  164. package/src/assets/sfx/crunch.wav +0 -0
  165. package/src/assets/sfx/dance.wav +0 -0
  166. package/src/assets/sfx/deselect.wav +0 -0
  167. package/src/assets/sfx/dice_roll.wav +0 -0
  168. package/src/assets/sfx/die.wav +0 -0
  169. package/src/assets/sfx/draw.wav +0 -0
  170. package/src/assets/sfx/drop.wav +0 -0
  171. package/src/assets/sfx/eat.wav +0 -0
  172. package/src/assets/sfx/engine.wav +0 -0
  173. package/src/assets/sfx/error.wav +0 -0
  174. package/src/assets/sfx/flag.wav +0 -0
  175. package/src/assets/sfx/flap.wav +0 -0
  176. package/src/assets/sfx/flip_disc.wav +0 -0
  177. package/src/assets/sfx/footstep_run.wav +0 -0
  178. package/src/assets/sfx/footstep_walk.wav +0 -0
  179. package/src/assets/sfx/game_over.wav +0 -0
  180. package/src/assets/sfx/gate.wav +0 -0
  181. package/src/assets/sfx/hit.wav +0 -0
  182. package/src/assets/sfx/hop.wav +0 -0
  183. package/src/assets/sfx/hurt.wav +0 -0
  184. package/src/assets/sfx/invalid.wav +0 -0
  185. package/src/assets/sfx/jump.wav +0 -0
  186. package/src/assets/sfx/ladder.wav +0 -0
  187. package/src/assets/sfx/land.wav +0 -0
  188. package/src/assets/sfx/laugh.wav +0 -0
  189. package/src/assets/sfx/lose.wav +0 -0
  190. package/src/assets/sfx/merge.wav +0 -0
  191. package/src/assets/sfx/miss.wav +0 -0
  192. package/src/assets/sfx/nitro.wav +0 -0
  193. package/src/assets/sfx/pew.wav +0 -0
  194. package/src/assets/sfx/place.wav +0 -0
  195. package/src/assets/sfx/pling.wav +0 -0
  196. package/src/assets/sfx/point.wav +0 -0
  197. package/src/assets/sfx/pop.wav +0 -0
  198. package/src/assets/sfx/pop_soft.wav +0 -0
  199. package/src/assets/sfx/power_up.wav +0 -0
  200. package/src/assets/sfx/reveal.wav +0 -0
  201. package/src/assets/sfx/robot.wav +0 -0
  202. package/src/assets/sfx/rotate.wav +0 -0
  203. package/src/assets/sfx/run_steps.wav +0 -0
  204. package/src/assets/sfx/select.wav +0 -0
  205. package/src/assets/sfx/shuffle.wav +0 -0
  206. package/src/assets/sfx/six.wav +0 -0
  207. package/src/assets/sfx/slice.wav +0 -0
  208. package/src/assets/sfx/slide.wav +0 -0
  209. package/src/assets/sfx/snake.wav +0 -0
  210. package/src/assets/sfx/snap.wav +0 -0
  211. package/src/assets/sfx/splash.wav +0 -0
  212. package/src/assets/sfx/star.wav +0 -0
  213. package/src/assets/sfx/start.wav +0 -0
  214. package/src/assets/sfx/swoosh.wav +0 -0
  215. package/src/assets/sfx/tap.wav +0 -0
  216. package/src/assets/sfx/thud.wav +0 -0
  217. package/src/assets/sfx/thunk.wav +0 -0
  218. package/src/assets/sfx/tick.wav +0 -0
  219. package/src/assets/sfx/time_up.wav +0 -0
  220. package/src/assets/sfx/tock.wav +0 -0
  221. package/src/assets/sfx/walk_steps.wav +0 -0
  222. package/src/assets/sfx/warning.wav +0 -0
  223. package/src/assets/sfx/whack.wav +0 -0
  224. package/src/assets/sfx/whoosh.wav +0 -0
  225. package/src/assets/sfx/win.wav +0 -0
  226. package/src/assets/sfx/zap.wav +0 -0
  227. package/src/assets/textures/ad_bolt.png +0 -0
  228. package/src/assets/textures/ad_bubbles.png +0 -0
  229. package/src/assets/textures/ad_chevrons.png +0 -0
  230. package/src/assets/textures/asphalt.png +0 -0
  231. package/src/assets/textures/bark.jpg +0 -0
  232. package/src/assets/textures/explorer-atlas.png +0 -0
  233. package/src/assets/textures/facade.png +0 -0
  234. package/src/assets/textures/grass.png +0 -0
  235. package/src/assets/textures/leaves.png +0 -0
  236. package/src/assets/textures/limestone.jpg +0 -0
  237. package/src/assets/textures/meadow.jpg +0 -0
  238. package/src/assets/textures/nature-sources.json +0 -87
  239. package/src/assets/textures/pine.png +0 -0
  240. package/src/assets/textures/river.jpg +0 -0
  241. package/src/assets/textures/soft_glow.png +0 -0
  242. package/src/games/arrows/Arrows.tsx +0 -69
  243. package/src/games/arrows/ArrowsConstants.ts +0 -107
  244. package/src/games/arrows/ArrowsGame.ts +0 -735
  245. package/src/games/arrows/ArrowsScene.ts +0 -395
  246. package/src/games/balloon-blaster/BalloonBlaster.tsx +0 -75
  247. package/src/games/balloon-blaster/BalloonBlasterConstants.ts +0 -79
  248. package/src/games/balloon-blaster/BalloonBlasterGame.ts +0 -287
  249. package/src/games/balloon-blaster/BalloonBlasterPhysics.ts +0 -95
  250. package/src/games/balloon-blaster/BalloonBlasterScene.ts +0 -225
  251. package/src/games/bike-racing/BikeMeshes.ts +0 -273
  252. package/src/games/bike-racing/BikeRacing.tsx +0 -211
  253. package/src/games/bike-racing/BikeRacingConstants.ts +0 -103
  254. package/src/games/bike-racing/BikeRacingGame.ts +0 -557
  255. package/src/games/bike-racing/BikeRacingScene.ts +0 -119
  256. package/src/games/block-blast/BlockBlast.tsx +0 -73
  257. package/src/games/block-blast/BlockBlastConstants.ts +0 -179
  258. package/src/games/block-blast/BlockBlastGame.ts +0 -471
  259. package/src/games/block-blast/BlockBlastScene.ts +0 -156
  260. package/src/games/block-breaker/BlockBreaker.tsx +0 -79
  261. package/src/games/block-breaker/BlockBreakerConstants.ts +0 -139
  262. package/src/games/block-breaker/BlockBreakerGame.ts +0 -459
  263. package/src/games/block-breaker/BlockBreakerScene.ts +0 -257
  264. package/src/games/bluk/Bluk.tsx +0 -82
  265. package/src/games/bluk/BlukConstants.ts +0 -121
  266. package/src/games/bluk/BlukGame.ts +0 -323
  267. package/src/games/bluk/BlukRules.ts +0 -154
  268. package/src/games/bluk/BlukScene.ts +0 -514
  269. package/src/games/bubble-shooter/BubbleShooter.tsx +0 -76
  270. package/src/games/bubble-shooter/BubbleShooterConstants.ts +0 -103
  271. package/src/games/bubble-shooter/BubbleShooterGame.ts +0 -459
  272. package/src/games/bubble-shooter/BubbleShooterScene.ts +0 -158
  273. package/src/games/candy-crush/CandyCrush.tsx +0 -77
  274. package/src/games/candy-crush/CandyCrushConstants.ts +0 -94
  275. package/src/games/candy-crush/CandyCrushGame.ts +0 -477
  276. package/src/games/candy-crush/CandyCrushScene.ts +0 -209
  277. package/src/games/car-racing/CarMeshes.ts +0 -440
  278. package/src/games/car-racing/CarRacing.tsx +0 -211
  279. package/src/games/car-racing/CarRacingConstants.ts +0 -167
  280. package/src/games/car-racing/CarRacingFacade.ts +0 -40
  281. package/src/games/car-racing/CarRacingGame.ts +0 -539
  282. package/src/games/car-racing/CarRacingScene.ts +0 -1026
  283. package/src/games/car-racing/CarRacingScenery.ts +0 -265
  284. package/src/games/chameleon-run/ChameleonRun.tsx +0 -96
  285. package/src/games/chameleon-run/ChameleonRunBackdrop.ts +0 -186
  286. package/src/games/chameleon-run/ChameleonRunConstants.ts +0 -47
  287. package/src/games/chameleon-run/ChameleonRunGame.ts +0 -309
  288. package/src/games/chameleon-run/ChameleonRunMeshes.ts +0 -305
  289. package/src/games/chameleon-run/ChameleonRunRules.ts +0 -252
  290. package/src/games/chameleon-run/ChameleonRunScene.ts +0 -310
  291. package/src/games/checkers/Checkers.tsx +0 -83
  292. package/src/games/checkers/CheckersAI.ts +0 -255
  293. package/src/games/checkers/CheckersConstants.ts +0 -68
  294. package/src/games/checkers/CheckersGame.ts +0 -322
  295. package/src/games/checkers/CheckersRules.ts +0 -167
  296. package/src/games/checkers/CheckersScene.ts +0 -308
  297. package/src/games/color-switch/ColorSwitch.tsx +0 -75
  298. package/src/games/color-switch/ColorSwitchConstants.ts +0 -61
  299. package/src/games/color-switch/ColorSwitchGame.ts +0 -329
  300. package/src/games/color-switch/ColorSwitchScene.ts +0 -220
  301. package/src/games/colors-sort/ColorsSort.tsx +0 -82
  302. package/src/games/colors-sort/ColorsSortConstants.ts +0 -119
  303. package/src/games/colors-sort/ColorsSortGame.ts +0 -246
  304. package/src/games/colors-sort/ColorsSortScene.ts +0 -315
  305. package/src/games/connect-em-all/ConnectEmAll.tsx +0 -70
  306. package/src/games/connect-em-all/ConnectEmAllConstants.ts +0 -77
  307. package/src/games/connect-em-all/ConnectEmAllGame.ts +0 -401
  308. package/src/games/connect-em-all/ConnectEmAllScene.ts +0 -235
  309. package/src/games/crossy-road/CrossyRoad.tsx +0 -74
  310. package/src/games/crossy-road/CrossyRoadCamera.ts +0 -59
  311. package/src/games/crossy-road/CrossyRoadConstants.ts +0 -132
  312. package/src/games/crossy-road/CrossyRoadGame.ts +0 -293
  313. package/src/games/crossy-road/CrossyRoadMeshes.ts +0 -195
  314. package/src/games/crossy-road/CrossyRoadPerson.ts +0 -198
  315. package/src/games/crossy-road/CrossyRoadRules.ts +0 -99
  316. package/src/games/crossy-road/CrossyRoadScene.ts +0 -355
  317. package/src/games/dino-jump/DinoJump.tsx +0 -77
  318. package/src/games/dino-jump/DinoJumpConstants.ts +0 -80
  319. package/src/games/dino-jump/DinoJumpGame.ts +0 -344
  320. package/src/games/dino-jump/DinoJumpScene.ts +0 -686
  321. package/src/games/dots-and-boxes/DotsAndBoxes.tsx +0 -83
  322. package/src/games/dots-and-boxes/DotsAndBoxesConstants.ts +0 -77
  323. package/src/games/dots-and-boxes/DotsAndBoxesGame.ts +0 -271
  324. package/src/games/dots-and-boxes/DotsAndBoxesScene.ts +0 -249
  325. package/src/games/falling-sticks/FallingSticks.tsx +0 -72
  326. package/src/games/falling-sticks/FallingSticksConstants.ts +0 -62
  327. package/src/games/falling-sticks/FallingSticksGame.ts +0 -220
  328. package/src/games/falling-sticks/FallingSticksRules.ts +0 -145
  329. package/src/games/falling-sticks/FallingSticksScene.ts +0 -245
  330. package/src/games/find-different-number/FindDifferentNumber.tsx +0 -74
  331. package/src/games/find-different-number/FindDifferentNumberConstants.ts +0 -74
  332. package/src/games/find-different-number/FindDifferentNumberGame.ts +0 -174
  333. package/src/games/find-different-number/FindDifferentNumberRules.ts +0 -43
  334. package/src/games/find-different-number/FindDifferentNumberScene.ts +0 -193
  335. package/src/games/flappy-bird/FlappyBird.tsx +0 -73
  336. package/src/games/flappy-bird/FlappyBirdConstants.ts +0 -95
  337. package/src/games/flappy-bird/FlappyBirdGame.ts +0 -375
  338. package/src/games/flappy-bird/FlappyBirdScene.ts +0 -630
  339. package/src/games/fruit-merger/FruitMerger.tsx +0 -73
  340. package/src/games/fruit-merger/FruitMergerConstants.ts +0 -102
  341. package/src/games/fruit-merger/FruitMergerGame.ts +0 -285
  342. package/src/games/fruit-merger/FruitMergerRules.ts +0 -286
  343. package/src/games/fruit-merger/FruitMergerScene.ts +0 -498
  344. package/src/games/fruit-ninja/FruitNinja.tsx +0 -129
  345. package/src/games/fruit-ninja/FruitNinjaConstants.ts +0 -107
  346. package/src/games/fruit-ninja/FruitNinjaGame.ts +0 -391
  347. package/src/games/fruit-ninja/FruitNinjaScene.ts +0 -319
  348. package/src/games/fruit-ninja/FruitNinjaWorld.ts +0 -17
  349. package/src/games/game-2048/Game2048.tsx +0 -84
  350. package/src/games/game-2048/Game2048Constants.ts +0 -68
  351. package/src/games/game-2048/Game2048Game.ts +0 -181
  352. package/src/games/game-2048/Game2048Rules.ts +0 -101
  353. package/src/games/game-2048/Game2048Scene.ts +0 -206
  354. package/src/games/knife-hit/KnifeHit.tsx +0 -78
  355. package/src/games/knife-hit/KnifeHitConstants.ts +0 -89
  356. package/src/games/knife-hit/KnifeHitGame.ts +0 -264
  357. package/src/games/knife-hit/KnifeHitScene.ts +0 -360
  358. package/src/games/ludo-king/LudoKing.tsx +0 -86
  359. package/src/games/ludo-king/LudoKingConstants.ts +0 -212
  360. package/src/games/ludo-king/LudoKingGame.ts +0 -326
  361. package/src/games/ludo-king/LudoKingRules.ts +0 -143
  362. package/src/games/ludo-king/LudoKingScene.ts +0 -397
  363. package/src/games/maze-runner/MazeRunner.tsx +0 -88
  364. package/src/games/maze-runner/MazeRunnerConstants.ts +0 -65
  365. package/src/games/maze-runner/MazeRunnerGame.ts +0 -176
  366. package/src/games/maze-runner/MazeRunnerRules.ts +0 -161
  367. package/src/games/maze-runner/MazeRunnerScene.ts +0 -245
  368. package/src/games/memory-match/MemoryMatch.tsx +0 -77
  369. package/src/games/memory-match/MemoryMatchConstants.ts +0 -105
  370. package/src/games/memory-match/MemoryMatchGame.ts +0 -222
  371. package/src/games/memory-match/MemoryMatchRules.ts +0 -38
  372. package/src/games/memory-match/MemoryMatchScene.ts +0 -268
  373. package/src/games/mine-sweeper/MineSweeper.tsx +0 -77
  374. package/src/games/mine-sweeper/MineSweeperConstants.ts +0 -94
  375. package/src/games/mine-sweeper/MineSweeperGame.ts +0 -234
  376. package/src/games/mine-sweeper/MineSweeperRules.ts +0 -67
  377. package/src/games/mine-sweeper/MineSweeperScene.ts +0 -262
  378. package/src/games/mob-control/MobControl.tsx +0 -73
  379. package/src/games/mob-control/MobControlConstants.ts +0 -106
  380. package/src/games/mob-control/MobControlGame.ts +0 -176
  381. package/src/games/mob-control/MobControlMeshes.ts +0 -85
  382. package/src/games/mob-control/MobControlRenderer.ts +0 -108
  383. package/src/games/mob-control/MobControlRules.ts +0 -522
  384. package/src/games/mob-control/MobControlScene.ts +0 -399
  385. package/src/games/number-search/NumberSearch.tsx +0 -18
  386. package/src/games/number-search/NumberSearchNumbers.ts +0 -623
  387. package/src/games/nuts-and-bolts/NutsAndBolts.tsx +0 -85
  388. package/src/games/nuts-and-bolts/NutsAndBoltsConstants.ts +0 -75
  389. package/src/games/nuts-and-bolts/NutsAndBoltsGame.ts +0 -298
  390. package/src/games/nuts-and-bolts/NutsAndBoltsRules.ts +0 -474
  391. package/src/games/nuts-and-bolts/NutsAndBoltsScene.ts +0 -498
  392. package/src/games/pac-man/PacMan.tsx +0 -86
  393. package/src/games/pac-man/PacManConstants.ts +0 -169
  394. package/src/games/pac-man/PacManGame.ts +0 -406
  395. package/src/games/pac-man/PacManRules.ts +0 -255
  396. package/src/games/pac-man/PacManScene.ts +0 -387
  397. package/src/games/paper-io/PaperIo.tsx +0 -91
  398. package/src/games/paper-io/PaperIoConstants.ts +0 -86
  399. package/src/games/paper-io/PaperIoGame.ts +0 -193
  400. package/src/games/paper-io/PaperIoMeshes.ts +0 -233
  401. package/src/games/paper-io/PaperIoRules.ts +0 -315
  402. package/src/games/paper-io/PaperIoScene.ts +0 -310
  403. package/src/games/penguin-run/PenguinMeshes.ts +0 -269
  404. package/src/games/penguin-run/PenguinModel.ts +0 -712
  405. package/src/games/penguin-run/PenguinRun.tsx +0 -77
  406. package/src/games/penguin-run/PenguinRunConstants.ts +0 -69
  407. package/src/games/penguin-run/PenguinRunGame.ts +0 -406
  408. package/src/games/penguin-run/PenguinRunScene.ts +0 -949
  409. package/src/games/perfect-circle/PerfectCircle.tsx +0 -74
  410. package/src/games/perfect-circle/PerfectCircleConstants.ts +0 -52
  411. package/src/games/perfect-circle/PerfectCircleGame.ts +0 -153
  412. package/src/games/perfect-circle/PerfectCircleRules.ts +0 -111
  413. package/src/games/perfect-circle/PerfectCircleScene.ts +0 -176
  414. package/src/games/pipe-connect/PipeConnect.tsx +0 -69
  415. package/src/games/pipe-connect/PipeConnectConstants.ts +0 -101
  416. package/src/games/pipe-connect/PipeConnectGame.ts +0 -179
  417. package/src/games/pipe-connect/PipeConnectRules.ts +0 -326
  418. package/src/games/pipe-connect/PipeConnectScene.ts +0 -271
  419. package/src/games/play-with-tua/PlayWithTua.tsx +0 -123
  420. package/src/games/play-with-tua/PlayWithTuaConstants.ts +0 -70
  421. package/src/games/play-with-tua/PlayWithTuaGame.ts +0 -167
  422. package/src/games/play-with-tua/PlayWithTuaModel.ts +0 -42
  423. package/src/games/play-with-tua/PlayWithTuaScene.ts +0 -36
  424. package/src/games/popit-fidget/PopitFidget.tsx +0 -72
  425. package/src/games/popit-fidget/PopitFidgetConstants.ts +0 -71
  426. package/src/games/popit-fidget/PopitFidgetGame.ts +0 -148
  427. package/src/games/popit-fidget/PopitFidgetScene.ts +0 -242
  428. package/src/games/reversi/Reversi.tsx +0 -94
  429. package/src/games/reversi/ReversiConstants.ts +0 -67
  430. package/src/games/reversi/ReversiGame.ts +0 -266
  431. package/src/games/reversi/ReversiRules.ts +0 -176
  432. package/src/games/reversi/ReversiScene.ts +0 -240
  433. package/src/games/search-grid/SearchGrid.tsx +0 -92
  434. package/src/games/search-grid/SearchGridConstants.ts +0 -178
  435. package/src/games/search-grid/SearchGridGame.ts +0 -209
  436. package/src/games/search-grid/SearchGridScene.ts +0 -301
  437. package/src/games/shared/BackdropCard.tsx +0 -54
  438. package/src/games/shared/EngineBackdrop.ts +0 -300
  439. package/src/games/shared/EngineBlasts.ts +0 -136
  440. package/src/games/shared/EngineBlocks.ts +0 -91
  441. package/src/games/shared/EngineControlText.ts +0 -17
  442. package/src/games/shared/EngineDice.ts +0 -250
  443. package/src/games/shared/EngineFootprint.ts +0 -35
  444. package/src/games/shared/EngineFruits.ts +0 -1435
  445. package/src/games/shared/EngineGameLoader.tsx +0 -88
  446. package/src/games/shared/EngineGameScreen.tsx +0 -325
  447. package/src/games/shared/EngineGameWidth.ts +0 -3
  448. package/src/games/shared/EngineGameWidth.web.ts +0 -3
  449. package/src/games/shared/EngineGlyphs.ts +0 -178
  450. package/src/games/shared/EngineHud.ts +0 -815
  451. package/src/games/shared/EngineLoading.ts +0 -477
  452. package/src/games/shared/EngineMeadow.ts +0 -725
  453. package/src/games/shared/EngineMeshCache.ts +0 -15
  454. package/src/games/shared/EngineMeshes.ts +0 -10
  455. package/src/games/shared/EngineRacingChase.ts +0 -21
  456. package/src/games/shared/EngineRacingHandling.ts +0 -48
  457. package/src/games/shared/EngineReadyContext.ts +0 -4
  458. package/src/games/shared/EngineTilt.ts +0 -44
  459. package/src/games/shared/EngineTouchSurface.tsx +0 -103
  460. package/src/games/shared/EngineUtils.ts +0 -52
  461. package/src/games/shared/GameActivity.ts +0 -13
  462. package/src/games/shared/GameLoading.tsx +0 -202
  463. package/src/games/shared/GameLoadingTransition.tsx +0 -61
  464. package/src/games/shared/ProceduralCacheVersion.ts +0 -2
  465. package/src/games/shared/useEngineGame.ts +0 -240
  466. package/src/games/shared/useGameResource.ts +0 -21
  467. package/src/games/shared/useLiveState.ts +0 -58
  468. package/src/games/sliding-numbers/SlidingNumbers.tsx +0 -71
  469. package/src/games/sliding-numbers/SlidingNumbersConstants.ts +0 -65
  470. package/src/games/sliding-numbers/SlidingNumbersGame.ts +0 -192
  471. package/src/games/sliding-numbers/SlidingNumbersRules.ts +0 -79
  472. package/src/games/sliding-numbers/SlidingNumbersScene.ts +0 -193
  473. package/src/games/snake-3d/Snake3D.tsx +0 -76
  474. package/src/games/snake-3d/Snake3DConstants.ts +0 -61
  475. package/src/games/snake-3d/Snake3DGame.ts +0 -192
  476. package/src/games/snake-3d/Snake3DMotion.ts +0 -22
  477. package/src/games/snake-3d/Snake3DRules.ts +0 -116
  478. package/src/games/snake-3d/Snake3DScene.ts +0 -322
  479. package/src/games/snakes-and-ladders/SnakesAndLadders.tsx +0 -87
  480. package/src/games/snakes-and-ladders/SnakesAndLaddersConstants.ts +0 -136
  481. package/src/games/snakes-and-ladders/SnakesAndLaddersGame.ts +0 -310
  482. package/src/games/snakes-and-ladders/SnakesAndLaddersScene.ts +0 -515
  483. package/src/games/space-fighter/SpaceFighter.tsx +0 -74
  484. package/src/games/space-fighter/SpaceFighterConstants.ts +0 -86
  485. package/src/games/space-fighter/SpaceFighterGame.ts +0 -292
  486. package/src/games/space-fighter/SpaceFighterScene.ts +0 -550
  487. package/src/games/spider-solitaire/SpiderSolitaire.tsx +0 -80
  488. package/src/games/spider-solitaire/SpiderSolitaireConstants.ts +0 -107
  489. package/src/games/spider-solitaire/SpiderSolitaireGame.ts +0 -387
  490. package/src/games/spider-solitaire/SpiderSolitaireRules.ts +0 -123
  491. package/src/games/spider-solitaire/SpiderSolitaireScene.ts +0 -352
  492. package/src/games/stack-tower/StackTower.tsx +0 -76
  493. package/src/games/stack-tower/StackTowerConstants.ts +0 -74
  494. package/src/games/stack-tower/StackTowerGame.ts +0 -236
  495. package/src/games/stack-tower/StackTowerScene.ts +0 -186
  496. package/src/games/sudoku/Sudoku.tsx +0 -73
  497. package/src/games/sudoku/SudokuConstants.ts +0 -127
  498. package/src/games/sudoku/SudokuGame.ts +0 -250
  499. package/src/games/sudoku/SudokuRules.ts +0 -125
  500. package/src/games/sudoku/SudokuScene.ts +0 -304
  501. package/src/games/tangram/Tangram.tsx +0 -79
  502. package/src/games/tangram/TangramConstants.ts +0 -64
  503. package/src/games/tangram/TangramGame.ts +0 -356
  504. package/src/games/tangram/TangramRules.ts +0 -409
  505. package/src/games/tangram/TangramScene.ts +0 -203
  506. package/src/games/tank-1990/Tank1990.tsx +0 -78
  507. package/src/games/tank-1990/Tank1990Constants.ts +0 -81
  508. package/src/games/tank-1990/Tank1990Game.ts +0 -331
  509. package/src/games/tank-1990/Tank1990Rules.ts +0 -390
  510. package/src/games/tank-1990/Tank1990Scene.ts +0 -434
  511. package/src/games/tic-tac-toe/TicTacToe.tsx +0 -98
  512. package/src/games/tic-tac-toe/TicTacToeConstants.ts +0 -69
  513. package/src/games/tic-tac-toe/TicTacToeGame.ts +0 -200
  514. package/src/games/tic-tac-toe/TicTacToeRules.ts +0 -103
  515. package/src/games/tic-tac-toe/TicTacToeScene.ts +0 -245
  516. package/src/games/tile-home/TileHome.tsx +0 -92
  517. package/src/games/tile-home/TileHomeConstants.ts +0 -139
  518. package/src/games/tile-home/TileHomeGame.ts +0 -435
  519. package/src/games/tile-home/TileHomeScene.ts +0 -154
  520. package/src/games/treasure-hunt/TreasureHunt.tsx +0 -206
  521. package/src/games/treasure-hunt/TreasureHuntConstants.ts +0 -266
  522. package/src/games/treasure-hunt/TreasureHuntControls.ts +0 -280
  523. package/src/games/treasure-hunt/TreasureHuntGame.ts +0 -402
  524. package/src/games/treasure-hunt/TreasureHuntMeshes.ts +0 -422
  525. package/src/games/treasure-hunt/TreasureHuntModel.ts +0 -506
  526. package/src/games/treasure-hunt/TreasureHuntRules.ts +0 -1210
  527. package/src/games/treasure-hunt/TreasureHuntScene.ts +0 -586
  528. package/src/games/whack-a-mole/WhackAMole.tsx +0 -79
  529. package/src/games/whack-a-mole/WhackAMoleConstants.ts +0 -94
  530. package/src/games/whack-a-mole/WhackAMoleGame.ts +0 -233
  531. package/src/games/whack-a-mole/WhackAMoleScene.ts +0 -349
  532. package/src/games/word-search/WordSearch.tsx +0 -18
  533. package/src/games/word-search/WordSearchWords.ts +0 -1642
  534. package/src/helpers/GamePatternData.ts +0 -120
  535. package/src/helpers/GameSettingsModal.tsx +0 -384
  536. package/src/helpers/GameTheme.tsx +0 -37
  537. package/src/helpers/IconPaths.ts +0 -6
  538. package/src/helpers/index.ts +0 -2
  539. package/src/index.tsx +0 -60
  540. package/src/services/GameAssetLoader.ts +0 -111
  541. package/src/services/GameAssets.ts +0 -149
  542. package/src/services/GameLoaders.ts +0 -93
  543. package/src/services/GamesConstants.ts +0 -193
  544. package/src/services/GamesMetadata.ts +0 -711
  545. package/src/services/GamesService.ts +0 -116
  546. package/src/services/HapticsService.ts +0 -48
  547. package/src/services/ScoringService.ts +0 -19
  548. package/src/services/SfxSources.ts +0 -81
  549. package/src/services/SoundsService.ts +0 -582
  550. package/src/services/ThemeService.ts +0 -281
  551. package/src/services/UtilsService.ts +0 -134
  552. package/src/services/index.ts +0 -6
@@ -1,515 +0,0 @@
1
- // Everything Snakes and Ladders draws. An orthographic camera leaning back from straight down over a
2
- // wooden board; the board lies in the world's XY plane (x right, y up the board, z up off it), centred
3
- // on the origin, one board unit (the playing area's width) to `layout.size` world units (view points).
4
- // The board, its cells, frame, snakes, ladders and the start pad are one static mesh; the cell numbers
5
- // are ten digit meshes shared by every cell (one instanced draw each); the pawns, the die and their
6
- // shadows are entities of their own. Every mesh is built once: mesh ids are app-wide and limited.
7
- import {
8
- type Camera,
9
- type Color,
10
- effects,
11
- type Entity,
12
- extrude,
13
- type GeometryPart,
14
- lathe,
15
- merge,
16
- type Model,
17
- Path,
18
- type Quat,
19
- quat,
20
- shapeGeometry,
21
- tube,
22
- type Vec3,
23
- type World
24
- } from '@nayan-ui/engine';
25
- import type { GameTheme } from '../../services/ThemeService';
26
- import { setBackdropTheme, spawnBackdrop } from '../shared/EngineBackdrop';
27
- import { dieMesh, dieRotation as sharedDieRotation, rollDie as rollSharedDie } from '../shared/EngineDice';
28
- import { flatGlyphMesh, GLYPH_ADVANCE, GLYPH_WIDTH } from '../shared/EngineGlyphs';
29
- import { noise } from '../shared/EngineMeadow';
30
- import { cacheGameAsset, createGameMesh as createShape } from '../shared/EngineMeshes';
31
- import { aimTilted, placeTiltedBackdrop, type TiltView } from '../shared/EngineTilt';
32
- import { toColor } from '../shared/EngineUtils';
33
- import {
34
- AI_COLOR,
35
- BOARD_SIZE,
36
- CELL_PALETTE,
37
- cellCenter,
38
- DIE_SIZE,
39
- DIE_Y,
40
- FINISH_CELL,
41
- LADDER_AT,
42
- type LadderData,
43
- LADDERS,
44
- type Layout,
45
- NUMBER_COLOR,
46
- PLAYER_COLOR,
47
- RIM,
48
- SNAKE_AT,
49
- type SnakeData,
50
- SNAKES,
51
- STAR_NUMBER_COLOR,
52
- START_CELL,
53
- START_X,
54
- START_Z,
55
- TILE_TOP,
56
- TILT,
57
- TOKEN_HEIGHT,
58
- WINNING_POSITION
59
- } from './SnakesAndLaddersConstants';
60
-
61
- // ── Helpers ───────────────────────────────────────────────────────────
62
-
63
- const meshes = new Map<string, Model>();
64
- const cached = (key: string, build: () => Model) => {
65
- let m = meshes.get(key);
66
- if (!m) {
67
- m = cacheGameAsset('snakes-and-ladders/SnakesAndLaddersScene:' + key, build);
68
- meshes.set(key, m);
69
- }
70
- return m;
71
- };
72
- type RGB = [number, number, number];
73
- const rgb = (css: string): RGB => {
74
- const [r, g, b] = toColor(css);
75
- return [r, g, b];
76
- };
77
- const mix = (a: RGB, b: RGB, t: number): RGB => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t];
78
- const shade = (c: RGB, k: number): RGB => [c[0] * k, c[1] * k, c[2] * k];
79
- const smooth = (a: number, b: number, x: number) => {
80
- const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
81
- return t * t * (3 - 2 * t);
82
- };
83
- const sphere = () => shapeGeometry('sphere');
84
- const cube = () => shapeGeometry('cube');
85
- /** Stands a lathe (built around +y) up off the board (+z). */
86
- const STAND_UP = quat.x(Math.PI / 2);
87
- type V2 = [number, number];
88
- const along = (a: V2, b: V2, t: number): V2 => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
89
-
90
- // ── Snakes ────────────────────────────────────────────────────────────
91
-
92
- const SNAKE_POINTS = 30;
93
- const snakeRadius = (t: number) => 0.0135 * (0.8 + 0.2 * smooth(0, 0.15, t)) * (1 - 0.85 * smooth(0.5, 1, t));
94
-
95
- /**
96
- * A snake's spine from its head (t = 0) to its tail tip (t = 1): an S-curve across the board, on the
97
- * cells (with `raised`, at the height of its round body, before the board flattens it onto them).
98
- */
99
- export function snakePath(s: SnakeData, raised = false): Vec3[] {
100
- const head = cellCenter(s.head);
101
- const tail = cellCenter(s.tail);
102
- const dx = tail[0] - head[0];
103
- const dy = tail[1] - head[1];
104
- const d = Math.hypot(dx, dy);
105
- const perp: V2 = [-dy / d, dx / d];
106
- const waves = Math.max(2, Math.round(d / 0.15));
107
- const amp = Math.min(0.042, d * 0.14);
108
- return Array.from({ length: SNAKE_POINTS }, (_, i) => {
109
- const t = i / (SNAKE_POINTS - 1);
110
- const [x, y] = along(head, tail, t);
111
- const w = amp * Math.sin(Math.PI * waves * t) * (1 - 0.6 * t);
112
- return [x + perp[0] * w, y + perp[1] * w, raised ? snakeRadius(t) * 0.8 : TILE_TOP] as Vec3;
113
- });
114
- }
115
-
116
- /** A snake's parts, heights measured from the cells' top (the board flattens them onto it). */
117
- function snakeParts(s: SnakeData): GeometryPart[] {
118
- const path = snakePath(s, true);
119
- const base = rgb(s.color);
120
- const accent = rgb(s.accent);
121
- const belly = rgb(s.belly);
122
- const length = Math.hypot(path[0]![0] - path[SNAKE_POINTS - 1]![0], path[0]![1] - path[SNAKE_POINTS - 1]![1]);
123
- const bands = Math.max(6, Math.round(length * 55));
124
- const body = tube(path, {
125
- radius: snakeRadius,
126
- sides: 12,
127
- smoothness: 4,
128
- color: ({ v, normal: n, position: p }) => {
129
- const band = 0.5 + 0.5 * Math.cos(Math.PI * 2 * bands * v);
130
- let c = mix(base, accent, smooth(0.62, 0.86, band));
131
- if (n[2] > 0.55 && band < 0.22) c = mix(c, belly, 0.55); // pale saddles along the back
132
- if (n[2] < -0.2) c = belly;
133
- return shade(c, 0.9 + 0.2 * noise(p[0] * 160, p[1] * 160));
134
- }
135
- });
136
-
137
- // The head: a flattened wedge past the neck, looking away from the body
138
- const [hx, hy] = cellCenter(s.head);
139
- const neck = path[2]!;
140
- const hd: V2 = [hx - neck[0], hy - neck[1]];
141
- const hl = Math.hypot(hd[0], hd[1]) || 1;
142
- hd[0] /= hl;
143
- hd[1] /= hl;
144
- const side: V2 = [-hd[1], hd[0]];
145
- const angle = Math.atan2(hd[1], hd[0]);
146
- const yaw = quat.z(angle);
147
- const at = (forward: number, across: number, z: number): Vec3 => [
148
- hx + hd[0] * forward + side[0] * across,
149
- hy + hd[1] * forward + side[1] * across,
150
- z
151
- ];
152
- const headColor = mix(base, accent, 0.25);
153
- const parts: GeometryPart[] = [
154
- { geometry: body },
155
- { geometry: sphere(), position: at(0.006, 0, 0.011), scale: [0.05, 0.038, 0.022], rotation: yaw, color: [...headColor, 1] },
156
- { geometry: sphere(), position: at(0.022, 0, 0.009), scale: [0.03, 0.027, 0.017], rotation: yaw, color: [...headColor, 1] }
157
- ];
158
- for (const k of [1, -1]) {
159
- parts.push(
160
- { geometry: sphere(), position: at(0.008, 0.012 * k, 0.019), scale: 0.012, color: [1, 1, 0.92, 1] },
161
- { geometry: sphere(), position: at(0.01, 0.0125 * k, 0.0245), scale: [0.004, 0.008, 0.004], rotation: yaw, color: [0.05, 0.05, 0.05, 1] },
162
- { geometry: sphere(), position: at(0.012, 0.011 * k, 0.026), scale: 0.0022, color: [1, 1, 1, 1] },
163
- { geometry: sphere(), position: at(0.033, 0.0055 * k, 0.016), scale: 0.0032, color: [0.08, 0.06, 0.05, 1] }
164
- );
165
- }
166
- // A forked tongue flicking out
167
- const red: RGB = [0.85, 0.08, 0.12];
168
- parts.push({ geometry: tube([at(0.034, 0, 0.007), at(0.05, 0, 0.007)], { radius: 0.0017, sides: 6, color: red }) });
169
- for (const k of [1, -1])
170
- parts.push({ geometry: tube([at(0.049, 0, 0.007), at(0.058, 0.0055 * k, 0.007)], { radius: 0.0014, sides: 6, color: red }) });
171
- return parts;
172
- }
173
-
174
- // ── Ladders ───────────────────────────────────────────────────────────
175
-
176
- const RAIL_GAP = 0.019; // from the ladder's middle to a rail
177
- const RAIL_Z = 0.005; // above the cells' top, before the board flattens the ladder onto it
178
-
179
- /** A ladder's parts, heights measured from the cells' top (the board flattens them onto it). */
180
- function ladderParts(l: LadderData): GeometryPart[] {
181
- const a = cellCenter(l.bottom);
182
- const b = cellCenter(l.top);
183
- const d = Math.hypot(b[0] - a[0], b[1] - a[1]);
184
- const u: V2 = [(b[0] - a[0]) / d, (b[1] - a[1]) / d];
185
- const p: V2 = [-u[1], u[0]];
186
- const wood = rgb(l.color);
187
- const light = rgb(l.highlight);
188
- const grain = ({ v, normal: n }: { v: number; normal: Vec3 }): Color => {
189
- const g = 0.5 + 0.5 * Math.sin(v * d * 260 + noise(v * d * 40, 3) * 5);
190
- return shade(mix(wood, light, g * 0.45 + Math.max(0, n[2]) * 0.3), 1);
191
- };
192
- const ext = 0.014;
193
- const parts: GeometryPart[] = [1, -1].map((k) => ({
194
- geometry: tube(
195
- [
196
- [a[0] - u[0] * ext + p[0] * RAIL_GAP * k, a[1] - u[1] * ext + p[1] * RAIL_GAP * k, RAIL_Z],
197
- [b[0] + u[0] * ext + p[0] * RAIL_GAP * k, b[1] + u[1] * ext + p[1] * RAIL_GAP * k, RAIL_Z]
198
- ],
199
- { radius: 0.0045, sides: 8, smoothness: Math.max(8, Math.round(d * 90)), color: grain }
200
- )
201
- }));
202
- const rungs = Math.max(3, Math.floor(d / 0.045));
203
- for (let r = 1; r <= rungs; r++) {
204
- const [x, y] = along(a, b, r / (rungs + 1));
205
- parts.push({
206
- geometry: tube(
207
- [
208
- [x - p[0] * RAIL_GAP, y - p[1] * RAIL_GAP, RAIL_Z + 0.0008],
209
- [x + p[0] * RAIL_GAP, y + p[1] * RAIL_GAP, RAIL_Z + 0.0008]
210
- ],
211
- { radius: 0.0032, sides: 8, color: mix(wood, light, 0.6) }
212
- )
213
- });
214
- }
215
- return parts;
216
- }
217
-
218
- /** The ladder's line, from its foot to its top, on the cells where a pawn climbs it. */
219
- export function ladderPath(l: LadderData): Vec3[] {
220
- const [ax, ay] = cellCenter(l.bottom);
221
- const [bx, by] = cellCenter(l.top);
222
- return [
223
- [ax, ay, TILE_TOP],
224
- [bx, by, TILE_TOP]
225
- ];
226
- }
227
-
228
- // ── The board ─────────────────────────────────────────────────────────
229
-
230
- const CELL = 1 / BOARD_SIZE;
231
-
232
- function cellColor(cell: number): RGB {
233
- const i = cell - 1;
234
- let c = rgb(CELL_PALETTE[(Math.floor(i / BOARD_SIZE) + (i % BOARD_SIZE)) % CELL_PALETTE.length]!);
235
- if (cell === 1) c = rgb(START_CELL);
236
- else if (cell === WINNING_POSITION) c = rgb(FINISH_CELL);
237
- return c;
238
- }
239
-
240
- /** How much of their height the snakes and ladders keep: pressed flat onto the cells, like a printed board. */
241
- const FLAT = 0.05;
242
- /** How thin the flat layers are (cells, star, start pad). */
243
- const SKIN = 0.0004;
244
- /**
245
- * The flat layers' heights above the cells' top, far enough apart that the depth test always knows
246
- * which is in front (closer, the numbers and the snakes flicker into each other where they overlap),
247
- * yet well under a pixel on screen: numbers, then the snakes and ladders over them, then pawn shadows.
248
- */
249
- const DIGITS_Z = TILE_TOP + 0.002;
250
- const ART_Z = TILE_TOP + 0.004;
251
- export const SHADOW_Z = TILE_TOP + 0.008;
252
- /** Pawns stand on top of the flat layers (their shadows included), not sunk into them. */
253
- const PAWN_LIFT = SHADOW_Z + 0.001 - TILE_TOP;
254
- const pawnAt = (l: Layout, p: Vec3) => toWorld(l, p[0], p[1], p[2] + PAWN_LIFT);
255
-
256
- /**
257
- * The board, all flat (only the pawns and the die stand up in 3D): a slim frame round the grout, the
258
- * hundred cells, the snakes and ladders pressed onto them, the star on the last cell and the start pad.
259
- */
260
- const boardMesh = () =>
261
- cached('snl-board', () => {
262
- const outer = 1 + RIM * 2;
263
- const frame = rgb('#5C4033');
264
- const flat = (z: number, scale: Vec3) => ({ position: [0, 0, z] as Vec3, scale });
265
- const parts: GeometryPart[] = [
266
- // The frame (the board's edge) and the grout showing between the cells, flush under them
267
- { geometry: cube(), ...flat(TILE_TOP - 0.006, [outer, outer, SKIN]), color: [...frame, 1] },
268
- { geometry: cube(), ...flat(TILE_TOP - 0.003, [1, 1, SKIN]), color: [...rgb('#CBB894'), 1] }
269
- ];
270
- for (let cell = 1; cell <= WINNING_POSITION; cell++) {
271
- const [x, y] = cellCenter(cell);
272
- parts.push({
273
- geometry: cube(),
274
- position: [x, y, TILE_TOP - SKIN / 2],
275
- scale: [CELL - 0.005, CELL - 0.005, SKIN],
276
- color: [...cellColor(cell), 1]
277
- });
278
- }
279
- // A gold star on the last cell
280
- const [fx, fy] = cellCenter(WINNING_POSITION);
281
- parts.push({
282
- geometry: extrude(new Path().addStar(0, 0, 0.5, 0.22), { depth: 0.12 }),
283
- position: [fx, fy - 0.012, DIGITS_Z],
284
- scale: [0.042, 0.042, 0.004],
285
- color: [...rgb('#FFC107'), 1]
286
- });
287
- // The start pad: a flat wooden disc for the pawns before their first move
288
- parts.push({ geometry: extrude(new Path().addCircle(0, 0, 0.08), { depth: SKIN, color: rgb('#A1887F') }), position: [START_X, DIE_Y, START_Z] });
289
- // Snakes and ladders, pressed onto the cells
290
- const art = merge([...LADDERS.flatMap(ladderParts), ...SNAKES.flatMap(snakeParts)]);
291
- parts.push({ geometry: art, position: [0, 0, ART_Z], scale: [1, 1, FLAT] });
292
- // Matte, like printed card: no glossy highlight on the board (the pawns and die keep theirs)
293
- return createShape(merge(parts), { center: false, shine: 0 });
294
- });
295
-
296
- // ── Cell numbers: the shared 3D glyphs ────────────────────────────────
297
-
298
- const DIGIT_SCALE = 0.027; // a digit's height on the board
299
-
300
- /** Each cell's number near its top edge, as children of the board. */
301
- function spawnNumbers(world: World, board: Entity) {
302
- const dark = toColor(NUMBER_COLOR);
303
- const gold = toColor(STAR_NUMBER_COLOR);
304
- for (let cell = 1; cell <= WINNING_POSITION; cell++) {
305
- const [x, y] = cellCenter(cell);
306
- const text = String(cell);
307
- const width = text.length * GLYPH_ADVANCE - (GLYPH_ADVANCE - GLYPH_WIDTH);
308
- for (let i = 0; i < text.length; i++) {
309
- world.spawn({
310
- mesh: flatGlyphMesh(text[i]!),
311
- parent: board,
312
- position: [x + (-width / 2 + GLYPH_WIDTH / 2 + i * GLYPH_ADVANCE) * DIGIT_SCALE, y + CELL * 0.24, DIGITS_Z],
313
- scale: DIGIT_SCALE,
314
- color: cell === 1 || cell === WINNING_POSITION ? gold : dark,
315
- pickable: false
316
- });
317
- }
318
- }
319
- }
320
-
321
- // ── Pawns, the die, shadows ───────────────────────────────────────────
322
-
323
- /** A glossy pawn, one unit tall, standing on the origin. */
324
- const pawnMesh = () =>
325
- cached('snl-pawn', () =>
326
- createShape(
327
- merge([
328
- {
329
- geometry: lathe(
330
- [
331
- [0.001, 0],
332
- [0.42, 0],
333
- [0.44, 0.04],
334
- [0.42, 0.1],
335
- [0.31, 0.14],
336
- [0.25, 0.2],
337
- [0.19, 0.42],
338
- [0.15, 0.58],
339
- [0.27, 0.61],
340
- [0.27, 0.66],
341
- [0.14, 0.69]
342
- ],
343
- { segments: 32 }
344
- )
345
- },
346
- { geometry: sphere(), position: [0, 0.84, 0], scale: 0.4 }
347
- ]),
348
- { center: false, shine: 0.65 }
349
- )
350
- );
351
-
352
- /** The die showing `value` toward the camera (shared/EngineDice), turned `twist` round its up axis. */
353
- export const dieRotation = (value: number, twist = 0): Quat => sharedDieRotation(TILT, value, twist);
354
-
355
- const discMesh = () => cached('snl-disc', () => createShape(extrude(new Path().addCircle(0, 0, 0.5), { depth: 0 })));
356
- const ringMesh = () =>
357
- cached('snl-ring', () => createShape(extrude(new Path().addCircle(0, 0, 0.5).addCircle(0, 0, 0.42), { depth: 0, fillRule: 'evenodd' })));
358
-
359
- // ── Spawning ──────────────────────────────────────────────────────────
360
-
361
- const SHADOW: Color = [0, 0, 0, 0.22];
362
- const BACKDROP_DEPTH = 25; // below the board, in world units
363
-
364
- export type Scene = {
365
- backdrop: Entity;
366
- board: Entity;
367
- tokens: [Entity, Entity];
368
- shadows: [Entity, Entity];
369
- die: Entity;
370
- dieShadow: Entity;
371
- ring: Entity;
372
- };
373
-
374
- /** Board units to world units (view points). */
375
- export const toWorld = (l: Layout, x: number, y: number, z: number): Vec3 => [x * l.size, y * l.size, z * l.size];
376
-
377
- const tiltView = (l: Layout): TiltView => ({ width: l.width, height: l.height, centerY: l.centerY, tilt: TILT });
378
-
379
- /** Points the camera at the board so it lands where the layout puts it. */
380
- export const aimCamera = (camera: Camera, l: Layout) => aimTilted(camera, tiltView(l));
381
-
382
- export function buildScene(world: World, l: Layout, theme: GameTheme): Scene {
383
- const backdrop = spawnBackdrop(world, l.width, l.height, -BACKDROP_DEPTH, theme);
384
- placeTiltedBackdrop(world, backdrop, tiltView(l), BACKDROP_DEPTH);
385
- const board = world.spawn({ mesh: boardMesh(), scale: l.size, color: [1, 1, 1, 1], pickable: false });
386
- spawnNumbers(world, board);
387
- const token = (color: string) =>
388
- world.spawn({ mesh: pawnMesh(), rotation: STAND_UP, scale: TOKEN_HEIGHT * l.size, color: toColor(color), pickable: false });
389
- const shadow = () => world.spawn({ mesh: discMesh(), scale: 0.052 * l.size, color: SHADOW, pickable: false });
390
- const dieShadow = world.spawn({
391
- mesh: discMesh(),
392
- position: toWorld(l, 0.012, DIE_Y - 0.01, 0.001),
393
- scale: [DIE_SIZE * 1.25 * l.size, DIE_SIZE * 1.1 * l.size, 1],
394
- color: SHADOW,
395
- pickable: false
396
- });
397
- const ring = world.spawn({ mesh: ringMesh(), position: toWorld(l, 0, DIE_Y, 0.002), scale: 0, color: [1, 0.78, 0.15, 0.85], pickable: false });
398
- const die = world.spawn({ mesh: dieMesh(), position: dieRest(l), rotation: dieRotation(1), scale: DIE_SIZE * l.size, pickable: false });
399
- return { backdrop, board, tokens: [token(PLAYER_COLOR), token(AI_COLOR)], shadows: [shadow(), shadow()], die, dieShadow, ring };
400
- }
401
-
402
- export function removeScene(world: World, s: Scene) {
403
- for (const e of [s.backdrop, s.board, ...s.tokens, ...s.shadows, s.die, s.dieShadow, s.ring]) world.despawn(e);
404
- }
405
-
406
- export function setSceneTheme(world: World, s: Scene, theme: GameTheme) {
407
- setBackdropTheme(world, s.backdrop, theme);
408
- }
409
-
410
- // ── Motion ────────────────────────────────────────────────────────────
411
-
412
- export const dieRest = (l: Layout): Vec3 => toWorld(l, 0, DIE_Y, DIE_SIZE / 2);
413
-
414
- /** The die is tossed, tumbles and bounces to rest showing `value` (shared/EngineDice). */
415
- export function rollDie(world: World, l: Layout, s: Scene, value: number, time: number, disposed?: () => boolean) {
416
- rollSharedDie(world, {
417
- die: s.die,
418
- shadow: s.dieShadow,
419
- rest: dieRest(l),
420
- shadowAt: toWorld(l, 0.012, DIE_Y - 0.01, 0.001),
421
- shadowScale: [DIE_SIZE * 1.25 * l.size, DIE_SIZE * 1.1 * l.size, 1],
422
- size: DIE_SIZE * l.size,
423
- tilt: TILT,
424
- value,
425
- duration: time,
426
- disposed
427
- });
428
- }
429
-
430
- /** The gold ring under the die pulses while it's the player's roll. */
431
- export function showRollHint(world: World, l: Layout, s: Scene, on: boolean) {
432
- world.stopAnimation(s.ring);
433
- if (!on) {
434
- world.set(s.ring, { scale: 0 });
435
- return;
436
- }
437
- const size = DIE_SIZE * 1.55 * l.size;
438
- world.set(s.ring, { scale: size });
439
- world.animate(s.ring, { scale: size * 1.15 }, { duration: 0.6, easing: 'easeInOut', repeat: 'forever', yoyo: true });
440
- }
441
-
442
- /** A pawn's place on a board point (x, y) at height z, and its shadow's under it. */
443
- export function placeToken(world: World, l: Layout, s: Scene, who: number, at: Vec3) {
444
- world.stopAnimation(s.tokens[who]!);
445
- world.stopAnimation(s.shadows[who]!);
446
- world.set(s.tokens[who]!, { position: pawnAt(l, at) });
447
- world.set(s.shadows[who]!, { position: toWorld(l, at[0] + 0.006, at[1] - 0.006, SHADOW_Z) });
448
- }
449
-
450
- /**
451
- * Moves a pawn through board points (x, y, z) in `time` seconds, along a smooth curve; with `hop`, it
452
- * arcs up between them. Its shadow follows along the board.
453
- */
454
- export function moveToken(world: World, l: Layout, s: Scene, who: number, points: Vec3[], time: number, hop = 0) {
455
- const token = s.tokens[who]!;
456
- const shadow = s.shadows[who]!;
457
- const end = points[points.length - 1]!;
458
- const keys = hop
459
- ? [
460
- { position: pawnAt(l, [(points[0]![0] + end[0]) / 2, (points[0]![1] + end[1]) / 2, Math.max(points[0]![2], end[2]) + hop]), at: 0.5 },
461
- { position: pawnAt(l, end), at: 1 }
462
- ]
463
- : points.slice(1).map((p, i) => ({ position: pawnAt(l, p), at: (i + 1) / (points.length - 1) }));
464
- world.stopAnimation(token);
465
- world.stopAnimation(shadow);
466
- world.animate(token, keys, { duration: time, path: 'smooth', easing: hop ? 'linear' : 'easeInOut' });
467
- world.animate(shadow, { position: toWorld(l, end[0] + 0.006, end[1] - 0.006, SHADOW_Z) }, { duration: time, easing: hop ? 'linear' : 'easeInOut' });
468
- }
469
-
470
- /** The pawn whose turn it is bobs gently. */
471
- export function bobToken(world: World, l: Layout, s: Scene, who: number | null) {
472
- s.tokens.forEach((t, i) => world.set(t, { bob: i === who ? { amplitude: [0, 0, 0.008 * l.size], speed: 6 } : null }));
473
- }
474
-
475
- /** A snake's bite: the pawn shakes and the board jolts. */
476
- export function snakeBite(world: World, l: Layout, s: Scene, camera: Camera, who: number) {
477
- world.animate(s.tokens[who]!, { shake: 0.01 * l.size }, { duration: 0.3 });
478
- camera.shake = 0.008 * l.size;
479
- }
480
-
481
- /** Sparkles at a board point (a ladder's top). */
482
- export function sparkle(world: World, l: Layout, at: Vec3) {
483
- effects.sparkle(world, {
484
- position: toWorld(l, at[0], at[1], at[2] + 0.03),
485
- count: 16,
486
- size: 0.009 * l.size,
487
- speed: 0.25 * l.size,
488
- lifetime: 0.6,
489
- colors: [toColor('#FFD54F'), toColor('#FFF59D'), toColor('#FFFFFF')]
490
- });
491
- }
492
-
493
- /** Confetti over the winning pawn. */
494
- export function confetti(world: World, l: Layout, at: Vec3) {
495
- effects.confetti(world, {
496
- position: toWorld(l, at[0], at[1], at[2] + 0.06),
497
- count: 48,
498
- size: 0.012 * l.size,
499
- speed: 0.7 * l.size,
500
- lifetime: 1.3,
501
- gravity: -1.2 * l.size,
502
- colors: ['#FF5252', '#FFD740', '#69F0AE', '#448AFF'].map((c) => toColor(c))
503
- });
504
- }
505
-
506
- /** The line a pawn slides down a snake (head to tail) or climbs a ladder (foot to top), in board points. */
507
- const slidePaths = new Map<number, Vec3[] | null>();
508
- export function slidePath(from: number): Vec3[] | null {
509
- if (slidePaths.has(from)) return slidePaths.get(from)!;
510
- const snake = SNAKE_AT.get(from);
511
- const ladder = LADDER_AT.get(from);
512
- const path = snake ? snakePath(snake).filter((_, i) => i % 3 === 0 || i === SNAKE_POINTS - 1) : ladder ? ladderPath(ladder) : null;
513
- if (snake || ladder) slidePaths.set(from, path);
514
- return path;
515
- }
@@ -1,74 +0,0 @@
1
- // Space Fighter's screen, on the Nayan engine: deep space, the ship and the asteroid belts are one 3D
2
- // scene (a perspective camera looking out into space), under Playtura's scoreboard, controls and
3
- // modals. The rules are in SpaceFighterGame.ts, what it draws in SpaceFighterScene.ts.
4
- //
5
- // One world serves the whole visit: Start, Stop and Play Again reset it in place, so the GPU view is
6
- // never rebuilt. Rocks tumble, stars drift and the exhausts flicker in the engine's Rust core; JS runs
7
- // the field (a handful of boxes) and steps the world once a frame.
8
- import { HapticType } from '../../services/HapticsService';
9
- import { GAME_SOUNDS } from '../../services/SoundsService';
10
- import { GAME_IDS } from '../../services/UtilsService';
11
- import { engineGame, EngineGameScreen } from '../shared/EngineGameScreen';
12
- import { livesColumn, scoreColumn, timerColumn } from '../shared/EngineHud';
13
- import { toRgb } from '../shared/EngineUtils';
14
- import { useEngineGame } from '../shared/useEngineGame';
15
- import { useLiveState } from '../shared/useLiveState';
16
- import { BACKGROUND, DAY_BACKGROUND, getLayout, LIGHT, LIVES, TIME_LIMIT } from './SpaceFighterConstants';
17
- import { createGame, dispose, drag, type GameEvent, reset, setLayout, setTheme, start, tick } from './SpaceFighterGame';
18
-
19
- const SOUNDS = GAME_SOUNDS.SPACE_FIGHTER;
20
- const NIGHT_RGB = toRgb(BACKGROUND);
21
- const DAY_RGB = toRgb(DAY_BACKGROUND);
22
-
23
- /** Each event's sound and haptic, as the original version played them. */
24
- const FEEDBACK: Record<GameEvent, { sound: (typeof SOUNDS)[keyof typeof SOUNDS]; haptic: HapticType }> = {
25
- grab: { sound: SOUNDS.GRAB, haptic: HapticType.MEDIUM },
26
- release: { sound: SOUNDS.RELEASE, haptic: HapticType.LIGHT },
27
- dodge: { sound: SOUNDS.DODGE, haptic: HapticType.LIGHT },
28
- hit: { sound: SOUNDS.COLLISION, haptic: HapticType.HEAVY }
29
- };
30
-
31
- export const SpaceFighter = engineGame(GAME_IDS.SPACE_FIGHTER, (props) => {
32
- const [score, setScore] = useLiveState(0);
33
- const [lives, setLives] = useLiveState(LIVES);
34
- const [timeLeft, setTimeLeft] = useLiveState(TIME_LIMIT);
35
-
36
- // A win when the time runs out, a loss with no lives left
37
- const { theme, status, screen, gameOver } = useEngineGame(props, {
38
- gameId: GAME_IDS.SPACE_FIGHTER,
39
- create: createGame,
40
- setTheme,
41
- start,
42
- reset,
43
- dispose,
44
- tick,
45
- resize: (g, width, height, offset) => setLayout(g, getLayout(width, height, offset)),
46
- drag,
47
- sounds: SOUNDS,
48
- onStart: (fx) => fx(SOUNDS.START, HapticType.SUCCESS),
49
- onOver: (fx, s) => fx(s === 'win' ? SOUNDS.WIN : SOUNDS.GAME_OVER, s === 'win' ? HapticType.SUCCESS : HapticType.ERROR),
50
- wire: (g, fx) => {
51
- g.onScore = setScore;
52
- g.onLives = setLives;
53
- g.onTime = setTimeLeft;
54
- g.onEvent = (event) => fx(FEEDBACK[event].sound, FEEDBACK[event].haptic);
55
- }
56
- });
57
-
58
- return (
59
- <EngineGameScreen
60
- {...screen}
61
- light={LIGHT}
62
- background={theme.mode === 'dark' ? NIGHT_RGB : DAY_RGB}
63
- columns={[scoreColumn(score), livesColumn(lives, LIVES), timerColumn(timeLeft, theme, 0)]}
64
- subtext="Navigate through space!"
65
- gameOver={gameOver({
66
- title: 'GAME OVER',
67
- message: status === 'win' ? 'You survived the asteroid field!' : 'Your ship was destroyed!',
68
- scoreLabel: 'Final Score',
69
- score,
70
- buttonText: 'Fly Again!'
71
- })}
72
- />
73
- );
74
- });
@@ -1,86 +0,0 @@
1
- import type { Light } from '@nayan-ui/engine';
2
- // Space Fighter's rules, physics, timings and layout. Rules, scoring and sizing match the original version
3
- // (games/space-fighter): everything is in screen points, scaled from a 390 x 844 phone, so the field
4
- // takes the same time to cross and the gaps are as wide on every device.
5
- import { getScoreBoardTop } from '../shared/EngineHud';
6
-
7
- // ── Rules ─────────────────────────────────────────────────────────────
8
-
9
- export const TIME_LIMIT = 120; // seconds; surviving them wins
10
- export const LIVES = 3;
11
- export const DODGE_POINTS = 500; // a pair of asteroid belts passed
12
- export const HIT_COOLDOWN = 2; // seconds of blinking safety after a hit
13
-
14
- // ── Sizes and speeds (points, at the 390 x 844 base) ──────────────────
15
-
16
- const BASE_WIDTH = 390;
17
- const BASE_HEIGHT = 844;
18
- const TABLET_WIDTH = 640;
19
- const SHIP_SIZE = { phone: 28, tablet: 22 }; // the ship's hitbox, a square
20
- const BELT_HEIGHT = { phone: 80, tablet: 60 }; // each belt's depth down the screen
21
- const GAP = 120; // the opening between a pair's belts
22
- const SPAWN_INTERVAL = { phone: 1.5, tablet: 1.8 }; // seconds, at the base height
23
- const FALL_SPEED = 3.5; // points per 16 ms frame, at the base height
24
- const GAP_VARIANCE = 0.15; // of the width: how far the opening wanders from the centre
25
- const MIN_EDGE = 0.08; // of the width: the narrowest a belt gets
26
- const SPAWN_ABOVE = 0.3; // of the height: where a pair starts, above the top edge
27
-
28
- export const BASE_FRAME = 0.016; // the fall speed is per this much time
29
- export const MAX_FRAME = 0.064; // a long frame moves the field at most this much
30
-
31
- // ── The scene ─────────────────────────────────────────────────────────
32
-
33
- /** How far ahead of the camera the game plays, in world units: screen points map onto this plane. */
34
- export const PLAY_DEPTH = 12;
35
- export const FOV = 0.9;
36
- export const BACKGROUND = '#050311'; // night: deep black space
37
- export const DAY_BACKGROUND = '#A8DCF7'; // day (light mode): a bright daytime sky
38
- /** A cool starlight from the upper left, a touch of violet in the shadows. */
39
- export const LIGHT: Light = { direction: [-0.45, 0.6, 0.65], ambient: 0.38, shadows: false, color: [1.05, 1.02, 1.1] };
40
-
41
- // ── Layout ────────────────────────────────────────────────────────────
42
-
43
- export type Layout = {
44
- width: number;
45
- height: number;
46
- offset: number;
47
- /** World units per screen point on the play plane. */
48
- k: number;
49
- shipSize: number;
50
- shipY: number;
51
- beltHeight: number;
52
- gap: number;
53
- spawnInterval: number;
54
- /** Points per second. */
55
- fallSpeed: number;
56
- spawnY: number;
57
- /** Where the scoreboard ends, for the start hint. */
58
- scoreboardBottom: number;
59
- };
60
-
61
- export function getLayout(width: number, height: number, offset: number): Layout {
62
- const tablet = width > TABLET_WIDTH;
63
- const sx = width / BASE_WIDTH;
64
- const sy = height / BASE_HEIGHT;
65
- return {
66
- width,
67
- height,
68
- offset,
69
- k: (2 * PLAY_DEPTH * Math.tan(FOV / 2)) / height,
70
- shipSize: Math.round((tablet ? SHIP_SIZE.tablet : SHIP_SIZE.phone) * sx),
71
- shipY: height * (offset > 0 ? 0.77 : 0.68),
72
- beltHeight: Math.round((tablet ? BELT_HEIGHT.tablet : BELT_HEIGHT.phone) * sy),
73
- gap: Math.round(GAP * sx),
74
- spawnInterval: (tablet ? SPAWN_INTERVAL.tablet : SPAWN_INTERVAL.phone) / sy,
75
- fallSpeed: (FALL_SPEED * sy) / BASE_FRAME,
76
- spawnY: -Math.round(height * SPAWN_ABOVE),
77
- scoreboardBottom: getScoreBoardTop(offset) + 82
78
- };
79
- }
80
-
81
- /** Where a pair's opening goes: near the centre, wandering a little, never squeezing a belt off the edge. */
82
- export function gapLeft(l: Layout, random = Math.random) {
83
- const centre = l.width / 2 + (random() - 0.5) * 2 * l.width * GAP_VARIANCE;
84
- const minEdge = Math.round(l.width * MIN_EDGE);
85
- return Math.max(minEdge, Math.min(centre - l.gap / 2, l.width - l.gap - minEdge));
86
- }