@rpgjs/client 5.0.0-beta.2 → 5.0.0-beta.20

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 (314) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/Game/AnimationManager.d.ts +2 -1
  3. package/dist/Game/AnimationManager.js +21 -9
  4. package/dist/Game/AnimationManager.js.map +1 -1
  5. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  6. package/dist/Game/ClientVisuals.d.ts +61 -0
  7. package/dist/Game/ClientVisuals.js +96 -0
  8. package/dist/Game/ClientVisuals.js.map +1 -0
  9. package/dist/Game/ClientVisuals.spec.d.ts +1 -0
  10. package/dist/Game/Event.js.map +1 -1
  11. package/dist/Game/EventComponentResolver.d.ts +16 -0
  12. package/dist/Game/EventComponentResolver.js +52 -0
  13. package/dist/Game/EventComponentResolver.js.map +1 -0
  14. package/dist/Game/EventComponentResolver.spec.d.ts +1 -0
  15. package/dist/Game/Map.d.ts +9 -1
  16. package/dist/Game/Map.js +83 -5
  17. package/dist/Game/Map.js.map +1 -1
  18. package/dist/Game/Object.d.ts +49 -15
  19. package/dist/Game/Object.js +101 -42
  20. package/dist/Game/Object.js.map +1 -1
  21. package/dist/Game/Object.spec.d.ts +1 -0
  22. package/dist/Game/Player.js.map +1 -1
  23. package/dist/Game/ProjectileManager.d.ts +98 -0
  24. package/dist/Game/ProjectileManager.js +196 -0
  25. package/dist/Game/ProjectileManager.js.map +1 -0
  26. package/dist/Game/ProjectileManager.spec.d.ts +1 -0
  27. package/dist/Gui/Gui.d.ts +20 -6
  28. package/dist/Gui/Gui.js +96 -54
  29. package/dist/Gui/Gui.js.map +1 -1
  30. package/dist/Gui/Gui.spec.d.ts +1 -0
  31. package/dist/Gui/NotificationManager.js.map +1 -1
  32. package/dist/Resource.js +1 -1
  33. package/dist/Resource.js.map +1 -1
  34. package/dist/RpgClient.d.ts +194 -15
  35. package/dist/RpgClientEngine.d.ts +176 -11
  36. package/dist/RpgClientEngine.js +669 -68
  37. package/dist/RpgClientEngine.js.map +1 -1
  38. package/dist/Sound.js.map +1 -1
  39. package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorate.js +1 -1
  40. package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorateMetadata.js +1 -1
  41. package/dist/_virtual/_rolldown/runtime.js +13 -0
  42. package/dist/components/animations/animation.ce.js +6 -5
  43. package/dist/components/animations/animation.ce.js.map +1 -1
  44. package/dist/components/animations/fx.ce.js +60 -0
  45. package/dist/components/animations/fx.ce.js.map +1 -0
  46. package/dist/components/animations/hit.ce.js +24 -28
  47. package/dist/components/animations/hit.ce.js.map +1 -1
  48. package/dist/components/animations/index.d.ts +1 -0
  49. package/dist/components/animations/index.js +6 -4
  50. package/dist/components/animations/index.js.map +1 -1
  51. package/dist/components/character.ce.js +606 -248
  52. package/dist/components/character.ce.js.map +1 -1
  53. package/dist/components/dynamics/bar.ce.js +99 -0
  54. package/dist/components/dynamics/bar.ce.js.map +1 -0
  55. package/dist/components/dynamics/image.ce.js +26 -0
  56. package/dist/components/dynamics/image.ce.js.map +1 -0
  57. package/dist/components/dynamics/parse-value.d.ts +3 -0
  58. package/dist/components/dynamics/parse-value.js +54 -35
  59. package/dist/components/dynamics/parse-value.js.map +1 -1
  60. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  61. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  62. package/dist/components/dynamics/shape-utils.js +73 -0
  63. package/dist/components/dynamics/shape-utils.js.map +1 -0
  64. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  65. package/dist/components/dynamics/shape.ce.js +86 -0
  66. package/dist/components/dynamics/shape.ce.js.map +1 -0
  67. package/dist/components/dynamics/text.ce.js +36 -56
  68. package/dist/components/dynamics/text.ce.js.map +1 -1
  69. package/dist/components/gui/box.ce.js +9 -9
  70. package/dist/components/gui/box.ce.js.map +1 -1
  71. package/dist/components/gui/dialogbox/index.ce.js +75 -65
  72. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  73. package/dist/components/gui/gameover.ce.js +47 -68
  74. package/dist/components/gui/gameover.ce.js.map +1 -1
  75. package/dist/components/gui/hud/hud.ce.js +23 -31
  76. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  77. package/dist/components/gui/menu/equip-menu.ce.js +121 -172
  78. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
  79. package/dist/components/gui/menu/exit-menu.ce.js +15 -10
  80. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
  81. package/dist/components/gui/menu/items-menu.ce.js +62 -77
  82. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  83. package/dist/components/gui/menu/main-menu.ce.js +89 -104
  84. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  85. package/dist/components/gui/menu/options-menu.ce.js +12 -8
  86. package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
  87. package/dist/components/gui/menu/skills-menu.ce.js +17 -19
  88. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
  89. package/dist/components/gui/mobile/index.js +2 -2
  90. package/dist/components/gui/mobile/index.js.map +1 -1
  91. package/dist/components/gui/mobile/mobile.ce.js +7 -5
  92. package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
  93. package/dist/components/gui/notification/notification.ce.js +28 -26
  94. package/dist/components/gui/notification/notification.ce.js.map +1 -1
  95. package/dist/components/gui/save-load.ce.js +81 -256
  96. package/dist/components/gui/save-load.ce.js.map +1 -1
  97. package/dist/components/gui/shop/shop.ce.js +107 -142
  98. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  99. package/dist/components/gui/title-screen.ce.js +50 -73
  100. package/dist/components/gui/title-screen.ce.js.map +1 -1
  101. package/dist/components/index.d.ts +2 -1
  102. package/dist/components/index.js +1 -0
  103. package/dist/components/interaction-components.ce.js +22 -0
  104. package/dist/components/interaction-components.ce.js.map +1 -0
  105. package/dist/components/player-components-utils.d.ts +67 -0
  106. package/dist/components/player-components-utils.js +162 -0
  107. package/dist/components/player-components-utils.js.map +1 -0
  108. package/dist/components/player-components-utils.spec.d.ts +1 -0
  109. package/dist/components/player-components.ce.js +191 -0
  110. package/dist/components/player-components.ce.js.map +1 -0
  111. package/dist/components/prebuilt/hp-bar.ce.js +45 -45
  112. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
  113. package/dist/components/prebuilt/light-halo.ce.js +39 -60
  114. package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
  115. package/dist/components/scenes/canvas.ce.js +205 -27
  116. package/dist/components/scenes/canvas.ce.js.map +1 -1
  117. package/dist/components/scenes/draw-map.ce.js +39 -39
  118. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  119. package/dist/components/scenes/event-layer.ce.js +51 -10
  120. package/dist/components/scenes/event-layer.ce.js.map +1 -1
  121. package/dist/core/inject.js +1 -1
  122. package/dist/core/inject.js.map +1 -1
  123. package/dist/core/setup.js +1 -1
  124. package/dist/core/setup.js.map +1 -1
  125. package/dist/decorators/spritesheet.d.ts +1 -0
  126. package/dist/decorators/spritesheet.js +11 -0
  127. package/dist/decorators/spritesheet.js.map +1 -0
  128. package/dist/i18n.d.ts +55 -0
  129. package/dist/i18n.js +60 -0
  130. package/dist/i18n.js.map +1 -0
  131. package/dist/i18n.spec.d.ts +1 -0
  132. package/dist/index.d.ts +7 -0
  133. package/dist/index.js +29 -21
  134. package/dist/module.js +45 -4
  135. package/dist/module.js.map +1 -1
  136. package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@3.1.0}/node_modules/@signe/di/dist/index.js +7 -117
  137. package/dist/node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js.map +1 -0
  138. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js +239 -0
  139. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  141. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  142. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js +698 -0
  143. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js.map +1 -0
  144. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js +43 -0
  145. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  146. package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@3.1.0_react@19.2.7}/node_modules/@signe/sync/dist/index.js +57 -141
  147. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js.map +1 -0
  148. package/dist/node_modules/.pnpm/{partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js} +30 -17
  149. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js.map +1 -0
  150. package/dist/node_modules/.pnpm/{partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js} +65 -34
  151. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js.map +1 -0
  152. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js +13 -0
  153. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js.map +1 -0
  154. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js +106 -0
  155. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js.map +1 -0
  156. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +13 -0
  157. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js.map +1 -0
  158. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js +121 -0
  159. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js.map +1 -0
  160. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js +10 -0
  161. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js.map +1 -0
  162. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js +110 -0
  163. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js.map +1 -0
  164. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js +99 -0
  165. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js.map +1 -0
  166. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js +82 -0
  167. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js.map +1 -0
  168. package/dist/node_modules/.pnpm/{zod@3.24.2/node_modules/zod/lib/index.js → zod@3.25.76/node_modules/zod/v3/types.js} +74 -611
  169. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js.map +1 -0
  170. package/dist/presets/animation.js.map +1 -1
  171. package/dist/presets/faceset.js.map +1 -1
  172. package/dist/presets/icon.js.map +1 -1
  173. package/dist/presets/index.js.map +1 -1
  174. package/dist/presets/lpc.js.map +1 -1
  175. package/dist/presets/rmspritesheet.js.map +1 -1
  176. package/dist/services/AbstractSocket.d.ts +2 -0
  177. package/dist/services/AbstractSocket.js.map +1 -1
  178. package/dist/services/actionInput.d.ts +14 -0
  179. package/dist/services/actionInput.js +59 -0
  180. package/dist/services/actionInput.js.map +1 -0
  181. package/dist/services/actionInput.spec.d.ts +1 -0
  182. package/dist/services/interactions.d.ts +159 -0
  183. package/dist/services/interactions.js +460 -0
  184. package/dist/services/interactions.js.map +1 -0
  185. package/dist/services/interactions.spec.d.ts +1 -0
  186. package/dist/services/keyboardControls.d.ts +1 -0
  187. package/dist/services/keyboardControls.js +1 -0
  188. package/dist/services/keyboardControls.js.map +1 -1
  189. package/dist/services/loadMap.d.ts +9 -0
  190. package/dist/services/loadMap.js +1 -1
  191. package/dist/services/loadMap.js.map +1 -1
  192. package/dist/services/mmorpg-connection.d.ts +5 -0
  193. package/dist/services/mmorpg-connection.js +50 -0
  194. package/dist/services/mmorpg-connection.js.map +1 -0
  195. package/dist/services/mmorpg-connection.spec.d.ts +1 -0
  196. package/dist/services/mmorpg.d.ts +11 -4
  197. package/dist/services/mmorpg.js +57 -33
  198. package/dist/services/mmorpg.js.map +1 -1
  199. package/dist/services/pointerContext.d.ts +11 -0
  200. package/dist/services/pointerContext.js +48 -0
  201. package/dist/services/pointerContext.js.map +1 -0
  202. package/dist/services/pointerContext.spec.d.ts +1 -0
  203. package/dist/services/save.js.map +1 -1
  204. package/dist/services/save.spec.d.ts +1 -0
  205. package/dist/services/standalone-message.d.ts +1 -0
  206. package/dist/services/standalone-message.js +9 -0
  207. package/dist/services/standalone-message.js.map +1 -0
  208. package/dist/services/standalone.d.ts +4 -1
  209. package/dist/services/standalone.js +36 -16
  210. package/dist/services/standalone.js.map +1 -1
  211. package/dist/services/standalone.spec.d.ts +1 -0
  212. package/dist/utils/getEntityProp.js +4 -3
  213. package/dist/utils/getEntityProp.js.map +1 -1
  214. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  215. package/dist/utils/mapId.d.ts +1 -0
  216. package/dist/utils/mapId.js +6 -0
  217. package/dist/utils/mapId.js.map +1 -0
  218. package/dist/utils/readPropValue.d.ts +2 -0
  219. package/dist/utils/readPropValue.js +13 -0
  220. package/dist/utils/readPropValue.js.map +1 -0
  221. package/package.json +13 -13
  222. package/src/Game/AnimationManager.spec.ts +30 -0
  223. package/src/Game/AnimationManager.ts +26 -10
  224. package/src/Game/ClientVisuals.spec.ts +56 -0
  225. package/src/Game/ClientVisuals.ts +184 -0
  226. package/src/Game/EventComponentResolver.spec.ts +84 -0
  227. package/src/Game/EventComponentResolver.ts +74 -0
  228. package/src/Game/Map.ts +134 -2
  229. package/src/Game/Object.spec.ts +59 -0
  230. package/src/Game/Object.ts +181 -77
  231. package/src/Game/ProjectileManager.spec.ts +449 -0
  232. package/src/Game/ProjectileManager.ts +346 -0
  233. package/src/Gui/Gui.spec.ts +340 -0
  234. package/src/Gui/Gui.ts +129 -57
  235. package/src/Resource.ts +1 -2
  236. package/src/RpgClient.ts +220 -17
  237. package/src/RpgClientEngine.ts +959 -116
  238. package/src/components/animations/fx.ce +101 -0
  239. package/src/components/animations/index.ts +4 -2
  240. package/src/components/character.ce +681 -45
  241. package/src/components/dynamics/bar.ce +88 -0
  242. package/src/components/dynamics/image.ce +21 -0
  243. package/src/components/dynamics/parse-value.spec.ts +83 -0
  244. package/src/components/dynamics/parse-value.ts +111 -37
  245. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  246. package/src/components/dynamics/shape-utils.ts +61 -0
  247. package/src/components/dynamics/shape.ce +90 -0
  248. package/src/components/dynamics/text.ce +35 -149
  249. package/src/components/gui/dialogbox/index.ce +52 -21
  250. package/src/components/gui/gameover.ce +6 -4
  251. package/src/components/gui/menu/equip-menu.ce +11 -9
  252. package/src/components/gui/menu/exit-menu.ce +6 -4
  253. package/src/components/gui/menu/items-menu.ce +11 -9
  254. package/src/components/gui/menu/main-menu.ce +14 -12
  255. package/src/components/gui/menu/options-menu.ce +4 -3
  256. package/src/components/gui/menu/skills-menu.ce +2 -1
  257. package/src/components/gui/notification/notification.ce +7 -1
  258. package/src/components/gui/save-load.ce +13 -11
  259. package/src/components/gui/shop/shop.ce +20 -18
  260. package/src/components/gui/title-screen.ce +6 -4
  261. package/src/components/index.ts +2 -1
  262. package/src/components/interaction-components.ce +23 -0
  263. package/src/components/player-components-utils.spec.ts +109 -0
  264. package/src/components/player-components-utils.ts +205 -0
  265. package/src/components/player-components.ce +222 -0
  266. package/src/components/prebuilt/hp-bar.ce +4 -3
  267. package/src/components/prebuilt/light-halo.ce +2 -2
  268. package/src/components/scenes/canvas.ce +219 -15
  269. package/src/components/scenes/draw-map.ce +34 -22
  270. package/src/components/scenes/event-layer.ce +55 -4
  271. package/src/core/setup.ts +2 -2
  272. package/src/decorators/spritesheet.ts +8 -0
  273. package/src/i18n.spec.ts +39 -0
  274. package/src/i18n.ts +59 -0
  275. package/src/index.ts +7 -0
  276. package/src/module.ts +61 -11
  277. package/src/services/AbstractSocket.ts +3 -0
  278. package/src/services/actionInput.spec.ts +155 -0
  279. package/src/services/actionInput.ts +120 -0
  280. package/src/services/interactions.spec.ts +175 -0
  281. package/src/services/interactions.ts +722 -0
  282. package/src/services/keyboardControls.ts +2 -1
  283. package/src/services/loadMap.ts +5 -1
  284. package/src/services/mmorpg-connection.spec.ts +99 -0
  285. package/src/services/mmorpg-connection.ts +69 -0
  286. package/src/services/mmorpg.ts +70 -36
  287. package/src/services/pointerContext.spec.ts +36 -0
  288. package/src/services/pointerContext.ts +84 -0
  289. package/src/services/save.spec.ts +127 -0
  290. package/src/services/standalone-message.ts +7 -0
  291. package/src/services/standalone.spec.ts +54 -0
  292. package/src/services/standalone.ts +44 -12
  293. package/src/utils/getEntityProp.spec.ts +96 -0
  294. package/src/utils/getEntityProp.ts +4 -3
  295. package/src/utils/mapId.ts +2 -0
  296. package/src/utils/readPropValue.ts +16 -0
  297. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
  298. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js +0 -457
  299. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js.map +0 -1
  300. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
  301. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
  302. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
  303. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
  304. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
  305. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
  306. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
  307. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
  308. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
  309. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
  310. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
  311. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +0 -1
  312. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +0 -1
  313. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +0 -2
  314. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +0 -1
package/src/Gui/Gui.ts CHANGED
@@ -3,12 +3,12 @@ import { signal, Signal, WritableSignal } from "canvasengine";
3
3
  import { AbstractWebsocket, WebSocketToken } from "../services/AbstractSocket";
4
4
  import { DialogboxComponent, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent } from "../components/gui";
5
5
  import { combineLatest, Subscription } from "rxjs";
6
- import { delay, PrebuiltGui } from "@rpgjs/common";
6
+ import { PrebuiltGui } from "@rpgjs/common";
7
7
 
8
8
  interface GuiOptions {
9
9
  name?: string;
10
10
  id?: string;
11
- component: any;
11
+ component?: any;
12
12
  display?: boolean;
13
13
  data?: any;
14
14
  /**
@@ -28,19 +28,38 @@ interface GuiOptions {
28
28
  * @default false
29
29
  */
30
30
  attachToSprite?: boolean;
31
+ /**
32
+ * Vue v4 compatibility flag. Prefer attachToSprite in v5 projects.
33
+ */
34
+ rpgAttachToSprite?: boolean;
31
35
  }
32
36
 
33
- interface GuiInstance {
37
+ export interface GuiInstance {
34
38
  name: string;
35
39
  component: any;
36
40
  display: WritableSignal<boolean>;
37
41
  data: WritableSignal<any>;
42
+ openId?: string;
38
43
  autoDisplay: boolean;
39
- dependencies?: () => Signal[];
44
+ dependencies?: Signal[];
40
45
  subscription?: Subscription;
41
46
  attachToSprite?: boolean;
42
47
  }
43
48
 
49
+ type GuiState = {
50
+ name: string;
51
+ component: any;
52
+ display: boolean;
53
+ data: any;
54
+ openId?: string;
55
+ attachToSprite: boolean;
56
+ };
57
+
58
+ type VueGuiBridge = {
59
+ updateGuiState?: (state: GuiState) => void;
60
+ initializeGuiStates?: (states: GuiState[]) => void;
61
+ };
62
+
44
63
  interface GuiAction {
45
64
  guiId: string;
46
65
  name: string;
@@ -117,7 +136,7 @@ export class RpgGui {
117
136
  private webSocket: AbstractWebsocket;
118
137
  gui = signal<Record<string, GuiInstance>>({});
119
138
  extraGuis: GuiInstance[] = [];
120
- private vueGuiInstance: any = null; // Reference to VueGui instance
139
+ private vueGuiInstance: VueGuiBridge | null = null;
121
140
  private optimisticReducers = new Map<string, OptimisticReducer[]>();
122
141
  private pendingActions = new Map<string, GuiAction[]>();
123
142
  /**
@@ -162,12 +181,18 @@ export class RpgGui {
162
181
  }
163
182
 
164
183
  async _initialize() {
165
- this.webSocket.on("gui.open", (data: { guiId: string; data: any }) => {
184
+ this.webSocket.on("gui.open", (data: { guiId: string; data: any; guiOpenId?: string }) => {
166
185
  this.clearPendingActions(data.guiId);
167
- this.display(data.guiId, data.data);
186
+ this.display(data.guiId, data.data, [], data.guiOpenId);
168
187
  });
169
188
 
170
- this.webSocket.on("gui.exit", (guiId: string) => {
189
+ this.webSocket.on("gui.exit", (payload: string | { guiId: string; guiOpenId?: string }) => {
190
+ const guiId = typeof payload === "string" ? payload : payload.guiId;
191
+ const guiOpenId = typeof payload === "string" ? undefined : payload.guiOpenId;
192
+ const current = this.get(guiId);
193
+ if (guiOpenId && current?.openId && current.openId !== guiOpenId) {
194
+ return;
195
+ }
171
196
  this.hide(guiId);
172
197
  });
173
198
 
@@ -196,6 +221,7 @@ export class RpgGui {
196
221
  */
197
222
  _setVueGuiInstance(vueGuiInstance: any) {
198
223
  this.vueGuiInstance = vueGuiInstance;
224
+ this._initializeVueComponents();
199
225
  }
200
226
 
201
227
  /**
@@ -207,21 +233,9 @@ export class RpgGui {
207
233
  * @param data - Component data
208
234
  */
209
235
  private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {
210
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
211
- // Find the GUI in extraGuis
212
- const extraGui = this.extraGuis.find(gui => gui.name === guiId);
213
- if (extraGui) {
214
- // Update the Vue component's display state and data
215
- this.vueGuiInstance.vm.gui[guiId] = {
216
- name: guiId,
217
- display,
218
- data,
219
- attachToSprite: extraGui.attachToSprite || false
220
- };
221
- // Trigger Vue reactivity
222
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
223
- }
224
- }
236
+ const extraGui = this.extraGuis.find(gui => gui.name === guiId);
237
+ if (!extraGui) return;
238
+ this.vueGuiInstance?.updateGuiState?.(this.toGuiState(extraGui, display, data));
225
239
  }
226
240
 
227
241
  /**
@@ -229,20 +243,9 @@ export class RpgGui {
229
243
  * This should be called after VueGui is mounted
230
244
  */
231
245
  _initializeVueComponents() {
232
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
233
- // Initialize all extraGuis in the Vue instance
234
- this.extraGuis.forEach(gui => {
235
- this.vueGuiInstance.vm.gui[gui.name] = {
236
- name: gui.name,
237
- display: gui.display(),
238
- data: gui.data(),
239
- attachToSprite: gui.attachToSprite || false
240
- };
241
- });
242
-
243
- // Trigger Vue reactivity
244
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
245
- }
246
+ this.vueGuiInstance?.initializeGuiStates?.(
247
+ this.extraGuis.map(gui => this.toGuiState(gui))
248
+ );
246
249
  }
247
250
 
248
251
  guiInteraction(guiId: string, name: string, data: any) {
@@ -261,9 +264,12 @@ export class RpgGui {
261
264
  });
262
265
  }
263
266
 
264
- guiClose(guiId: string, data?: any) {
267
+ guiClose(guiId: string, data?: any, guiOpenId?: unknown) {
268
+ const normalizedOpenId =
269
+ typeof guiOpenId === "string" && guiOpenId.length > 0 ? guiOpenId : undefined;
265
270
  this.webSocket.emit("gui.exit", {
266
271
  guiId,
272
+ guiOpenId: normalizedOpenId,
267
273
  data,
268
274
  });
269
275
  }
@@ -301,35 +307,47 @@ export class RpgGui {
301
307
  * });
302
308
  * ```
303
309
  */
304
- add(gui: GuiOptions) {
305
- const guiId = gui.name || gui.id;
310
+ add(gui: GuiOptions | any) {
311
+ const component = this.resolveComponent(gui);
312
+ const guiId = this.resolveGuiId(gui, component);
306
313
  if (!guiId) {
307
314
  throw new Error("GUI must have a name or id");
308
315
  }
316
+ const attachToSprite = this.resolveAttachToSprite(gui, component);
309
317
  const guiInstance: GuiInstance = {
310
318
  name: guiId,
311
- component: gui.component,
312
- display: signal(gui.display || false),
313
- data: signal(gui.data || {}),
319
+ component,
320
+ display: signal<boolean>(gui.display || false),
321
+ data: signal<any>(gui.data || {}),
322
+ openId: undefined,
314
323
  autoDisplay: gui.autoDisplay || false,
315
324
  dependencies: gui.dependencies ? gui.dependencies() : [],
316
- attachToSprite: gui.attachToSprite || false,
325
+ attachToSprite,
317
326
  };
318
327
 
319
- // Accept both CanvasEngine components (.ce) and Vue components
320
- // Vue components will be handled by VueGui if available
321
- if (typeof gui.component !== 'function') {
322
- guiInstance.component = gui;
323
- this.extraGuis.push(guiInstance);
328
+ if (this.isVueComponentInstance(guiInstance)) {
329
+ this.removeCanvasGui(guiId);
330
+ const existingIndex = this.extraGuis.findIndex(existing => existing.name === guiId);
331
+ if (existingIndex >= 0) {
332
+ this.extraGuis[existingIndex].subscription?.unsubscribe();
333
+ this.extraGuis[existingIndex] = guiInstance;
334
+ } else {
335
+ this.extraGuis.push(guiInstance);
336
+ }
337
+
338
+ this._initializeVueComponents();
324
339
 
325
- // Auto display Vue components if enabled
326
340
  if (guiInstance.autoDisplay) {
327
- this._notifyVueGui(guiId, true, gui.data || {});
341
+ this.display(guiId, gui.data);
342
+ } else {
343
+ this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());
328
344
  }
329
345
  return;
330
346
  }
331
347
 
348
+ this.removeVueGui(guiId);
332
349
  this.gui()[guiId] = guiInstance;
350
+ this._initializeVueComponents();
333
351
 
334
352
  // Auto display if enabled and it's a CanvasEngine component
335
353
  if (guiInstance.autoDisplay && typeof gui.component === 'function') {
@@ -357,8 +375,15 @@ export class RpgGui {
357
375
  * ```
358
376
  */
359
377
  getAttachedGuis(): GuiInstance[] {
360
- const allGuis = this.getAll();
361
- return Object.values(allGuis).filter(gui => gui.attachToSprite === true);
378
+ return Object.values(this.gui()).filter(gui => gui.attachToSprite === true);
379
+ }
380
+
381
+ getVueGuis(): GuiInstance[] {
382
+ return [...this.extraGuis];
383
+ }
384
+
385
+ getAttachedVueGuis(): GuiInstance[] {
386
+ return this.extraGuis.filter(gui => gui.attachToSprite === true);
362
387
  }
363
388
 
364
389
  /**
@@ -418,7 +443,7 @@ export class RpgGui {
418
443
  * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);
419
444
  * ```
420
445
  */
421
- display(id: string, data = {}, dependencies: Signal[] = []) {
446
+ display(id: string, data = {}, dependencies: Signal[] = [], openId?: string) {
422
447
  if (!this.exists(id)) {
423
448
  throw throwError(id);
424
449
  }
@@ -430,8 +455,9 @@ export class RpgGui {
430
455
 
431
456
  if (isVueComponent) {
432
457
  // Handle Vue component display
433
- this._handleVueComponentDisplay(id, data, dependencies, guiInstance);
458
+ this._handleVueComponentDisplay(id, data, dependencies, guiInstance, openId);
434
459
  } else {
460
+ guiInstance.openId = openId;
435
461
  guiInstance.data.set(data);
436
462
  guiInstance.display.set(true);
437
463
  }
@@ -451,7 +477,7 @@ export class RpgGui {
451
477
  * @param dependencies - Runtime dependencies
452
478
  * @param guiInstance - GUI instance
453
479
  */
454
- private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {
480
+ private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance, openId?: string) {
455
481
  // Unsubscribe from previous subscription if exists
456
482
  if (guiInstance.subscription) {
457
483
  guiInstance.subscription.unsubscribe();
@@ -461,7 +487,7 @@ export class RpgGui {
461
487
  // Use runtime dependencies or config dependencies
462
488
  const deps = dependencies.length > 0
463
489
  ? dependencies
464
- : (guiInstance.dependencies ? guiInstance.dependencies() : []);
490
+ : (guiInstance.dependencies ?? []);
465
491
 
466
492
  if (deps.length > 0) {
467
493
  // Subscribe to dependencies
@@ -469,6 +495,7 @@ export class RpgGui {
469
495
  deps.map(dependency => dependency.observable)
470
496
  ).subscribe((values) => {
471
497
  if (values.every(value => value !== undefined)) {
498
+ guiInstance.openId = openId;
472
499
  guiInstance.data.set(data);
473
500
  guiInstance.display.set(true);
474
501
  this._notifyVueGui(id, true, data);
@@ -478,6 +505,7 @@ export class RpgGui {
478
505
  }
479
506
 
480
507
  // No dependencies, display immediately
508
+ guiInstance.openId = openId;
481
509
  guiInstance.data.set(data);
482
510
  guiInstance.display.set(true);
483
511
  this._notifyVueGui(id, true, data);
@@ -510,6 +538,7 @@ export class RpgGui {
510
538
  }
511
539
 
512
540
  guiInstance.display.set(false)
541
+ guiInstance.openId = undefined;
513
542
 
514
543
  // Check if it's a Vue component and notify VueGui
515
544
  const isVueComponent = this.extraGuis.some(gui => gui.name === id);
@@ -522,6 +551,49 @@ export class RpgGui {
522
551
  return this.extraGuis.some(gui => gui.name === id);
523
552
  }
524
553
 
554
+ private isVueComponentInstance(gui: GuiInstance) {
555
+ return typeof gui.component !== "function";
556
+ }
557
+
558
+ private removeCanvasGui(guiId: string) {
559
+ const current = this.gui();
560
+ if (!(guiId in current)) return;
561
+ const next = { ...current };
562
+ delete next[guiId];
563
+ this.gui.set(next);
564
+ }
565
+
566
+ private removeVueGui(guiId: string) {
567
+ const removed = this.extraGuis.filter(existing => existing.name === guiId);
568
+ removed.forEach(gui => gui.subscription?.unsubscribe());
569
+ if (removed.length > 0) {
570
+ this.extraGuis = this.extraGuis.filter(existing => existing.name !== guiId);
571
+ }
572
+ }
573
+
574
+ private resolveComponent(gui: GuiOptions | any) {
575
+ return gui?.component ?? gui;
576
+ }
577
+
578
+ private resolveGuiId(gui: GuiOptions | any, component: any) {
579
+ return gui?.name || gui?.id || component?.name || component?.__name;
580
+ }
581
+
582
+ private resolveAttachToSprite(gui: GuiOptions | any, component: any) {
583
+ return !!(gui?.attachToSprite || gui?.rpgAttachToSprite || component?.attachToSprite || component?.rpgAttachToSprite);
584
+ }
585
+
586
+ private toGuiState(gui: GuiInstance, display = gui.display(), data = gui.data()): GuiState {
587
+ return {
588
+ name: gui.name,
589
+ component: gui.component,
590
+ display,
591
+ data,
592
+ openId: gui.openId,
593
+ attachToSprite: gui.attachToSprite || false,
594
+ };
595
+ }
596
+
525
597
  private clearPendingActions(guiId: string) {
526
598
  this.pendingActions.delete(guiId);
527
599
  }
package/src/Resource.ts CHANGED
@@ -64,7 +64,7 @@ export class RpgResource {
64
64
  // Extract image path from spritesheet
65
65
  const imageLink = spritesheet?.image || spritesheet?.imageSource || undefined;
66
66
  if (imageLink) {
67
- RpgResource._spritesheets.set(id, imageLink);
67
+ RpgResource._spritesheets.set(String(id), imageLink);
68
68
  }
69
69
  });
70
70
 
@@ -147,4 +147,3 @@ export class RpgResource {
147
147
  return RpgResource._sounds;
148
148
  }
149
149
  }
150
-
package/src/RpgClient.ts CHANGED
@@ -2,11 +2,49 @@ import { ComponentFunction, Signal } from 'canvasengine'
2
2
  import { RpgClientEngine } from './RpgClientEngine'
3
3
  import { Loader, Container } from 'pixi.js'
4
4
  import { RpgClientObject } from './Game/Object'
5
- import { type MapPhysicsEntityContext, type MapPhysicsInitContext } from '@rpgjs/common'
5
+ import type { RpgClientEvent } from './Game/Event'
6
+ import { type I18nMessages, type MapPhysicsEntityContext, type MapPhysicsInitContext, type RpgActionName } from '@rpgjs/common'
7
+ import type {
8
+ ClientProjectileSpawn,
9
+ RenderedProjectileProps,
10
+ } from './Game/ProjectileManager'
11
+ import type { ClientVisualMap } from './Game/ClientVisuals'
12
+ import type {
13
+ RpgInteractionBehavior,
14
+ RpgInteractionMatcher,
15
+ } from './services/interactions'
6
16
 
7
17
  type RpgClass<T = any> = new (...args: any[]) => T
8
18
  type RpgComponent = RpgClientObject
9
19
  type SceneMap = Container
20
+ export type SpriteComponentConfig = ComponentFunction | {
21
+ component: ComponentFunction
22
+ props?: Record<string, any> | ((object: RpgClientObject) => Record<string, any>)
23
+ data?: Record<string, any> | ((object: RpgClientObject) => Record<string, any>)
24
+ dependencies?: (object: RpgClientObject) => any[]
25
+ }
26
+
27
+ export type EventComponentSprite = RpgClientEvent & Record<string, any>
28
+
29
+ export type EventComponentConfig = ComponentFunction | {
30
+ component: ComponentFunction
31
+ props?: Record<string, any> | ((event: EventComponentSprite) => Record<string, any>)
32
+ data?: Record<string, any> | ((event: EventComponentSprite) => Record<string, any>)
33
+ dependencies?: (event: EventComponentSprite) => any[]
34
+ renderGraphic?: boolean
35
+ }
36
+
37
+ export interface RpgSpriteBeforeRemoveContext {
38
+ reason?: string
39
+ data?: any
40
+ transition?: {
41
+ animation?: string
42
+ graphic?: string | string[]
43
+ duration?: number
44
+ effect?: string
45
+ }
46
+ timeoutMs?: number
47
+ }
10
48
 
11
49
  export interface RpgClientEngineHooks {
12
50
  /**
@@ -28,13 +66,14 @@ export interface RpgClientEngineHooks {
28
66
  /**
29
67
  * Recover keys from the pressed keyboard
30
68
  *
31
- * @prop { (engine: RpgClientEngine, obj: { input: string, playerId: number }) => any } [onInput]
69
+ * @prop { (engine: RpgClientEngine, obj: { input: string | number, action?: string | number, data?: any, playerId: number }) => any } [onInput]
32
70
  * @memberof RpgEngineHooks
33
71
  */
34
- onInput?: (engine: RpgClientEngine, obj: { input: string, playerId: number }) => any
72
+ onInput?: (engine: RpgClientEngine, obj: { input: RpgActionName, action?: RpgActionName, data?: any, playerId: number }) => any
35
73
 
36
74
  /**
37
- * Called when the user is connected to the server
75
+ * Called when the user is connected to the server. In MMORPG mode, this
76
+ * runs after the server sends the RPGJS connection acceptance packet.
38
77
  *
39
78
  * @prop { (engine: RpgClientEngine, socket: any) => any } [onConnected]
40
79
  * @memberof RpgEngineHooks
@@ -50,7 +89,8 @@ export interface RpgClientEngineHooks {
50
89
  onDisconnect?: (engine: RpgClientEngine, reason: any, socket: any) => any
51
90
 
52
91
  /**
53
- * Called when there was a connection error
92
+ * Called when there was a connection error. In MMORPG mode, this also runs
93
+ * when server-side auth refuses the connection.
54
94
  *
55
95
  * @prop { (engine: RpgClientEngine, err: any, socket: any) => any } [onConnectError]
56
96
  * @memberof RpgEngineHooks
@@ -81,7 +121,7 @@ export interface RpgSpriteHooks {
81
121
  * }
82
122
  * ```
83
123
  */
84
- componentsBehind?: ComponentFunction[]
124
+ componentsBehind?: SpriteComponentConfig[]
85
125
 
86
126
  /**
87
127
  * Array of components to render in front of the sprite
@@ -96,7 +136,53 @@ export interface RpgSpriteHooks {
96
136
  * }
97
137
  * ```
98
138
  */
99
- componentsInFront?: ComponentFunction[]
139
+ componentsInFront?: SpriteComponentConfig[]
140
+
141
+ /**
142
+ * Reusable sprite components addressable by server-side component definitions.
143
+ *
144
+ * The server sends only the component id and serializable props. The client
145
+ * registry maps that id to the CanvasEngine component that renders it.
146
+ *
147
+ * @prop {Record<string, ComponentFunction>} [components]
148
+ * @memberof RpgSpriteHooks
149
+ * @example
150
+ * ```ts
151
+ * import GuildBadge from './components/guild-badge.ce'
152
+ *
153
+ * const sprite: RpgSpriteHooks = {
154
+ * components: {
155
+ * guildBadge: GuildBadge
156
+ * }
157
+ * }
158
+ * ```
159
+ */
160
+ components?: Record<string, ComponentFunction>
161
+
162
+ /**
163
+ * Resolve a custom CanvasEngine component for a specific event.
164
+ *
165
+ * The component always receives the synced event object as the `sprite` prop.
166
+ * Custom props are merged in addition to `sprite`, but cannot replace it.
167
+ * Return `null` or `undefined` to keep the default graphic renderer.
168
+ *
169
+ * @prop { (event: EventComponentSprite) => EventComponentConfig | null | undefined } [eventComponent]
170
+ * @memberof RpgSpriteHooks
171
+ * @example
172
+ * ```ts
173
+ * import ChestEvent from './components/chest-event.ce'
174
+ *
175
+ * const sprite: RpgSpriteHooks = {
176
+ * eventComponent(sprite) {
177
+ * if (sprite.name === 'CHEST') {
178
+ * return ChestEvent
179
+ * }
180
+ * return null
181
+ * }
182
+ * }
183
+ * ```
184
+ */
185
+ eventComponent?: (event: EventComponentSprite) => EventComponentConfig | null | undefined
100
186
 
101
187
  /**
102
188
  * As soon as the sprite is initialized
@@ -114,6 +200,21 @@ export interface RpgSpriteHooks {
114
200
  */
115
201
  onDestroy?: (sprite: RpgComponent) => any
116
202
 
203
+ /**
204
+ * Called when a sprite removal is requested, before it disappears from the scene.
205
+ *
206
+ * Return a promise to keep the sprite visible while an animation, effect, or
207
+ * sound transition is running. The server still owns gameplay removal and
208
+ * uses the timeout carried by the remove request as a safety limit.
209
+ *
210
+ * @prop { (sprite: RpgSprite, context: RpgSpriteBeforeRemoveContext) => any } [onBeforeRemove]
211
+ * @memberof RpgSpriteHooks
212
+ */
213
+ onBeforeRemove?: (
214
+ sprite: RpgComponent,
215
+ context: RpgSpriteBeforeRemoveContext
216
+ ) => any
217
+
117
218
  /**
118
219
  * As soon as a data is changed on the server side (the name for example), you are able to know the new data but also the old data.
119
220
  *
@@ -191,6 +292,14 @@ export interface RpgSceneHooks<Scene> {
191
292
  }
192
293
 
193
294
  export interface RpgSceneMapHooks extends RpgSceneHooks<SceneMap> {
295
+ /**
296
+ * Root CanvasEngine component used to render the RPG scene map.
297
+ *
298
+ * Use the exported `SceneMap` component inside your custom component to
299
+ * keep the default map rendering and compose additional scene children.
300
+ */
301
+ component?: ComponentFunction
302
+
194
303
  /**
195
304
  * The map and resources are being loaded
196
305
  *
@@ -235,7 +344,37 @@ export interface RpgSceneMapHooks extends RpgSceneHooks<SceneMap> {
235
344
  onPhysicsReset?: (scene: SceneMap) => any
236
345
  }
237
346
 
347
+ export interface RpgProjectileHooks {
348
+ /**
349
+ * CanvasEngine components used to render server-authoritative projectiles.
350
+ */
351
+ components?: Record<string, ComponentFunction>
352
+
353
+ /**
354
+ * Called when a projectile spawn batch is received from the server.
355
+ */
356
+ onSpawn?: (projectile: ClientProjectileSpawn) => any
357
+
358
+ /**
359
+ * Called when the server confirms a projectile impact.
360
+ */
361
+ onImpact?: (projectile: RenderedProjectileProps | null) => any
362
+
363
+ /**
364
+ * Called when the server destroys a projectile.
365
+ */
366
+ onDestroy?: (projectile: RenderedProjectileProps | null) => any
367
+ }
368
+
238
369
  export interface RpgClient {
370
+ /**
371
+ * Default translations owned by this client module.
372
+ *
373
+ * Game-level translations provided with `provideI18n()` override module
374
+ * translations when they share the same locale and key.
375
+ */
376
+ i18n?: I18nMessages
377
+
239
378
  /**
240
379
  * Add hooks to the player or engine. All modules can listen to the hook
241
380
  *
@@ -485,6 +624,13 @@ export interface RpgClient {
485
624
  * ```
486
625
  */
487
626
  attachToSprite?: boolean
627
+ /**
628
+ * Vue v4 compatibility alias for `attachToSprite`.
629
+ *
630
+ * Prefer `attachToSprite` in v5 projects. This is read by `@rpgjs/vue`
631
+ * for Vue GUI components migrated from the v4 GUI API.
632
+ */
633
+ rpgAttachToSprite?: boolean
488
634
  } | any)[],
489
635
 
490
636
  /**
@@ -563,33 +709,36 @@ export interface RpgClient {
563
709
  * */
564
710
  sprite?: RpgSpriteHooks
565
711
 
566
- /**
567
- * Reference the scenes of the game. Here you can put your own class that inherits RpgSceneMap
712
+ /**
713
+ * Reference the scenes of the game.
568
714
  *
569
715
  * ```ts
570
716
  * import { RpgSceneMapHooks, RpgClient, defineModule } from '@rpgjs/client'
717
+ * import MyScene from './my-scene.ce'
571
718
  *
572
719
  * export const sceneMap: RpgSceneMapHooks = {
573
- *
720
+ * component: MyScene
574
721
  * }
575
722
  *
576
723
  * defineModule<RpgClient>({
577
- * scenes: {
578
- * // If you put the RpgSceneMap scene, Thhe key is called mandatory `map`
579
- * map: sceneMap
580
- * }
724
+ * sceneMap
581
725
  * })
582
726
  * ```
583
727
  *
584
- * @prop { [sceneName: string]: RpgSceneMapHooks } [scenes]
728
+ * @prop {RpgSceneMapHooks} [sceneMap]
585
729
  * @memberof RpgClient
586
730
  * */
731
+ sceneMap?: RpgSceneMapHooks
732
+
733
+ /**
734
+ * Legacy scene map hook container.
735
+ *
736
+ * Prefer `sceneMap` for new code.
737
+ */
587
738
  scenes?: {
588
739
  map: RpgSceneMapHooks
589
740
  }
590
741
 
591
- sceneMap?: RpgSceneMapHooks
592
-
593
742
  /**
594
743
  * Array containing the list of component animations
595
744
  * Each element defines a temporary component to display for animations like hits, effects, etc.
@@ -620,4 +769,58 @@ export interface RpgClient {
620
769
  id: string,
621
770
  component: ComponentFunction
622
771
  }[]
772
+
773
+ /**
774
+ * Named client-side visual macros.
775
+ *
776
+ * Use client visuals when the server needs to trigger a group of existing
777
+ * client visual primitives at once, such as a flash, damage text, sound,
778
+ * component animation, and camera shake. The server sends only the visual
779
+ * name and a serializable payload; the rendering details live on the client.
780
+ *
781
+ * For a single sound, flash, or component animation, prefer the direct
782
+ * server APIs (`playSound`, `flash`, `showComponentAnimation`). Client
783
+ * visuals are meant to group several visual operations and reduce bandwidth.
784
+ *
785
+ * ```ts
786
+ * import { defineModule, RpgClient } from '@rpgjs/client'
787
+ *
788
+ * export default defineModule<RpgClient>({
789
+ * clientVisuals: {
790
+ * hit({ target, data }, helpers) {
791
+ * helpers.flash(target, { type: 'tint', tint: 'red' })
792
+ * helpers.showHit(target, `-${data.damage}`)
793
+ * helpers.sound('hit')
794
+ * }
795
+ * }
796
+ * })
797
+ * ```
798
+ *
799
+ * @prop {Record<string, ClientVisualHandler>} [clientVisuals]
800
+ * @memberof RpgClient
801
+ */
802
+ clientVisuals?: ClientVisualMap
803
+
804
+ /**
805
+ * Client-side projectile rendering configuration.
806
+ *
807
+ * Register a CanvasEngine component per projectile type. The server sends
808
+ * compact spawn/impact/destroy events and the client predicts x/y locally.
809
+ */
810
+ projectiles?: RpgProjectileHooks
811
+
812
+ /**
813
+ * Client-only pointer interactions attached to sprites.
814
+ *
815
+ * Use this for hover popovers, selection, drag previews, cursor changes, and
816
+ * explicit mouse-driven gameplay actions. Pointer feedback stays local unless
817
+ * the behavior calls `ctx.action(...)`.
818
+ */
819
+ interactions?:
820
+ | ((engine: RpgClientEngine) => void)
821
+ | {
822
+ setup?: (engine: RpgClientEngine) => void
823
+ load?: (engine: RpgClientEngine) => void
824
+ use?: Array<[RpgInteractionMatcher, RpgInteractionBehavior | ComponentFunction]>
825
+ }
623
826
  }