@rpgjs/client 5.0.0-alpha.9 → 5.0.0-beta.10

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 (347) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +19 -0
  3. package/dist/Game/AnimationManager.d.ts +8 -0
  4. package/dist/Game/AnimationManager.js +35 -0
  5. package/dist/Game/AnimationManager.js.map +1 -0
  6. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  7. package/dist/Game/Event.d.ts +1 -1
  8. package/dist/Game/Event.js +12 -0
  9. package/dist/Game/Event.js.map +1 -0
  10. package/dist/Game/Map.d.ts +31 -2
  11. package/dist/Game/Map.js +138 -0
  12. package/dist/Game/Map.js.map +1 -0
  13. package/dist/Game/Object.d.ts +189 -0
  14. package/dist/Game/Object.js +255 -0
  15. package/dist/Game/Object.js.map +1 -0
  16. package/dist/Game/Player.d.ts +1 -1
  17. package/dist/Game/Player.js +12 -0
  18. package/dist/Game/Player.js.map +1 -0
  19. package/dist/Gui/Gui.d.ts +192 -7
  20. package/dist/Gui/Gui.js +475 -0
  21. package/dist/Gui/Gui.js.map +1 -0
  22. package/dist/Gui/Gui.spec.d.ts +1 -0
  23. package/dist/Gui/NotificationManager.d.ts +23 -0
  24. package/dist/Gui/NotificationManager.js +49 -0
  25. package/dist/Gui/NotificationManager.js.map +1 -0
  26. package/dist/Resource.d.ts +97 -0
  27. package/dist/Resource.js +133 -0
  28. package/dist/Resource.js.map +1 -0
  29. package/dist/RpgClient.d.ts +295 -13
  30. package/dist/RpgClientEngine.d.ts +671 -15
  31. package/dist/RpgClientEngine.js +1442 -0
  32. package/dist/RpgClientEngine.js.map +1 -0
  33. package/dist/Sound.d.ts +199 -0
  34. package/dist/Sound.js +167 -0
  35. package/dist/Sound.js.map +1 -0
  36. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js +9 -0
  37. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js +6 -0
  38. package/dist/components/animations/animation.ce.js +23 -0
  39. package/dist/components/animations/animation.ce.js.map +1 -0
  40. package/dist/components/animations/hit.ce.js +64 -0
  41. package/dist/components/animations/hit.ce.js.map +1 -0
  42. package/dist/components/animations/index.d.ts +4 -0
  43. package/dist/components/animations/index.js +11 -0
  44. package/dist/components/animations/index.js.map +1 -0
  45. package/dist/components/character.ce.js +572 -0
  46. package/dist/components/character.ce.js.map +1 -0
  47. package/dist/components/dynamics/bar.ce.js +96 -0
  48. package/dist/components/dynamics/bar.ce.js.map +1 -0
  49. package/dist/components/dynamics/image.ce.js +23 -0
  50. package/dist/components/dynamics/image.ce.js.map +1 -0
  51. package/dist/components/dynamics/parse-value.d.ts +4 -0
  52. package/dist/components/dynamics/parse-value.js +63 -0
  53. package/dist/components/dynamics/parse-value.js.map +1 -0
  54. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  55. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  56. package/dist/components/dynamics/shape-utils.js +73 -0
  57. package/dist/components/dynamics/shape-utils.js.map +1 -0
  58. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  59. package/dist/components/dynamics/shape.ce.js +83 -0
  60. package/dist/components/dynamics/shape.ce.js.map +1 -0
  61. package/dist/components/dynamics/text.ce.js +50 -0
  62. package/dist/components/dynamics/text.ce.js.map +1 -0
  63. package/dist/components/gui/box.ce.js +26 -0
  64. package/dist/components/gui/box.ce.js.map +1 -0
  65. package/dist/components/gui/dialogbox/index.ce.js +198 -0
  66. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  67. package/dist/components/gui/gameover.ce.js +169 -0
  68. package/dist/components/gui/gameover.ce.js.map +1 -0
  69. package/dist/components/gui/hud/hud.ce.js +83 -0
  70. package/dist/components/gui/hud/hud.ce.js.map +1 -0
  71. package/dist/components/gui/index.d.ts +15 -3
  72. package/dist/components/gui/index.js +14 -0
  73. package/dist/components/gui/menu/equip-menu.ce.js +427 -0
  74. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -0
  75. package/dist/components/gui/menu/exit-menu.ce.js +55 -0
  76. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -0
  77. package/dist/components/gui/menu/items-menu.ce.js +326 -0
  78. package/dist/components/gui/menu/items-menu.ce.js.map +1 -0
  79. package/dist/components/gui/menu/main-menu.ce.js +399 -0
  80. package/dist/components/gui/menu/main-menu.ce.js.map +1 -0
  81. package/dist/components/gui/menu/options-menu.ce.js +49 -0
  82. package/dist/components/gui/menu/options-menu.ce.js.map +1 -0
  83. package/dist/components/gui/menu/skills-menu.ce.js +102 -0
  84. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -0
  85. package/dist/components/gui/mobile/index.d.ts +8 -0
  86. package/dist/components/gui/mobile/index.js +21 -0
  87. package/dist/components/gui/mobile/index.js.map +1 -0
  88. package/dist/components/gui/mobile/mobile.ce.js +79 -0
  89. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  90. package/dist/components/gui/notification/notification.ce.js +62 -0
  91. package/dist/components/gui/notification/notification.ce.js.map +1 -0
  92. package/dist/components/gui/save-load.ce.js +211 -0
  93. package/dist/components/gui/save-load.ce.js.map +1 -0
  94. package/dist/components/gui/shop/shop.ce.js +614 -0
  95. package/dist/components/gui/shop/shop.ce.js.map +1 -0
  96. package/dist/components/gui/title-screen.ce.js +164 -0
  97. package/dist/components/gui/title-screen.ce.js.map +1 -0
  98. package/dist/components/index.d.ts +1 -0
  99. package/dist/components/index.js +4 -0
  100. package/dist/components/player-components-utils.d.ts +67 -0
  101. package/dist/components/player-components-utils.js +162 -0
  102. package/dist/components/player-components-utils.js.map +1 -0
  103. package/dist/components/player-components-utils.spec.d.ts +1 -0
  104. package/dist/components/player-components.ce.js +188 -0
  105. package/dist/components/player-components.ce.js.map +1 -0
  106. package/dist/components/prebuilt/hp-bar.ce.js +113 -0
  107. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  108. package/dist/components/prebuilt/index.d.ts +19 -0
  109. package/dist/components/prebuilt/index.js +2 -0
  110. package/dist/components/prebuilt/light-halo.ce.js +70 -0
  111. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  112. package/dist/components/scenes/canvas.ce.js +196 -0
  113. package/dist/components/scenes/canvas.ce.js.map +1 -0
  114. package/dist/components/scenes/draw-map.ce.js +79 -0
  115. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  116. package/dist/components/scenes/event-layer.ce.js +29 -0
  117. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  118. package/dist/core/inject.js +18 -0
  119. package/dist/core/inject.js.map +1 -0
  120. package/dist/core/setup.js +16 -0
  121. package/dist/core/setup.js.map +1 -0
  122. package/dist/decorators/spritesheet.d.ts +1 -0
  123. package/dist/decorators/spritesheet.js +11 -0
  124. package/dist/decorators/spritesheet.js.map +1 -0
  125. package/dist/index.d.ts +16 -1
  126. package/dist/index.js +45 -14
  127. package/dist/module.d.ts +43 -4
  128. package/dist/module.js +179 -0
  129. package/dist/module.js.map +1 -0
  130. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js +167 -0
  131. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js.map +1 -0
  132. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js +239 -0
  133. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js.map +1 -0
  134. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  135. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  136. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js +696 -0
  137. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js.map +1 -0
  138. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js +44 -0
  139. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js +241 -0
  141. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js.map +1 -0
  142. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js +115 -0
  143. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  144. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js +401 -0
  145. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  146. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +2 -0
  147. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js +3756 -0
  148. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  149. package/dist/presets/animation.d.ts +31 -0
  150. package/dist/presets/animation.js +39 -0
  151. package/dist/presets/animation.js.map +1 -0
  152. package/dist/presets/faceset.d.ts +30 -0
  153. package/dist/presets/faceset.js +51 -0
  154. package/dist/presets/faceset.js.map +1 -0
  155. package/dist/presets/icon.d.ts +20 -0
  156. package/dist/presets/icon.js +15 -0
  157. package/dist/presets/icon.js.map +1 -0
  158. package/dist/presets/index.d.ts +123 -0
  159. package/dist/presets/index.js +17 -0
  160. package/dist/presets/index.js.map +1 -0
  161. package/dist/presets/lpc.d.ts +89 -0
  162. package/dist/presets/lpc.js +98 -0
  163. package/dist/presets/lpc.js.map +1 -0
  164. package/dist/presets/rmspritesheet.js +42 -0
  165. package/dist/presets/rmspritesheet.js.map +1 -0
  166. package/dist/services/AbstractSocket.d.ts +9 -5
  167. package/dist/services/AbstractSocket.js +11 -0
  168. package/dist/services/AbstractSocket.js.map +1 -0
  169. package/dist/services/keyboardControls.d.ts +15 -0
  170. package/dist/services/keyboardControls.js +23 -0
  171. package/dist/services/keyboardControls.js.map +1 -0
  172. package/dist/services/loadMap.d.ts +6 -0
  173. package/dist/services/loadMap.js +123 -0
  174. package/dist/services/loadMap.js.map +1 -0
  175. package/dist/services/mmorpg.d.ts +21 -9
  176. package/dist/services/mmorpg.js +136 -0
  177. package/dist/services/mmorpg.js.map +1 -0
  178. package/dist/services/save.d.ts +19 -0
  179. package/dist/services/save.js +77 -0
  180. package/dist/services/save.js.map +1 -0
  181. package/dist/services/save.spec.d.ts +1 -0
  182. package/dist/services/standalone.d.ts +67 -7
  183. package/dist/services/standalone.js +168 -0
  184. package/dist/services/standalone.js.map +1 -0
  185. package/dist/utils/getEntityProp.d.ts +39 -0
  186. package/dist/utils/getEntityProp.js +53 -0
  187. package/dist/utils/getEntityProp.js.map +1 -0
  188. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  189. package/dist/utils/readPropValue.d.ts +2 -0
  190. package/dist/utils/readPropValue.js +13 -0
  191. package/dist/utils/readPropValue.js.map +1 -0
  192. package/package.json +14 -11
  193. package/src/Game/AnimationManager.spec.ts +30 -0
  194. package/src/Game/AnimationManager.ts +33 -0
  195. package/src/Game/Event.ts +1 -1
  196. package/src/Game/Map.ts +184 -3
  197. package/src/Game/Object.ts +409 -14
  198. package/src/Game/Player.ts +1 -1
  199. package/src/Gui/Gui.spec.ts +273 -0
  200. package/src/Gui/Gui.ts +566 -23
  201. package/src/Gui/NotificationManager.ts +69 -0
  202. package/src/Resource.ts +149 -0
  203. package/src/RpgClient.ts +309 -14
  204. package/src/RpgClientEngine.ts +1790 -63
  205. package/src/Sound.ts +253 -0
  206. package/src/components/{effects → animations}/animation.ce +3 -6
  207. package/src/components/{effects → animations}/index.ts +1 -1
  208. package/src/components/character.ce +801 -59
  209. package/src/components/dynamics/bar.ce +87 -0
  210. package/src/components/dynamics/image.ce +20 -0
  211. package/src/components/dynamics/parse-value.spec.ts +83 -0
  212. package/src/components/dynamics/parse-value.ts +154 -0
  213. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  214. package/src/components/dynamics/shape-utils.ts +61 -0
  215. package/src/components/dynamics/shape.ce +89 -0
  216. package/src/components/dynamics/text.ce +68 -0
  217. package/src/components/gui/box.ce +17 -0
  218. package/src/components/gui/dialogbox/index.ce +213 -187
  219. package/src/components/gui/gameover.ce +158 -0
  220. package/src/components/gui/hud/hud.ce +61 -0
  221. package/src/components/gui/index.ts +30 -4
  222. package/src/components/gui/menu/equip-menu.ce +410 -0
  223. package/src/components/gui/menu/exit-menu.ce +41 -0
  224. package/src/components/gui/menu/items-menu.ce +317 -0
  225. package/src/components/gui/menu/main-menu.ce +294 -0
  226. package/src/components/gui/menu/options-menu.ce +35 -0
  227. package/src/components/gui/menu/skills-menu.ce +83 -0
  228. package/src/components/gui/mobile/index.ts +24 -0
  229. package/src/components/gui/mobile/mobile.ce +80 -0
  230. package/src/components/gui/notification/notification.ce +51 -0
  231. package/src/components/gui/save-load.ce +208 -0
  232. package/src/components/gui/shop/shop.ce +493 -0
  233. package/src/components/gui/title-screen.ce +163 -0
  234. package/src/components/index.ts +3 -0
  235. package/src/components/player-components-utils.spec.ts +109 -0
  236. package/src/components/player-components-utils.ts +205 -0
  237. package/src/components/player-components.ce +221 -0
  238. package/src/components/prebuilt/hp-bar.ce +255 -0
  239. package/src/components/prebuilt/index.ts +24 -0
  240. package/src/components/prebuilt/light-halo.ce +148 -0
  241. package/src/components/scenes/canvas.ce +185 -21
  242. package/src/components/scenes/draw-map.ce +55 -21
  243. package/src/components/scenes/event-layer.ce +8 -2
  244. package/src/components/scenes/transition.ce +60 -0
  245. package/src/core/setup.ts +2 -2
  246. package/src/decorators/spritesheet.ts +8 -0
  247. package/src/index.ts +17 -2
  248. package/src/module.ts +132 -10
  249. package/src/presets/animation.ts +46 -0
  250. package/src/presets/faceset.ts +60 -0
  251. package/src/presets/icon.ts +17 -0
  252. package/src/presets/index.ts +9 -1
  253. package/src/presets/lpc.ts +108 -0
  254. package/src/services/AbstractSocket.ts +10 -2
  255. package/src/services/keyboardControls.ts +20 -0
  256. package/src/services/loadMap.ts +3 -1
  257. package/src/services/mmorpg.ts +106 -12
  258. package/src/services/save.spec.ts +127 -0
  259. package/src/services/save.ts +103 -0
  260. package/src/services/standalone.ts +110 -18
  261. package/src/utils/getEntityProp.spec.ts +96 -0
  262. package/src/utils/getEntityProp.ts +88 -0
  263. package/src/utils/readPropValue.ts +16 -0
  264. package/vite.config.ts +4 -2
  265. package/dist/Game/EffectManager.d.ts +0 -5
  266. package/dist/components/effects/index.d.ts +0 -4
  267. package/dist/index.js.map +0 -1
  268. package/dist/index10.js +0 -8
  269. package/dist/index10.js.map +0 -1
  270. package/dist/index11.js +0 -10
  271. package/dist/index11.js.map +0 -1
  272. package/dist/index12.js +0 -8
  273. package/dist/index12.js.map +0 -1
  274. package/dist/index13.js +0 -17
  275. package/dist/index13.js.map +0 -1
  276. package/dist/index14.js +0 -107
  277. package/dist/index14.js.map +0 -1
  278. package/dist/index15.js +0 -50
  279. package/dist/index15.js.map +0 -1
  280. package/dist/index16.js +0 -191
  281. package/dist/index16.js.map +0 -1
  282. package/dist/index17.js +0 -9
  283. package/dist/index17.js.map +0 -1
  284. package/dist/index18.js +0 -387
  285. package/dist/index18.js.map +0 -1
  286. package/dist/index19.js +0 -31
  287. package/dist/index19.js.map +0 -1
  288. package/dist/index2.js +0 -181
  289. package/dist/index2.js.map +0 -1
  290. package/dist/index20.js +0 -24
  291. package/dist/index20.js.map +0 -1
  292. package/dist/index21.js +0 -2421
  293. package/dist/index21.js.map +0 -1
  294. package/dist/index22.js +0 -114
  295. package/dist/index22.js.map +0 -1
  296. package/dist/index23.js +0 -109
  297. package/dist/index23.js.map +0 -1
  298. package/dist/index24.js +0 -71
  299. package/dist/index24.js.map +0 -1
  300. package/dist/index25.js +0 -21
  301. package/dist/index25.js.map +0 -1
  302. package/dist/index26.js +0 -41
  303. package/dist/index26.js.map +0 -1
  304. package/dist/index27.js +0 -5
  305. package/dist/index27.js.map +0 -1
  306. package/dist/index28.js +0 -322
  307. package/dist/index28.js.map +0 -1
  308. package/dist/index29.js +0 -27
  309. package/dist/index29.js.map +0 -1
  310. package/dist/index3.js +0 -87
  311. package/dist/index3.js.map +0 -1
  312. package/dist/index30.js +0 -11
  313. package/dist/index30.js.map +0 -1
  314. package/dist/index31.js +0 -11
  315. package/dist/index31.js.map +0 -1
  316. package/dist/index32.js +0 -174
  317. package/dist/index32.js.map +0 -1
  318. package/dist/index33.js +0 -501
  319. package/dist/index33.js.map +0 -1
  320. package/dist/index34.js +0 -12
  321. package/dist/index34.js.map +0 -1
  322. package/dist/index35.js +0 -4403
  323. package/dist/index35.js.map +0 -1
  324. package/dist/index36.js +0 -316
  325. package/dist/index36.js.map +0 -1
  326. package/dist/index37.js +0 -61
  327. package/dist/index37.js.map +0 -1
  328. package/dist/index38.js +0 -20
  329. package/dist/index38.js.map +0 -1
  330. package/dist/index39.js +0 -20
  331. package/dist/index39.js.map +0 -1
  332. package/dist/index4.js +0 -67
  333. package/dist/index4.js.map +0 -1
  334. package/dist/index5.js +0 -16
  335. package/dist/index5.js.map +0 -1
  336. package/dist/index6.js +0 -17
  337. package/dist/index6.js.map +0 -1
  338. package/dist/index7.js +0 -39
  339. package/dist/index7.js.map +0 -1
  340. package/dist/index8.js +0 -108
  341. package/dist/index8.js.map +0 -1
  342. package/dist/index9.js +0 -76
  343. package/dist/index9.js.map +0 -1
  344. package/src/Game/EffectManager.ts +0 -20
  345. package/src/components/gui/dialogbox/itemMenu.ce +0 -23
  346. package/src/components/gui/dialogbox/selection.ce +0 -67
  347. /package/src/components/{effects → animations}/hit.ce +0 -0
@@ -0,0 +1,87 @@
1
+ <Container width={width} height={containerHeight} minWidth={width} minHeight={containerHeight}>
2
+ <Graphics width={width} height={containerHeight} draw={drawBar} />
3
+ @if (hasLabel) {
4
+ <Text text={labelText} x={labelPosition.x} y={labelPosition.y} size={labelSize} color={labelColor} />
5
+ }
6
+ </Container>
7
+
8
+ <script>
9
+ import { computed } from "canvasengine";
10
+ import { resolveDynamicValue } from "./parse-value";
11
+
12
+ const { object, current, max, style, text } = defineProps();
13
+
14
+ const read = (prop, fallback) => prop ? prop() : fallback;
15
+
16
+ const toNumber = (value, fallback = 0) => {
17
+ const resolved = resolveDynamicValue(value, object);
18
+ const num = typeof resolved === 'number' ? resolved : parseFloat(resolved);
19
+ return Number.isFinite(num) ? num : fallback;
20
+ };
21
+
22
+ const toColor = (value, fallback) => {
23
+ const resolved = resolveDynamicValue(value, object);
24
+ if (typeof resolved === 'number') return resolved;
25
+ if (typeof resolved === 'string' && resolved.startsWith('#')) {
26
+ return parseInt(resolved.slice(1), 16);
27
+ }
28
+ return resolved ?? fallback;
29
+ };
30
+
31
+ const config = computed(() => read(style, {}) ?? {});
32
+ const width = computed(() => toNumber(config().width, 50));
33
+ const height = computed(() => toNumber(config().height, 8));
34
+ const borderRadius = computed(() => toNumber(config().borderRadius, 3));
35
+ const borderWidth = computed(() => toNumber(config().borderWidth, 1));
36
+ const backgroundColor = computed(() => toColor(config().bgColor, 0x16213e));
37
+ const fillColor = computed(() => toColor(config().fillColor, 0x4ade80));
38
+ const borderColor = computed(() => toColor(config().borderColor, 0x4a5568));
39
+ const opacity = computed(() => Math.max(0, Math.min(1, toNumber(config().opacity, 1))));
40
+
41
+ const currentValue = computed(() => toNumber(read(current, 0), 0));
42
+ const maxValue = computed(() => Math.max(0, toNumber(read(max, 0), 0)));
43
+ const percent = computed(() => {
44
+ const max = maxValue();
45
+ if (max <= 0) return 0;
46
+ return Math.max(0, Math.min(1, currentValue() / max));
47
+ });
48
+
49
+ const fillWidth = computed(() => Math.max(0, width() * percent()));
50
+ const labelTemplate = computed(() => read(text, null));
51
+ const labelText = computed(() => {
52
+ const template = labelTemplate();
53
+ if (template == null || template === '') return '';
54
+
55
+ const value = String(template)
56
+ .replace(/\{\$current\}/g, String(currentValue()))
57
+ .replace(/\{\$max\}/g, String(maxValue()))
58
+ .replace(/\{\$percent\}/g, String(Math.round(percent() * 100)));
59
+
60
+ return String(resolveDynamicValue(value, object) ?? '');
61
+ });
62
+ const labelSize = computed(() => toNumber(config().fontSize, 10));
63
+ const hasLabel = computed(() => labelText().length > 0);
64
+ const labelOffset = computed(() => hasLabel() ? labelSize() + 2 : 0);
65
+ const containerHeight = computed(() => labelOffset() + height());
66
+ const labelColor = computed(() => toColor(config().textColor, 0xffffff));
67
+ const labelPosition = computed(() => ({
68
+ x: 0,
69
+ y: 0
70
+ }));
71
+
72
+ const drawBar = (g) => {
73
+ g.roundRect(0, labelOffset(), width(), height(), borderRadius());
74
+ g.fill({ color: backgroundColor(), alpha: opacity() });
75
+
76
+ const currentWidth = fillWidth();
77
+ if (currentWidth > 0) {
78
+ g.roundRect(0, labelOffset(), currentWidth, height(), borderRadius());
79
+ g.fill({ color: fillColor(), alpha: opacity() });
80
+ }
81
+
82
+ const strokeWidth = borderWidth();
83
+ if (strokeWidth <= 0) return;
84
+ g.roundRect(0, labelOffset(), width(), height(), borderRadius());
85
+ g.stroke({ color: borderColor(), width: strokeWidth, alpha: opacity() });
86
+ };
87
+ </script>
@@ -0,0 +1,20 @@
1
+ <Sprite sheet={sheet} />
2
+
3
+ <script>
4
+ import { computed } from "canvasengine";
5
+ import { RpgClientEngine } from "../../RpgClientEngine";
6
+ import { inject } from "../../core/inject";
7
+ import { resolveDynamicValue } from "./parse-value";
8
+
9
+ const { object, value } = defineProps();
10
+ const client = inject(RpgClientEngine);
11
+
12
+ const sheet = computed(() => {
13
+ const id = resolveDynamicValue(value?.(), object);
14
+ if (!id) return null;
15
+ return {
16
+ definition: client.getSpriteSheet(id),
17
+ playing: 'default'
18
+ };
19
+ });
20
+ </script>
@@ -0,0 +1,83 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { signal } from "canvasengine";
3
+ import { resolveDynamicProps, resolveDynamicValue } from "./parse-value";
4
+
5
+ describe("dynamic component values", () => {
6
+ test("resolves player properties and keeps bar placeholders for the bar renderer", () => {
7
+ const object = {
8
+ _name: signal("Alex"),
9
+ _speed: signal(4),
10
+ _canMove: signal(true),
11
+ hpSignal: signal(100),
12
+ _param: signal({ maxHp: 120 }),
13
+ get name() {
14
+ return this._name();
15
+ },
16
+ set name(value: string) {
17
+ this._name.set(value);
18
+ },
19
+ get speed() {
20
+ return this._speed();
21
+ },
22
+ set speed(value: number) {
23
+ this._speed.set(value);
24
+ },
25
+ get canMove() {
26
+ return this._canMove();
27
+ },
28
+ set canMove(value: boolean) {
29
+ this._canMove.set(value);
30
+ }
31
+ };
32
+
33
+ expect(resolveDynamicValue("HP: {hp}/{param.maxHp} {name} {speed} {canMove} {$current}", object)).toBe("HP: 100/120 Alex 4 true {$current}");
34
+ });
35
+
36
+ test("keeps resolved props reactive", () => {
37
+ const object = {
38
+ _name: signal("Alex"),
39
+ _speed: signal(4),
40
+ _canMove: signal(true),
41
+ hpSignal: signal(100),
42
+ _param: signal({ maxHp: 120 }),
43
+ get name() {
44
+ return this._name();
45
+ },
46
+ set name(value: string) {
47
+ this._name.set(value);
48
+ },
49
+ get speed() {
50
+ return this._speed();
51
+ },
52
+ set speed(value: number) {
53
+ this._speed.set(value);
54
+ },
55
+ get canMove() {
56
+ return this._canMove();
57
+ },
58
+ set canMove(value: boolean) {
59
+ this._canMove.set(value);
60
+ }
61
+ };
62
+ const props: any = resolveDynamicProps({
63
+ value: "HP: {hp} {name} {speed} {canMove}",
64
+ text: "{$current}/{$max} {name}",
65
+ style: {
66
+ width: "{hp}"
67
+ }
68
+ }, object);
69
+
70
+ expect(props.value()).toBe("HP: 100 Alex 4 true");
71
+ expect(props.text()).toBe("{$current}/{$max} Alex");
72
+ expect(props.style()).toEqual({ width: "100" });
73
+
74
+ object.hpSignal.set(10);
75
+ object.name = "Sam";
76
+ object.speed = 6;
77
+ object.canMove = false;
78
+
79
+ expect(props.value()).toBe("HP: 10 Sam 6 false");
80
+ expect(props.text()).toBe("{$current}/{$max} Sam");
81
+ expect(props.style()).toEqual({ width: "10" });
82
+ });
83
+ });
@@ -0,0 +1,154 @@
1
+ import { computed } from "canvasengine";
2
+
3
+ interface MatchResult {
4
+ property: string;
5
+ fullMatch: string;
6
+ index: number;
7
+ }
8
+
9
+ const readSignal = (value: any) => typeof value === 'function' ? value() : value;
10
+ const DYNAMIC_VALUE_PATTERN = /\{([^}]+)\}/g;
11
+
12
+ const hasDynamicValue = (value: any) => {
13
+ value = readSignal(value);
14
+ if (typeof value !== 'string') return false;
15
+ DYNAMIC_VALUE_PATTERN.lastIndex = 0;
16
+ return DYNAMIC_VALUE_PATTERN.test(value);
17
+ };
18
+
19
+ const resolveDynamicSnapshot = (value: any, object?: any): any => {
20
+ value = readSignal(value);
21
+
22
+ if (Array.isArray(value)) {
23
+ return value.map((entry) => resolveDynamicSnapshot(entry, object));
24
+ }
25
+
26
+ if (value && typeof value === 'object') {
27
+ return Object.fromEntries(
28
+ Object.entries(value).map(([key, entry]) => [key, resolveDynamicSnapshot(entry, object)])
29
+ );
30
+ }
31
+
32
+ return resolveDynamicValue(value, object);
33
+ };
34
+
35
+ export const getDynamicValue = (property: string, object?: any) => {
36
+ try {
37
+ const propertyPath = property.split('.');
38
+ let currentValue = object;
39
+
40
+ for (let j = 0; j < propertyPath.length; j++) {
41
+ let prop = propertyPath[j];
42
+
43
+ currentValue = readSignal(currentValue);
44
+
45
+ if (j === 0) {
46
+ if (prop === 'hp') prop = 'hpSignal';
47
+ if (prop === 'sp') prop = 'spSignal';
48
+ if (prop === 'param') prop = '_param';
49
+ if (prop === 'name' && currentValue && typeof currentValue === 'object' && '_name' in currentValue) {
50
+ prop = '_name';
51
+ }
52
+ if (prop === 'speed' && currentValue && typeof currentValue === 'object' && '_speed' in currentValue) {
53
+ prop = '_speed';
54
+ }
55
+ if (prop === 'canMove' && currentValue && typeof currentValue === 'object' && '_canMove' in currentValue) {
56
+ prop = '_canMove';
57
+ }
58
+ }
59
+
60
+ if (currentValue && typeof currentValue === 'object' && prop in currentValue) {
61
+ currentValue = currentValue[prop];
62
+ } else {
63
+ return undefined;
64
+ }
65
+ }
66
+
67
+ return readSignal(currentValue);
68
+ } catch (error) {
69
+ return undefined;
70
+ }
71
+ };
72
+
73
+ export const resolveDynamicValue = (value: any, object?: any): any => {
74
+ value = readSignal(value);
75
+
76
+ if (typeof value !== 'string') {
77
+ return value;
78
+ }
79
+
80
+ return value.replace(DYNAMIC_VALUE_PATTERN, (fullMatch, property) => {
81
+ const propertyValue = getDynamicValue(property, object);
82
+ if (propertyValue == null && property.startsWith('$')) return fullMatch;
83
+ return propertyValue != null ? String(propertyValue) : '';
84
+ });
85
+ };
86
+
87
+ const resolveDynamicProp = (value: any, object?: any): any => {
88
+ if (Array.isArray(value) || (value && typeof value === 'object' && typeof value !== 'function')) {
89
+ return computed(() => resolveDynamicSnapshot(value, object));
90
+ }
91
+
92
+ if (typeof value === 'function' || hasDynamicValue(value)) {
93
+ return computed(() => resolveDynamicValue(value, object));
94
+ }
95
+
96
+ return value;
97
+ };
98
+
99
+ export const resolveDynamicProps = (props: any, object?: any): any => {
100
+ props = readSignal(props);
101
+
102
+ if (Array.isArray(props)) {
103
+ return computed(() => resolveDynamicSnapshot(props, object));
104
+ }
105
+
106
+ if (props && typeof props === 'object') {
107
+ return Object.fromEntries(
108
+ Object.entries(props).map(([key, value]) => [key, resolveDynamicProp(value, object)])
109
+ );
110
+ }
111
+
112
+ return resolveDynamicProp(props, object);
113
+ };
114
+
115
+ export const parseDynamicValue = (value: any, object?: any) => {
116
+ if (typeof value !== 'string') {
117
+ return computed(() => String(value ?? ''));
118
+ }
119
+
120
+ // Find all dynamic references like {propertyName}
121
+ const matches: MatchResult[] = [];
122
+ let match;
123
+
124
+ DYNAMIC_VALUE_PATTERN.lastIndex = 0;
125
+ while ((match = DYNAMIC_VALUE_PATTERN.exec(value)) !== null) {
126
+ matches.push({
127
+ property: match[1],
128
+ fullMatch: match[0],
129
+ index: match.index!
130
+ });
131
+ }
132
+
133
+ // If no dynamic references found, return simple computed
134
+ if (matches.length === 0) {
135
+ return computed(() => value);
136
+ }
137
+
138
+ // Create computed that tracks all referenced signals
139
+ return computed(() => {
140
+ let result = value;
141
+
142
+ // Replace from end to start to preserve indices
143
+ for (let i = matches.length - 1; i >= 0; i--) {
144
+ const { property, fullMatch } = matches[i];
145
+
146
+ const currentValue = getDynamicValue(property, object);
147
+ const propertyValue = currentValue != null ? String(currentValue) : property.startsWith('$') ? fullMatch : '';
148
+
149
+ result = result.replace(fullMatch, propertyValue);
150
+ }
151
+
152
+ return result;
153
+ });
154
+ };
@@ -0,0 +1,46 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { getShapeBox, getShapePointBounds, translatePolygonPoints } from "./shape-utils";
3
+
4
+ describe("shape utilities", () => {
5
+ test("normalizes rectangles and circles around their rendered bounds", () => {
6
+ expect(getShapeBox({ type: "rect", width: 32, height: 32 })).toEqual({
7
+ width: 32,
8
+ height: 32,
9
+ offsetX: 0,
10
+ offsetY: 0
11
+ });
12
+ expect(getShapeBox({ type: "circle", radius: 8 })).toEqual({
13
+ width: 16,
14
+ height: 16,
15
+ offsetX: 0,
16
+ offsetY: 0
17
+ });
18
+ });
19
+
20
+ test("normalizes line bounds with negative coordinates", () => {
21
+ expect(getShapeBox({ type: "line", x1: -4, y1: 6, x2: 12, y2: -2 })).toEqual({
22
+ width: 16,
23
+ height: 8,
24
+ offsetX: 4,
25
+ offsetY: 2
26
+ });
27
+ });
28
+
29
+ test("normalizes polygon bounds and translated points", () => {
30
+ const box = getShapeBox({ type: "polygon", points: [-5, 2, 15, 2, 5, 12] });
31
+
32
+ expect(getShapePointBounds([-5, 2, 15, 2, 5, 12])).toEqual({
33
+ minX: -5,
34
+ minY: 2,
35
+ maxX: 15,
36
+ maxY: 12
37
+ });
38
+ expect(box).toEqual({
39
+ width: 20,
40
+ height: 10,
41
+ offsetX: 5,
42
+ offsetY: -2
43
+ });
44
+ expect(translatePolygonPoints([-5, 2, 15, 2, 5, 12], box)).toEqual([0, 0, 20, 0, 10, 10]);
45
+ });
46
+ });
@@ -0,0 +1,61 @@
1
+ const defaultToNumber = (value: any, fallback = 0) => {
2
+ const num = typeof value === 'number' ? value : parseFloat(value);
3
+ return Number.isFinite(num) ? num : fallback;
4
+ };
5
+
6
+ export function getShapePointBounds(points: any[] = [], toNumber = defaultToNumber) {
7
+ if (!Array.isArray(points) || points.length < 2) {
8
+ return { minX: 0, minY: 0, maxX: 1, maxY: 1 };
9
+ }
10
+
11
+ let minX = Infinity;
12
+ let minY = Infinity;
13
+ let maxX = -Infinity;
14
+ let maxY = -Infinity;
15
+
16
+ for (let i = 0; i < points.length; i += 2) {
17
+ const x = toNumber(points[i], 0);
18
+ const y = toNumber(points[i + 1], 0);
19
+ minX = Math.min(minX, x);
20
+ minY = Math.min(minY, y);
21
+ maxX = Math.max(maxX, x);
22
+ maxY = Math.max(maxY, y);
23
+ }
24
+
25
+ return { minX, minY, maxX, maxY };
26
+ }
27
+
28
+ export function getShapeBox(cfg: any, toNumber = defaultToNumber) {
29
+ if (cfg.type === 'circle') {
30
+ return { width: cfg.radius * 2, height: cfg.radius * 2, offsetX: 0, offsetY: 0 };
31
+ }
32
+
33
+ if (cfg.type === 'line') {
34
+ const minX = Math.min(cfg.x1, cfg.x2);
35
+ const minY = Math.min(cfg.y1, cfg.y2);
36
+ const maxX = Math.max(cfg.x1, cfg.x2);
37
+ const maxY = Math.max(cfg.y1, cfg.y2);
38
+ return {
39
+ width: Math.max(1, maxX - minX),
40
+ height: Math.max(1, maxY - minY),
41
+ offsetX: -minX,
42
+ offsetY: -minY
43
+ };
44
+ }
45
+
46
+ if (cfg.type === 'polygon') {
47
+ const bounds = getShapePointBounds(cfg.points, toNumber);
48
+ return {
49
+ width: Math.max(1, bounds.maxX - bounds.minX),
50
+ height: Math.max(1, bounds.maxY - bounds.minY),
51
+ offsetX: -bounds.minX,
52
+ offsetY: -bounds.minY
53
+ };
54
+ }
55
+
56
+ return { width: cfg.width, height: cfg.height, offsetX: 0, offsetY: 0 };
57
+ }
58
+
59
+ export function translatePolygonPoints(points: any[] = [], box: { offsetX: number; offsetY: number }, toNumber = defaultToNumber) {
60
+ return points.map((point, index) => toNumber(point, 0) + (index % 2 === 0 ? box.offsetX : box.offsetY));
61
+ }
@@ -0,0 +1,89 @@
1
+ <Container width={shapeWidth} height={shapeHeight} minWidth={shapeWidth} minHeight={shapeHeight}>
2
+ <Graphics width={shapeWidth} height={shapeHeight} draw={drawShape} />
3
+ </Container>
4
+
5
+ <script>
6
+ import { computed } from "canvasengine";
7
+ import { resolveDynamicValue } from "./parse-value";
8
+ import { getShapeBox, translatePolygonPoints } from "./shape-utils";
9
+
10
+ const props = defineProps();
11
+ const { object } = props;
12
+
13
+ const read = (prop, fallback) => prop ? prop() : fallback;
14
+
15
+ const toNumber = (value, fallback = 0) => {
16
+ const resolved = resolveDynamicValue(value, object);
17
+ const num = typeof resolved === 'number' ? resolved : parseFloat(resolved);
18
+ return Number.isFinite(num) ? num : fallback;
19
+ };
20
+
21
+ const toColor = (value, fallback) => {
22
+ const resolved = resolveDynamicValue(value, object);
23
+ if (typeof resolved === 'number') return resolved;
24
+ if (typeof resolved === 'string' && resolved.startsWith('#')) {
25
+ return parseInt(resolved.slice(1), 16);
26
+ }
27
+ return resolved ?? fallback;
28
+ };
29
+
30
+ const config = computed(() => ({
31
+ type: read(props.type, 'rectangle'),
32
+ fill: toColor(read(props.fill, '#ffffff'), 0xffffff),
33
+ radius: toNumber(read(props.radius, 8), 8),
34
+ width: toNumber(read(props.width, 16), 16),
35
+ height: toNumber(read(props.height, 16), 16),
36
+ x1: toNumber(read(props.x1, 0), 0),
37
+ y1: toNumber(read(props.y1, 0), 0),
38
+ x2: toNumber(read(props.x2, 16), 16),
39
+ y2: toNumber(read(props.y2, 0), 0),
40
+ opacity: Math.max(0, Math.min(1, toNumber(read(props.opacity, 1), 1))),
41
+ points: read(props.points, []),
42
+ line: read(props.line, null)
43
+ }));
44
+
45
+ const shapeBox = computed(() => getShapeBox(config(), toNumber));
46
+
47
+ const shapeWidth = computed(() => shapeBox().width);
48
+ const shapeHeight = computed(() => shapeBox().height);
49
+
50
+ const drawShape = (g) => {
51
+ const cfg = config();
52
+ const box = shapeBox();
53
+
54
+ if (cfg.type === 'circle') {
55
+ g.circle(cfg.radius, cfg.radius, cfg.radius);
56
+ } else if (cfg.type === 'ellipse') {
57
+ g.ellipse(box.width / 2, box.height / 2, box.width / 2, box.height / 2);
58
+ } else if (cfg.type === 'line') {
59
+ g.moveTo(cfg.x1 + box.offsetX, cfg.y1 + box.offsetY);
60
+ g.lineTo(cfg.x2 + box.offsetX, cfg.y2 + box.offsetY);
61
+ } else if (cfg.type === 'polygon' && Array.isArray(cfg.points)) {
62
+ g.poly(translatePolygonPoints(cfg.points, box, toNumber));
63
+ } else if (cfg.type === 'rounded-rectangle') {
64
+ g.roundRect(0, 0, box.width, box.height, toNumber(read(props.radius, 4), 4));
65
+ } else {
66
+ g.rect(0, 0, box.width, box.height);
67
+ }
68
+
69
+ if (cfg.type === 'line') {
70
+ const line = cfg.line ?? {};
71
+ g.stroke({
72
+ color: toColor(line.color, cfg.fill),
73
+ width: toNumber(line.width, 1),
74
+ alpha: toNumber(line.alpha, cfg.opacity)
75
+ });
76
+ return;
77
+ }
78
+
79
+ g.fill({ color: cfg.fill, alpha: cfg.opacity });
80
+
81
+ if (cfg.line) {
82
+ g.stroke({
83
+ color: toColor(cfg.line.color, cfg.fill),
84
+ width: toNumber(cfg.line.width, 1),
85
+ alpha: toNumber(cfg.line.alpha, cfg.opacity)
86
+ });
87
+ }
88
+ };
89
+ </script>
@@ -0,0 +1,68 @@
1
+ <Text text={textValue} color={textColor} size={textSize} fontFamily={textFontFamily} style={textStyle} />
2
+
3
+ <script>
4
+ import { computed } from "canvasengine";
5
+ import { resolveDynamicValue } from "./parse-value";
6
+
7
+ const { object, value, style } = defineProps();
8
+
9
+ const read = (prop, fallback) => prop ? prop() : fallback;
10
+
11
+ const parseNumericStyleValue = (value, object) => {
12
+ value = resolveDynamicValue(value, object);
13
+ if (value === undefined || value === null) return undefined;
14
+ if (typeof value === 'number') return value;
15
+
16
+ const num = parseFloat(value);
17
+ return isNaN(num) ? undefined : num;
18
+ };
19
+
20
+ const getTextStyle = (style) => {
21
+ if (!style) return {};
22
+ const textStyle = {};
23
+
24
+ if (style.fontStyle !== undefined) {
25
+ textStyle.fontStyle = resolveDynamicValue(style.fontStyle, object);
26
+ }
27
+
28
+ if (style.fontWeight !== undefined) {
29
+ textStyle.fontWeight = resolveDynamicValue(style.fontWeight, object);
30
+ }
31
+
32
+ if (style.stroke !== undefined) {
33
+ textStyle.stroke = resolveDynamicValue(style.stroke, object);
34
+ }
35
+
36
+ if (style.opacity !== undefined) {
37
+ const opacityValue = parseNumericStyleValue(style.opacity, object);
38
+ if (opacityValue !== undefined) {
39
+ textStyle.opacity = opacityValue;
40
+ }
41
+ }
42
+
43
+ if (style.wordWrap !== undefined) {
44
+ textStyle.wordWrap = style.wordWrap;
45
+ }
46
+
47
+ if (style.align !== undefined) {
48
+ textStyle.align = resolveDynamicValue(style.align, object);
49
+ }
50
+
51
+ return textStyle;
52
+ };
53
+
54
+ const textValue = computed(() => String(resolveDynamicValue(read(value, ''), object) ?? ''));
55
+ const textColor = computed(() => {
56
+ const currentStyle = read(style, {});
57
+ return currentStyle.fill !== undefined ? resolveDynamicValue(currentStyle.fill, object) : undefined;
58
+ });
59
+ const textSize = computed(() => {
60
+ const currentStyle = read(style, {});
61
+ return currentStyle.fontSize !== undefined ? parseNumericStyleValue(currentStyle.fontSize, object) : undefined;
62
+ });
63
+ const textFontFamily = computed(() => {
64
+ const currentStyle = read(style, {});
65
+ return currentStyle.fontFamily !== undefined ? resolveDynamicValue(currentStyle.fontFamily, object) : undefined;
66
+ });
67
+ const textStyle = computed(() => getTextStyle(read(style, {})));
68
+ </script>
@@ -0,0 +1,17 @@
1
+ <Container positionType="absolute" top={top} left={left}>
2
+ <Container
3
+ anchor={[0.5, 0.5]}
4
+ >
5
+ <Rect width height color={_color} />
6
+ <Container attach={child}></Container>
7
+ </Container>
8
+ </Container>
9
+
10
+ <script>
11
+ import { RpgClientEngine, inject } from "../../index";
12
+
13
+ const { width, height, children, color, top, left } = defineProps();
14
+ const engine = inject(RpgClientEngine)
15
+ const child = children[0]
16
+ const _color = computed(() => engine.globalConfig.gui?.windowColor || color?.() || "#1a1a2e")
17
+ </script>