@waica/cli 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/dist/cli.js +184 -0
  4. package/dist/editor/assets/abap-08VXUWAP.js +1 -0
  5. package/dist/editor/assets/apex-BWPQTe0t.js +1 -0
  6. package/dist/editor/assets/azcli-Bc_sGQ0U.js +1 -0
  7. package/dist/editor/assets/bat-i0X4ZdIN.js +1 -0
  8. package/dist/editor/assets/bicep-B5-_aFwp.js +2 -0
  9. package/dist/editor/assets/cameligo-DMUM7wLl.js +1 -0
  10. package/dist/editor/assets/clojure-Cm7r79vr.js +1 -0
  11. package/dist/editor/assets/codicon-DCmgc-ay.ttf +0 -0
  12. package/dist/editor/assets/coffee-Ba7i2nA0.js +1 -0
  13. package/dist/editor/assets/cpp-C7h46wYY.js +1 -0
  14. package/dist/editor/assets/csharp-BKxtCVv1.js +1 -0
  15. package/dist/editor/assets/csp-bTuwJoIa.js +1 -0
  16. package/dist/editor/assets/css-DIMkf-bt.js +3 -0
  17. package/dist/editor/assets/css.worker-Fwwr_HdT.js +88 -0
  18. package/dist/editor/assets/cssMode-CQE-WdwL.js +4 -0
  19. package/dist/editor/assets/cypher-CVaqCwHa.js +1 -0
  20. package/dist/editor/assets/dart-onAF5SnQ.js +1 -0
  21. package/dist/editor/assets/dockerfile-DZFCIeNp.js +1 -0
  22. package/dist/editor/assets/ecl-D05T4iGw.js +1 -0
  23. package/dist/editor/assets/editor.worker-DsBDrWS5.js +12 -0
  24. package/dist/editor/assets/elixir-6RTg0lbw.js +1 -0
  25. package/dist/editor/assets/flow9-C5_-GSwl.js +1 -0
  26. package/dist/editor/assets/freemarker2-CYgdVabn.js +3 -0
  27. package/dist/editor/assets/fsharp-C8Ef5oNN.js +1 -0
  28. package/dist/editor/assets/go-C-y9NEjX.js +1 -0
  29. package/dist/editor/assets/graphql-fmXr3nnJ.js +1 -0
  30. package/dist/editor/assets/handlebars-DdeORCJD.js +1 -0
  31. package/dist/editor/assets/hcl-CpzslTdj.js +1 -0
  32. package/dist/editor/assets/html-DTIAGV84.js +1 -0
  33. package/dist/editor/assets/html.worker-B3Ztmmz2.js +495 -0
  34. package/dist/editor/assets/htmlMode-CRV3iBih.js +4 -0
  35. package/dist/editor/assets/index-Btzc6zxr.css +1 -0
  36. package/dist/editor/assets/index-Dhkqk31v.js +11016 -0
  37. package/dist/editor/assets/ini-sBoK_t0W.js +1 -0
  38. package/dist/editor/assets/java-BEtHBSE6.js +1 -0
  39. package/dist/editor/assets/javascript-dxBW86cl.js +1 -0
  40. package/dist/editor/assets/json.worker-PWQxM7ZO.js +51 -0
  41. package/dist/editor/assets/jsonMode-DFA5-FFK.js +10 -0
  42. package/dist/editor/assets/julia-Bri6UV-V.js +1 -0
  43. package/dist/editor/assets/kotlin-B0qVs-E9.js +1 -0
  44. package/dist/editor/assets/less-B9JPFI3C.js +2 -0
  45. package/dist/editor/assets/lexon-CfSJPG6W.js +1 -0
  46. package/dist/editor/assets/liquid-CScWaXYV.js +1 -0
  47. package/dist/editor/assets/lua-CsQS60Ue.js +1 -0
  48. package/dist/editor/assets/m3-D-oSqn_W.js +1 -0
  49. package/dist/editor/assets/markdown-Cimd5fb3.js +1 -0
  50. package/dist/editor/assets/mdx-Bvp84SqA.js +1 -0
  51. package/dist/editor/assets/mips-CIPQ_RoX.js +1 -0
  52. package/dist/editor/assets/msdax-DauUninz.js +1 -0
  53. package/dist/editor/assets/mysql-SOo6toE5.js +1 -0
  54. package/dist/editor/assets/objective-c-FvmIjYaQ.js +1 -0
  55. package/dist/editor/assets/pascal-DrH0SRf2.js +1 -0
  56. package/dist/editor/assets/pascaligo-D-ptJ9y-.js +1 -0
  57. package/dist/editor/assets/perl-oz_6vUea.js +1 -0
  58. package/dist/editor/assets/pgsql-DTj74zXo.js +1 -0
  59. package/dist/editor/assets/php-nr791fC2.js +1 -0
  60. package/dist/editor/assets/pla-CopQ2nXW.js +1 -0
  61. package/dist/editor/assets/postiats-43DmfD33.js +1 -0
  62. package/dist/editor/assets/powerquery-D3hlyOfw.js +1 -0
  63. package/dist/editor/assets/powershell-DmHpPYUd.js +1 -0
  64. package/dist/editor/assets/protobuf-C531GsRP.js +2 -0
  65. package/dist/editor/assets/pug-Z5eAx3Zn.js +1 -0
  66. package/dist/editor/assets/python-CG-OtvFa.js +1 -0
  67. package/dist/editor/assets/qsharp-DkqhCAOL.js +1 -0
  68. package/dist/editor/assets/r-BwWrilGY.js +1 -0
  69. package/dist/editor/assets/razor-r-iUEZPj.js +1 -0
  70. package/dist/editor/assets/redis-ClamHrr6.js +1 -0
  71. package/dist/editor/assets/redshift-DT7zqm-g.js +1 -0
  72. package/dist/editor/assets/restructuredtext-BYgofb2h.js +1 -0
  73. package/dist/editor/assets/ruby-DezsRK8O.js +1 -0
  74. package/dist/editor/assets/rust-DdL9SqIa.js +1 -0
  75. package/dist/editor/assets/sb-CcwsVR0C.js +1 -0
  76. package/dist/editor/assets/scala-DHpiXF5c.js +1 -0
  77. package/dist/editor/assets/scheme-BeGwcela.js +1 -0
  78. package/dist/editor/assets/scss-gp-XZpBa.js +3 -0
  79. package/dist/editor/assets/shell-CC2rA5mh.js +1 -0
  80. package/dist/editor/assets/solidity-BEEn4gHE.js +1 -0
  81. package/dist/editor/assets/sophia-CRfGWb83.js +1 -0
  82. package/dist/editor/assets/sparql-D_Lu-MrJ.js +1 -0
  83. package/dist/editor/assets/sql-NEE52Syq.js +1 -0
  84. package/dist/editor/assets/st-DbInun42.js +1 -0
  85. package/dist/editor/assets/swift-Bxkupp3x.js +1 -0
  86. package/dist/editor/assets/systemverilog-Bz4Y3fRF.js +1 -0
  87. package/dist/editor/assets/tcl-DISqw1ZD.js +1 -0
  88. package/dist/editor/assets/ts.worker-0mEyHVru.js +51339 -0
  89. package/dist/editor/assets/tsMode-Bth1rJwM.js +11 -0
  90. package/dist/editor/assets/twig-De2hgUGE.js +1 -0
  91. package/dist/editor/assets/typescript-tNRuHsoe.js +1 -0
  92. package/dist/editor/assets/typespec-B8J7ngcE.js +1 -0
  93. package/dist/editor/assets/vb-DV3o63ZY.js +1 -0
  94. package/dist/editor/assets/wgsl-DpFanUEy.js +298 -0
  95. package/dist/editor/assets/xml-BCx9e6CK.js +1 -0
  96. package/dist/editor/assets/yaml-Bb-peGP_.js +1 -0
  97. package/dist/editor/index.html +14 -0
  98. package/dist/mcp/archetypes.js +103 -0
  99. package/dist/mcp/cli.js +6 -0
  100. package/dist/mcp/create-project.js +151 -0
  101. package/dist/mcp/introspection.js +201 -0
  102. package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-coin.png +0 -0
  103. package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-dog.png +0 -0
  104. package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-slime.png +0 -0
  105. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.d.ts +10 -0
  106. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.js +13 -0
  107. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.d.ts +3 -0
  108. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.js +10 -0
  109. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.d.ts +5 -0
  110. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.js +12 -0
  111. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.d.ts +38 -0
  112. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.js +34 -0
  113. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.d.ts +15 -0
  114. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.js +26 -0
  115. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.d.ts +7 -0
  116. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.js +97 -0
  117. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.d.ts +5 -0
  118. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.js +45 -0
  119. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.d.ts +6 -0
  120. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.js +15 -0
  121. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.d.ts +40 -0
  122. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.js +93 -0
  123. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.d.ts +10 -0
  124. package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.js +24 -0
  125. package/dist/mcp/node_modules/@waica/archetype-platformer/package.json +30 -0
  126. package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.d.ts +59 -0
  127. package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.js +127 -0
  128. package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.d.ts +25 -0
  129. package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.js +27 -0
  130. package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.d.ts +29 -0
  131. package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.js +42 -0
  132. package/dist/mcp/node_modules/@waica/behaviors/dist/index.d.ts +9 -0
  133. package/dist/mcp/node_modules/@waica/behaviors/dist/index.js +9 -0
  134. package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.d.ts +16 -0
  135. package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.js +19 -0
  136. package/dist/mcp/node_modules/@waica/behaviors/dist/npc.d.ts +4 -0
  137. package/dist/mcp/node_modules/@waica/behaviors/dist/npc.js +14 -0
  138. package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.d.ts +43 -0
  139. package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.js +68 -0
  140. package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.d.ts +124 -0
  141. package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.js +146 -0
  142. package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.d.ts +3 -0
  143. package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.js +5 -0
  144. package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.d.ts +18 -0
  145. package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.js +95 -0
  146. package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.d.ts +23 -0
  147. package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.js +27 -0
  148. package/dist/mcp/node_modules/@waica/behaviors/package.json +24 -0
  149. package/dist/mcp/node_modules/@waica/engine/dist/aabb.d.ts +2 -0
  150. package/dist/mcp/node_modules/@waica/engine/dist/aabb.js +4 -0
  151. package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.d.ts +20 -0
  152. package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.js +24 -0
  153. package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.d.ts +21 -0
  154. package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.js +23 -0
  155. package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.d.ts +65 -0
  156. package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.js +44 -0
  157. package/dist/mcp/node_modules/@waica/engine/dist/archetype.d.ts +37 -0
  158. package/dist/mcp/node_modules/@waica/engine/dist/archetype.js +1 -0
  159. package/dist/mcp/node_modules/@waica/engine/dist/camera.d.ts +71 -0
  160. package/dist/mcp/node_modules/@waica/engine/dist/camera.js +59 -0
  161. package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.d.ts +26 -0
  162. package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.js +136 -0
  163. package/dist/mcp/node_modules/@waica/engine/dist/component-registry.d.ts +16 -0
  164. package/dist/mcp/node_modules/@waica/engine/dist/component-registry.js +44 -0
  165. package/dist/mcp/node_modules/@waica/engine/dist/component.d.ts +58 -0
  166. package/dist/mcp/node_modules/@waica/engine/dist/component.js +11 -0
  167. package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.d.ts +80 -0
  168. package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.js +210 -0
  169. package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.d.ts +68 -0
  170. package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.js +189 -0
  171. package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.d.ts +25 -0
  172. package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.js +21 -0
  173. package/dist/mcp/node_modules/@waica/engine/dist/components/solid.d.ts +32 -0
  174. package/dist/mcp/node_modules/@waica/engine/dist/components/solid.js +45 -0
  175. package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.d.ts +51 -0
  176. package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.js +112 -0
  177. package/dist/mcp/node_modules/@waica/engine/dist/entity.d.ts +22 -0
  178. package/dist/mcp/node_modules/@waica/engine/dist/entity.js +52 -0
  179. package/dist/mcp/node_modules/@waica/engine/dist/events.d.ts +8 -0
  180. package/dist/mcp/node_modules/@waica/engine/dist/events.js +20 -0
  181. package/dist/mcp/node_modules/@waica/engine/dist/game.d.ts +95 -0
  182. package/dist/mcp/node_modules/@waica/engine/dist/game.js +263 -0
  183. package/dist/mcp/node_modules/@waica/engine/dist/index.d.ts +39 -0
  184. package/dist/mcp/node_modules/@waica/engine/dist/index.js +26 -0
  185. package/dist/mcp/node_modules/@waica/engine/dist/input.d.ts +40 -0
  186. package/dist/mcp/node_modules/@waica/engine/dist/input.js +84 -0
  187. package/dist/mcp/node_modules/@waica/engine/dist/scene.d.ts +80 -0
  188. package/dist/mcp/node_modules/@waica/engine/dist/scene.js +93 -0
  189. package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.d.ts +21 -0
  190. package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.js +77 -0
  191. package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.d.ts +90 -0
  192. package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.js +81 -0
  193. package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.d.ts +83 -0
  194. package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.js +173 -0
  195. package/dist/mcp/node_modules/@waica/engine/dist/stats.d.ts +27 -0
  196. package/dist/mcp/node_modules/@waica/engine/dist/stats.js +54 -0
  197. package/dist/mcp/node_modules/@waica/engine/dist/ui.d.ts +47 -0
  198. package/dist/mcp/node_modules/@waica/engine/dist/ui.js +175 -0
  199. package/dist/mcp/node_modules/@waica/engine/package.json +25 -0
  200. package/dist/mcp/package-resolver.js +240 -0
  201. package/dist/mcp/project-path.js +86 -0
  202. package/dist/mcp/scaffolds.js +153 -0
  203. package/dist/mcp/server.js +217 -0
  204. package/dist/mcp/stdio.js +13 -0
  205. package/dist/mcp/template/README.md +22 -0
  206. package/dist/mcp/template/_gitignore +5 -0
  207. package/dist/mcp/template/index.html +25 -0
  208. package/dist/mcp/template/package.json.tpl +20 -0
  209. package/dist/mcp/template/public/waica.params.json +1 -0
  210. package/dist/mcp/template/src/art/waica-coin.png +0 -0
  211. package/dist/mcp/template/src/art/waica-dog.png +0 -0
  212. package/dist/mcp/template/src/art/waica-slime.png +0 -0
  213. package/dist/mcp/template/src/characters/player.character.json +133 -0
  214. package/dist/mcp/template/src/characters/slime.character.json +61 -0
  215. package/dist/mcp/template/src/controls.json +8 -0
  216. package/dist/mcp/template/src/game.json +10 -0
  217. package/dist/mcp/template/src/main.ts +105 -0
  218. package/dist/mcp/template/src/objects/coin.object.json +41 -0
  219. package/dist/mcp/template/src/scenes/main.scene.json +217 -0
  220. package/dist/mcp/template/src/stats.json +7 -0
  221. package/dist/mcp/template/src/tiles/block.tile.json +21 -0
  222. package/dist/mcp/template/src/tiles/decor.tile.json +14 -0
  223. package/dist/mcp/template/src/tiles/platform.tile.json +21 -0
  224. package/dist/mcp/template/src/ui/coin-counter.html +12 -0
  225. package/dist/mcp/template/tsconfig.json +15 -0
  226. package/dist/mcp/template/vite.config.ts +3 -0
  227. package/dist/mcp/validation.js +323 -0
  228. package/dist/mcp/workspace-loader.js +14 -0
  229. package/dist/mcp/workspace-runtime.js +109 -0
  230. package/dist/server.js +210 -0
  231. package/package.json +38 -0
@@ -0,0 +1,43 @@
1
+ import { Component, type RoleDefinition, type RoleGraph } from '@waica/engine';
2
+ export type PatrolAxis = 'horizontal' | 'vertical';
3
+ /**
4
+ * Rail patrol: back and forth `distance` units from the starting
5
+ * position along one axis — sideways or up and down — turning around
6
+ * at the ends (with a sprite flip when walking sideways).
7
+ * Passive like a motor: no onUpdate of its own — the 'patroller' logic
8
+ * set's walk state calls step(dt), so the StateMachine stays the single
9
+ * owner of the frame.
10
+ */
11
+ export declare class Patrol extends Component {
12
+ static componentName: string;
13
+ static params: {
14
+ axis: {
15
+ label: string;
16
+ options: string[];
17
+ };
18
+ distance: {
19
+ label: string;
20
+ min: number;
21
+ max: number;
22
+ step: number;
23
+ };
24
+ speed: {
25
+ label: string;
26
+ min: number;
27
+ max: number;
28
+ step: number;
29
+ };
30
+ };
31
+ axis: PatrolAxis;
32
+ distance: number;
33
+ speed: number;
34
+ private originX;
35
+ private originY;
36
+ private dir;
37
+ onReady(): void;
38
+ /** One patrol step: advance, turn at the rail's ends, flip the sprite. */
39
+ step(dt: number): void;
40
+ }
41
+ /** The state graph new patrolling characters start with, as prefab data. */
42
+ export declare const PATROLLER_STATE_GRAPH: RoleGraph;
43
+ export declare const PATROLLER_ROLE: RoleDefinition;
@@ -0,0 +1,68 @@
1
+ import { Component } from '@waica/engine';
2
+ /**
3
+ * Rail patrol: back and forth `distance` units from the starting
4
+ * position along one axis — sideways or up and down — turning around
5
+ * at the ends (with a sprite flip when walking sideways).
6
+ * Passive like a motor: no onUpdate of its own — the 'patroller' logic
7
+ * set's walk state calls step(dt), so the StateMachine stays the single
8
+ * owner of the frame.
9
+ */
10
+ export class Patrol extends Component {
11
+ static componentName = 'Patrol';
12
+ static params = {
13
+ axis: { label: 'Axis', options: ['horizontal', 'vertical'] },
14
+ distance: { label: 'Distance', min: 0.5, max: 20, step: 0.5 },
15
+ speed: { label: 'Speed', min: 0.5, max: 15, step: 0.5 },
16
+ };
17
+ axis = 'horizontal';
18
+ distance = 3;
19
+ speed = 2;
20
+ // Both origins are captured so a live axis switch keeps a valid rail.
21
+ originX = 0;
22
+ originY = 0;
23
+ dir = 1;
24
+ onReady() {
25
+ this.originX = this.entity.position.x;
26
+ this.originY = this.entity.position.y;
27
+ }
28
+ /** One patrol step: advance, turn at the rail's ends, flip the sprite. */
29
+ step(dt) {
30
+ const pos = this.entity.position;
31
+ const vertical = this.axis === 'vertical';
32
+ const key = vertical ? 'y' : 'x';
33
+ const origin = vertical ? this.originY : this.originX;
34
+ let next = pos[key] + this.dir * this.speed * dt;
35
+ if (next > origin + this.distance) {
36
+ next = origin + this.distance;
37
+ this.dir = -1;
38
+ }
39
+ else if (next < origin - this.distance) {
40
+ next = origin - this.distance;
41
+ this.dir = 1;
42
+ }
43
+ pos[key] = next;
44
+ if (!vertical)
45
+ this.entity.scale.x = this.dir;
46
+ }
47
+ }
48
+ /** The state graph new patrolling characters start with, as prefab data. */
49
+ export const PATROLLER_STATE_GRAPH = {
50
+ initial: 'walk',
51
+ states: { walk: {} },
52
+ };
53
+ // The walking-critter role. One state out of the box; give patrolling
54
+ // characters more states by registering on top (defineStates('patroller',
55
+ // { chasing: {...} })) plus prefab data.
56
+ export const PATROLLER_ROLE = {
57
+ description: 'Walks back and forth on its own along a rail — no player input, no ' +
58
+ 'gravity. Good for critters and moving hazards. Its states move Patrol.',
59
+ driver: 'Patrol',
60
+ graph: PATROLLER_STATE_GRAPH,
61
+ states: {
62
+ walk: {
63
+ onUpdate({ entity }, dt) {
64
+ entity.get(Patrol)?.step(dt);
65
+ },
66
+ },
67
+ },
68
+ };
@@ -0,0 +1,124 @@
1
+ import { Component } from '@waica/engine';
2
+ /**
3
+ * Passive platformer motor: tuning params, physical state and movement
4
+ * methods for state code to call. It has no onUpdate of its own — the
5
+ * StateMachine is the only owner of the frame; this is the toolbox the
6
+ * active state moves the body with. The out-of-the-box game feel a
7
+ * beginner doesn't know they need lives here: coyote time, jump
8
+ * buffering, jump cut (releasing jumps shorter) and squash & stretch.
9
+ * Per-axis collision against the scene's Solids — deterministic genre
10
+ * movement (Celeste-style), not "realistic" physics.
11
+ */
12
+ export declare class PlatformerMotor extends Component {
13
+ static componentName: string;
14
+ static displayName: string;
15
+ static params: {
16
+ moveSpeed: {
17
+ label: string;
18
+ min: number;
19
+ max: number;
20
+ step: number;
21
+ };
22
+ acceleration: {
23
+ label: string;
24
+ min: number;
25
+ max: number;
26
+ step: number;
27
+ };
28
+ deceleration: {
29
+ label: string;
30
+ min: number;
31
+ max: number;
32
+ step: number;
33
+ };
34
+ jumpVelocity: {
35
+ label: string;
36
+ min: number;
37
+ max: number;
38
+ step: number;
39
+ };
40
+ gravity: {
41
+ label: string;
42
+ min: number;
43
+ max: number;
44
+ step: number;
45
+ };
46
+ maxFallSpeed: {
47
+ label: string;
48
+ min: number;
49
+ max: number;
50
+ step: number;
51
+ };
52
+ coyoteTime: {
53
+ label: string;
54
+ min: number;
55
+ max: number;
56
+ step: number;
57
+ };
58
+ jumpBuffer: {
59
+ label: string;
60
+ min: number;
61
+ max: number;
62
+ step: number;
63
+ };
64
+ jumpCutStrength: {
65
+ label: string;
66
+ min: number;
67
+ max: number;
68
+ step: number;
69
+ };
70
+ runThreshold: {
71
+ label: string;
72
+ min: number;
73
+ max: number;
74
+ step: number;
75
+ };
76
+ squashStretch: {
77
+ label: string;
78
+ };
79
+ };
80
+ moveSpeed: number;
81
+ acceleration: number;
82
+ deceleration: number;
83
+ jumpVelocity: number;
84
+ gravity: number;
85
+ maxFallSpeed: number;
86
+ coyoteTime: number;
87
+ jumpBuffer: number;
88
+ /** >1 applies extra gravity while rising without holding jump. */
89
+ jumpCutStrength: number;
90
+ /** |vx| above this reads as running (the idle ↔ run edge). */
91
+ runThreshold: number;
92
+ squashStretch: boolean;
93
+ /** The character's AABB hitbox. */
94
+ hitboxWidth: number;
95
+ hitboxHeight: number;
96
+ vx: number;
97
+ vy: number;
98
+ grounded: boolean;
99
+ /** 1 facing right, -1 facing left. */
100
+ facing: number;
101
+ private coyoteTimer;
102
+ private bufferTimer;
103
+ private squashX;
104
+ private squashY;
105
+ /**
106
+ * Per-frame bookkeeping: forgiveness timers, squash decay and the
107
+ * facing flip. The logic set's '*' hook runs it in every state, so
108
+ * coyote and buffer survive state transitions.
109
+ */
110
+ tick(dt: number): void;
111
+ /** Accelerates toward dir (-1..1) * moveSpeed, flipping facing. */
112
+ runTowards(dir: number, dt: number): void;
113
+ /** A buffered jump press within coyote time — the frame to call jump(). */
114
+ wantsJump(): boolean;
115
+ jump(): void;
116
+ /** Gravity with jump cut: rising without holding jump falls sooner. */
117
+ applyGravity(dt: number): void;
118
+ /** Integrates velocity and resolves collisions against Solids. */
119
+ step(dt: number): void;
120
+ halt(): void;
121
+ private applySquash;
122
+ private resolveAxis;
123
+ private collisionBody;
124
+ }
@@ -0,0 +1,146 @@
1
+ import { Component, resolveSolidAxis, THREE } from '@waica/engine';
2
+ /**
3
+ * Passive platformer motor: tuning params, physical state and movement
4
+ * methods for state code to call. It has no onUpdate of its own — the
5
+ * StateMachine is the only owner of the frame; this is the toolbox the
6
+ * active state moves the body with. The out-of-the-box game feel a
7
+ * beginner doesn't know they need lives here: coyote time, jump
8
+ * buffering, jump cut (releasing jumps shorter) and squash & stretch.
9
+ * Per-axis collision against the scene's Solids — deterministic genre
10
+ * movement (Celeste-style), not "realistic" physics.
11
+ */
12
+ export class PlatformerMotor extends Component {
13
+ static componentName = 'PlatformerMotor';
14
+ static displayName = 'Motor';
15
+ static params = {
16
+ moveSpeed: { label: 'Speed', min: 1, max: 30, step: 0.5 },
17
+ acceleration: { label: 'Acceleration', min: 5, max: 200, step: 5 },
18
+ deceleration: { label: 'Deceleration', min: 5, max: 200, step: 5 },
19
+ jumpVelocity: { label: 'Jump impulse', min: 2, max: 40, step: 0.5 },
20
+ gravity: { label: 'Gravity', min: 5, max: 120, step: 1 },
21
+ maxFallSpeed: { label: 'Max fall speed', min: 5, max: 60, step: 1 },
22
+ coyoteTime: { label: 'Coyote time (s)', min: 0, max: 0.4, step: 0.01 },
23
+ jumpBuffer: { label: 'Jump buffer (s)', min: 0, max: 0.4, step: 0.01 },
24
+ jumpCutStrength: { label: 'Jump cut', min: 1, max: 6, step: 0.1 },
25
+ runThreshold: { label: 'Run threshold', min: 0, max: 5, step: 0.1 },
26
+ squashStretch: { label: 'Squash & stretch' },
27
+ };
28
+ moveSpeed = 9;
29
+ acceleration = 60;
30
+ deceleration = 80;
31
+ jumpVelocity = 14;
32
+ gravity = 42;
33
+ maxFallSpeed = 22;
34
+ coyoteTime = 0.1;
35
+ jumpBuffer = 0.12;
36
+ /** >1 applies extra gravity while rising without holding jump. */
37
+ jumpCutStrength = 2.5;
38
+ /** |vx| above this reads as running (the idle ↔ run edge). */
39
+ runThreshold = 0.5;
40
+ squashStretch = true;
41
+ /** The character's AABB hitbox. */
42
+ hitboxWidth = 0.9;
43
+ hitboxHeight = 0.95;
44
+ vx = 0;
45
+ vy = 0;
46
+ grounded = false;
47
+ /** 1 facing right, -1 facing left. */
48
+ facing = 1;
49
+ coyoteTimer = 0;
50
+ bufferTimer = 0;
51
+ squashX = 1;
52
+ squashY = 1;
53
+ /**
54
+ * Per-frame bookkeeping: forgiveness timers, squash decay and the
55
+ * facing flip. The logic set's '*' hook runs it in every state, so
56
+ * coyote and buffer survive state transitions.
57
+ */
58
+ tick(dt) {
59
+ this.coyoteTimer = this.grounded ? this.coyoteTime : this.coyoteTimer - dt;
60
+ this.bufferTimer = this.game.input.justPressed('jump')
61
+ ? this.jumpBuffer
62
+ : this.bufferTimer - dt;
63
+ this.squashX = THREE.MathUtils.damp(this.squashX, 1, 12, dt);
64
+ this.squashY = THREE.MathUtils.damp(this.squashY, 1, 12, dt);
65
+ this.entity.scale.set(this.facing * this.squashX, this.squashY, 1);
66
+ }
67
+ /** Accelerates toward dir (-1..1) * moveSpeed, flipping facing. */
68
+ runTowards(dir, dt) {
69
+ const target = dir * this.moveSpeed;
70
+ const rate = dir !== 0 ? this.acceleration : this.deceleration;
71
+ this.vx = THREE.MathUtils.damp(this.vx, target, rate / this.moveSpeed, dt);
72
+ if (dir !== 0)
73
+ this.facing = dir < 0 ? -1 : 1;
74
+ }
75
+ /** A buffered jump press within coyote time — the frame to call jump(). */
76
+ wantsJump() {
77
+ return this.bufferTimer > 0 && this.coyoteTimer > 0;
78
+ }
79
+ jump() {
80
+ this.vy = this.jumpVelocity;
81
+ this.coyoteTimer = 0;
82
+ this.bufferTimer = 0;
83
+ // The press that launched this jump is spent: a "key press jump"
84
+ // transition needs a NEW press, not the one already used here.
85
+ this.game.input.consume('jump');
86
+ this.applySquash(0.8, 1.25);
87
+ }
88
+ /** Gravity with jump cut: rising without holding jump falls sooner. */
89
+ applyGravity(dt) {
90
+ const cut = this.vy > 0 && !this.game.input.held('jump') ? this.jumpCutStrength : 1;
91
+ this.vy = Math.max(this.vy - this.gravity * cut * dt, -this.maxFallSpeed);
92
+ }
93
+ /** Integrates velocity and resolves collisions against Solids. */
94
+ step(dt) {
95
+ const pos = this.entity.position;
96
+ const wasAirborne = !this.grounded;
97
+ const previousX = pos.x;
98
+ pos.x += this.vx * dt;
99
+ this.resolveAxis('x', previousX);
100
+ this.grounded = false;
101
+ const previousY = pos.y;
102
+ pos.y += this.vy * dt;
103
+ this.resolveAxis('y', previousY);
104
+ if (wasAirborne && this.grounded)
105
+ this.applySquash(1.25, 0.8);
106
+ }
107
+ halt() {
108
+ this.vx = 0;
109
+ this.vy = 0;
110
+ }
111
+ applySquash(x, y) {
112
+ if (!this.squashStretch)
113
+ return;
114
+ this.squashX = x;
115
+ this.squashY = y;
116
+ }
117
+ resolveAxis(axis, previous) {
118
+ const collided = resolveSolidAxis({
119
+ entity: this.entity,
120
+ axis,
121
+ previous,
122
+ body: () => this.collisionBody(),
123
+ });
124
+ if (!collided)
125
+ return;
126
+ if (axis === 'x') {
127
+ this.vx = 0;
128
+ }
129
+ else if (this.vy <= 0) {
130
+ this.vy = 0;
131
+ this.grounded = true;
132
+ }
133
+ else {
134
+ this.vy = 0;
135
+ }
136
+ }
137
+ collisionBody() {
138
+ return {
139
+ x: this.entity.position.x,
140
+ y: this.entity.position.y,
141
+ width: this.hitboxWidth,
142
+ height: this.hitboxHeight,
143
+ shape: 'rectangle',
144
+ };
145
+ }
146
+ }
@@ -0,0 +1,3 @@
1
+ import { type Entity } from '@waica/engine';
2
+ /** Player identity is the role contract, independent of the movement driver. */
3
+ export declare function isPlayer(entity: Entity): boolean;
@@ -0,0 +1,5 @@
1
+ import { StateMachine } from '@waica/engine';
2
+ /** Player identity is the role contract, independent of the movement driver. */
3
+ export function isPlayer(entity) {
4
+ return entity.get(StateMachine)?.role === 'player';
5
+ }
@@ -0,0 +1,18 @@
1
+ import { type RoleDefinition, type RoleGraph, type StateContext } from '@waica/engine';
2
+ /**
3
+ * The 'player' role: the character you control. All four default states
4
+ * share one body update; they differ only in the edges their prefab data
5
+ * declares. Extending the player is defineStates('player', { yourState:
6
+ * {...} }) plus a state in the prefab — never a fight with a parallel
7
+ * controller.
8
+ */
9
+ /** The state graph new player characters start with, as prefab data. */
10
+ export declare const PLAYER_STATE_GRAPH: RoleGraph;
11
+ /**
12
+ * One body update shared by every default state: move, jump, gravity,
13
+ * collide, then report what the body is doing as signals. Unmatched
14
+ * signals are no-ops, so each state only reacts to the edges its data
15
+ * declares.
16
+ */
17
+ export declare function playerUpdate({ entity, game, fsm }: StateContext, dt: number): void;
18
+ export declare const PLAYER_ROLE: RoleDefinition;
@@ -0,0 +1,95 @@
1
+ import {} from '@waica/engine';
2
+ import { PlatformerMotor } from './platformer-motor.js';
3
+ /**
4
+ * The 'player' role: the character you control. All four default states
5
+ * share one body update; they differ only in the edges their prefab data
6
+ * declares. Extending the player is defineStates('player', { yourState:
7
+ * {...} }) plus a state in the prefab — never a fight with a parallel
8
+ * controller.
9
+ */
10
+ /** The state graph new player characters start with, as prefab data. */
11
+ export const PLAYER_STATE_GRAPH = {
12
+ initial: 'idle',
13
+ states: {
14
+ idle: {
15
+ transitions: [
16
+ { on: 'signal:move', to: 'run' },
17
+ { on: 'signal:rise', to: 'jump' },
18
+ { on: 'signal:fall', to: 'fall' },
19
+ ],
20
+ },
21
+ run: {
22
+ transitions: [
23
+ { on: 'signal:stop', to: 'idle' },
24
+ { on: 'signal:rise', to: 'jump' },
25
+ { on: 'signal:fall', to: 'fall' },
26
+ ],
27
+ },
28
+ jump: {
29
+ transitions: [
30
+ { on: 'signal:fall', to: 'fall' },
31
+ { on: 'signal:land', to: 'idle' },
32
+ ],
33
+ },
34
+ fall: {
35
+ // 'rise' from here is the coyote jump (and hazard stomp bounces).
36
+ transitions: [
37
+ { on: 'signal:rise', to: 'jump' },
38
+ { on: 'signal:land', to: 'idle' },
39
+ ],
40
+ },
41
+ },
42
+ };
43
+ /**
44
+ * One body update shared by every default state: move, jump, gravity,
45
+ * collide, then report what the body is doing as signals. Unmatched
46
+ * signals are no-ops, so each state only reacts to the edges its data
47
+ * declares.
48
+ */
49
+ export function playerUpdate({ entity, game, fsm }, dt) {
50
+ const motor = entity.get(PlatformerMotor);
51
+ if (!motor)
52
+ return;
53
+ motor.runTowards(game.input.axis(), dt);
54
+ if (motor.wantsJump())
55
+ motor.jump();
56
+ motor.applyGravity(dt);
57
+ motor.step(dt);
58
+ if (motor.grounded) {
59
+ fsm.signal('land');
60
+ fsm.signal(Math.abs(motor.vx) > motor.runThreshold ? 'move' : 'stop');
61
+ }
62
+ else {
63
+ fsm.signal(motor.vy > 0 ? 'rise' : 'fall');
64
+ }
65
+ }
66
+ export const PLAYER_ROLE = {
67
+ description: 'You control this character with the project controls: run and jump ' +
68
+ 'with platformer physics and curated game feel (coyote time, jump ' +
69
+ 'buffering). Its states move the Motor.',
70
+ driver: 'PlatformerMotor',
71
+ graph: PLAYER_STATE_GRAPH,
72
+ signals: {
73
+ move: 'on the ground and moving',
74
+ stop: 'on the ground and standing still',
75
+ rise: 'airborne, going up',
76
+ fall: 'airborne, going down',
77
+ land: 'just touched the ground',
78
+ },
79
+ states: {
80
+ // Always-hook: motor bookkeeping (coyote/buffer timers, squash, facing)
81
+ // must survive custom states like a dash, so it runs in every state.
82
+ '*': {
83
+ onUpdate({ entity }, dt) {
84
+ entity.get(PlatformerMotor)?.tick(dt);
85
+ },
86
+ },
87
+ // Fallback: a custom state without its own onUpdate keeps the full
88
+ // body update — its file only has to say what makes it special.
89
+ default: { onUpdate: playerUpdate },
90
+ idle: { onUpdate: playerUpdate },
91
+ run: { onUpdate: playerUpdate },
92
+ jump: { onUpdate: playerUpdate },
93
+ fall: { onUpdate: playerUpdate },
94
+ },
95
+ };
@@ -0,0 +1,23 @@
1
+ import { Component } from '@waica/engine';
2
+ /**
3
+ * Remembers the spawn point and puts the entity back there on death
4
+ * (falling off the world or touching a Hazard).
5
+ */
6
+ export declare class Respawnable extends Component {
7
+ static componentName: string;
8
+ static displayName: string;
9
+ static params: {
10
+ killY: {
11
+ label: string;
12
+ min: number;
13
+ max: number;
14
+ step: number;
15
+ };
16
+ };
17
+ /** Falling below this height respawns. */
18
+ killY: number;
19
+ private spawn;
20
+ onReady(): void;
21
+ respawn(): void;
22
+ onUpdate(): void;
23
+ }
@@ -0,0 +1,27 @@
1
+ import { Component, THREE } from '@waica/engine';
2
+ import { PlatformerMotor } from './platformer-motor.js';
3
+ /**
4
+ * Remembers the spawn point and puts the entity back there on death
5
+ * (falling off the world or touching a Hazard).
6
+ */
7
+ export class Respawnable extends Component {
8
+ static componentName = 'Respawnable';
9
+ static displayName = 'Respawn';
10
+ static params = {
11
+ killY: { label: 'Kill height', min: -50, max: 0, step: 1 },
12
+ };
13
+ /** Falling below this height respawns. */
14
+ killY = -12;
15
+ spawn = new THREE.Vector3();
16
+ onReady() {
17
+ this.spawn.copy(this.entity.position);
18
+ }
19
+ respawn() {
20
+ this.entity.position.copy(this.spawn);
21
+ this.entity.get(PlatformerMotor)?.halt();
22
+ }
23
+ onUpdate() {
24
+ if (this.entity.position.y < this.killY)
25
+ this.respawn();
26
+ }
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@waica/behaviors",
3
+ "version": "0.3.0",
4
+ "description": "Waica built-in behaviors — the curated game-feel library",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/chichex/waica",
10
+ "directory": "packages/behaviors"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@waica/engine": "^0.3.0"
23
+ }
24
+ }
@@ -0,0 +1,2 @@
1
+ /** Do two center+size AABBs overlap? Edges that merely touch don't count. */
2
+ export declare function aabbOverlap(ax: number, ay: number, aw: number, ah: number, bx: number, by: number, bw: number, bh: number): boolean;
@@ -0,0 +1,4 @@
1
+ /** Do two center+size AABBs overlap? Edges that merely touch don't count. */
2
+ export function aabbOverlap(ax, ay, aw, ah, bx, by, bw, bh) {
3
+ return Math.abs(ax - bx) * 2 < aw + bw && Math.abs(ay - by) * 2 < ah + bh;
4
+ }
@@ -0,0 +1,20 @@
1
+ export interface ClipDef {
2
+ /** Frame indices inside the spritesheet (row×cols + col). */
3
+ frames: number[];
4
+ fps: number;
5
+ /** Defaults to true; with false it sticks on the last frame. */
6
+ loop?: boolean;
7
+ }
8
+ /**
9
+ * Advances a clip through time. Pure logic (no three, no DOM) so it can
10
+ * be tested deterministically.
11
+ */
12
+ export declare class ClipPlayer {
13
+ private frames;
14
+ private fps;
15
+ private loop;
16
+ private t;
17
+ set(clip: ClipDef): void;
18
+ /** Advances the clock and returns the sheet frame to show. */
19
+ advance(dt: number): number;
20
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Advances a clip through time. Pure logic (no three, no DOM) so it can
3
+ * be tested deterministically.
4
+ */
5
+ export class ClipPlayer {
6
+ frames = [0];
7
+ fps = 1;
8
+ loop = true;
9
+ t = 0;
10
+ set(clip) {
11
+ this.frames = clip.frames.length > 0 ? clip.frames : [0];
12
+ this.fps = clip.fps;
13
+ this.loop = clip.loop ?? true;
14
+ this.t = 0;
15
+ }
16
+ /** Advances the clock and returns the sheet frame to show. */
17
+ advance(dt) {
18
+ this.t += dt;
19
+ const idx = Math.floor(this.t * this.fps);
20
+ const n = this.frames.length;
21
+ const clamped = this.loop ? idx % n : Math.min(idx, n - 1);
22
+ return this.frames[clamped] ?? 0;
23
+ }
24
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Animation contract: the archetype declares which clips a character
3
+ * needs and how to degrade when one is missing. It's the centerpiece of
4
+ * the "the engine tells you which assets you need" thesis (DESIGN.md §2
5
+ * and §4): the game works from minute zero with whatever is there, and
6
+ * the editor (H2) will show the gaps as a checklist.
7
+ */
8
+ export interface AnimationContract {
9
+ /** Clips the archetype expects to exist. */
10
+ required: string[];
11
+ /** Degradation chain: if a clip is missing, which one replaces it. */
12
+ fallbacks: Record<string, string>;
13
+ }
14
+ /**
15
+ * Resolves which clip to play: the requested one if it exists, otherwise
16
+ * it follows the fallback chain, and as a last resort the first available
17
+ * clip.
18
+ */
19
+ export declare function resolveClip(contract: AnimationContract, available: Iterable<string>, wanted: string): string | undefined;
20
+ /** Which contract clips are missing — what the editor will show as gaps. */
21
+ export declare function missingClips(contract: AnimationContract, available: Iterable<string>): string[];