@almadar/std 1.0.0 → 1.0.1

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 (40) hide show
  1. package/dist/behaviors/async.d.ts +8 -8
  2. package/dist/behaviors/async.js +548 -500
  3. package/dist/behaviors/async.js.map +1 -1
  4. package/dist/behaviors/data-management.d.ts +11 -19
  5. package/dist/behaviors/data-management.js +468 -449
  6. package/dist/behaviors/data-management.js.map +1 -1
  7. package/dist/behaviors/feedback.d.ts +6 -6
  8. package/dist/behaviors/feedback.js +312 -278
  9. package/dist/behaviors/feedback.js.map +1 -1
  10. package/dist/behaviors/game-core.d.ts +11 -12
  11. package/dist/behaviors/game-core.js +357 -406
  12. package/dist/behaviors/game-core.js.map +1 -1
  13. package/dist/behaviors/game-entity.d.ts +13 -14
  14. package/dist/behaviors/game-entity.js +622 -592
  15. package/dist/behaviors/game-entity.js.map +1 -1
  16. package/dist/behaviors/game-ui.d.ts +9 -10
  17. package/dist/behaviors/game-ui.js +522 -459
  18. package/dist/behaviors/game-ui.js.map +1 -1
  19. package/dist/behaviors/index.d.ts +3 -3
  20. package/dist/behaviors/index.js +3876 -3843
  21. package/dist/behaviors/index.js.map +1 -1
  22. package/dist/behaviors/registry.d.ts +14 -24
  23. package/dist/behaviors/registry.js +3868 -3803
  24. package/dist/behaviors/registry.js.map +1 -1
  25. package/dist/behaviors/types.d.ts +14 -138
  26. package/dist/behaviors/types.js +10 -47
  27. package/dist/behaviors/types.js.map +1 -1
  28. package/dist/behaviors/ui-interaction.d.ts +13 -20
  29. package/dist/behaviors/ui-interaction.js +961 -1043
  30. package/dist/behaviors/ui-interaction.js.map +1 -1
  31. package/dist/index.d.ts +44 -11
  32. package/dist/index.js +3913 -3870
  33. package/dist/index.js.map +1 -1
  34. package/dist/modules/index.js +11 -0
  35. package/dist/modules/index.js.map +1 -1
  36. package/dist/modules/str.js +11 -0
  37. package/dist/modules/str.js.map +1 -1
  38. package/dist/registry.js +11 -0
  39. package/dist/registry.js.map +1 -1
  40. package/package.json +3 -2
@@ -1,634 +1,664 @@
1
1
  // behaviors/game-entity.ts
2
2
  var HEALTH_BEHAVIOR = {
3
- name: "std/Health",
4
- category: "game-entity",
3
+ name: "std-health",
4
+ version: "1.0.0",
5
5
  description: "Entity health with damage, healing, invulnerability, and death",
6
- suggestedFor: [
7
- "Player characters",
8
- "Enemies",
9
- "Destructible objects",
10
- "Bosses"
11
- ],
12
- dataEntities: [
6
+ orbitals: [
13
7
  {
14
- name: "HealthState",
15
- runtime: true,
16
- fields: [
17
- { name: "currentHealth", type: "number", default: 100 },
18
- { name: "maxHealth", type: "number", default: 100 },
19
- { name: "isInvulnerable", type: "boolean", default: false },
20
- { name: "lastDamageTime", type: "number", default: 0 }
21
- ]
22
- }
23
- ],
24
- stateMachine: {
25
- initial: "Alive",
26
- states: [
27
- { name: "Alive", isInitial: true },
28
- { name: "Damaged" },
29
- { name: "Invulnerable" },
30
- { name: "Dead" }
31
- ],
32
- events: [
33
- { key: "INIT" },
34
- { key: "DAMAGE" },
35
- { key: "HEAL" },
36
- { key: "DIE" },
37
- { key: "RESPAWN" },
38
- { key: "INVULNERABILITY_END" }
39
- ],
40
- transitions: [
41
- {
42
- from: "*",
43
- to: "Alive",
44
- event: "INIT",
45
- effects: [
46
- ["set", "@entity.currentHealth", "@config.maxHealth"],
47
- ["set", "@entity.maxHealth", "@config.maxHealth"],
48
- ["set", "@entity.isInvulnerable", false],
49
- ["render", "hud.health", "health-bar", {
50
- current: "@entity.currentHealth",
51
- max: "@entity.maxHealth"
52
- }]
8
+ name: "HealthOrbital",
9
+ entity: {
10
+ name: "HealthState",
11
+ persistence: "runtime",
12
+ fields: [
13
+ { name: "id", type: "string", required: true },
14
+ { name: "currentHealth", type: "number", default: 100 },
15
+ { name: "maxHealth", type: "number", default: 100 },
16
+ { name: "isInvulnerable", type: "boolean", default: false },
17
+ { name: "lastDamageTime", type: "number", default: 0 },
18
+ { name: "invulnerabilityTime", type: "number", default: 1e3 },
19
+ { name: "onDeath", type: "string", default: null }
53
20
  ]
54
21
  },
55
- {
56
- from: "Alive",
57
- to: "Damaged",
58
- event: "DAMAGE",
59
- guard: ["not", "@entity.isInvulnerable"],
60
- effects: [
61
- ["set", "@entity.currentHealth", ["math/max", 0, ["-", "@entity.currentHealth", "@payload.amount"]]],
62
- ["set", "@entity.lastDamageTime", "@now"],
63
- [
64
- "if",
65
- ["<=", "@entity.currentHealth", 0],
66
- ["emit", "DIE"],
67
- [
68
- "do",
69
- ["set", "@entity.isInvulnerable", true],
70
- ["render", "entity.flash", "damage-flash", {}]
22
+ traits: [
23
+ {
24
+ name: "Health",
25
+ linkedEntity: "HealthState",
26
+ category: "interaction",
27
+ stateMachine: {
28
+ states: [
29
+ { name: "Alive", isInitial: true },
30
+ { name: "Damaged" },
31
+ { name: "Invulnerable" },
32
+ { name: "Dead", isTerminal: true }
33
+ ],
34
+ events: [
35
+ { key: "INIT", name: "Initialize" },
36
+ { key: "DAMAGE", name: "Damage" },
37
+ { key: "HEAL", name: "Heal" },
38
+ { key: "DIE", name: "Die" },
39
+ { key: "RESPAWN", name: "Respawn" },
40
+ { key: "INVULNERABILITY_END", name: "Invulnerability End" }
41
+ ],
42
+ transitions: [
43
+ {
44
+ from: "Alive",
45
+ to: "Alive",
46
+ event: "INIT",
47
+ effects: [
48
+ ["set", "@entity.currentHealth", "@entity.maxHealth"],
49
+ ["set", "@entity.isInvulnerable", false],
50
+ ["render-ui", "hud-top", {
51
+ type: "stats",
52
+ label: "Health",
53
+ value: "@entity.currentHealth"
54
+ }]
55
+ ]
56
+ },
57
+ {
58
+ from: "Alive",
59
+ to: "Damaged",
60
+ event: "DAMAGE",
61
+ guard: ["not", "@entity.isInvulnerable"],
62
+ effects: [
63
+ ["set", "@entity.currentHealth", ["math/max", 0, ["-", "@entity.currentHealth", "@payload.amount"]]],
64
+ ["set", "@entity.lastDamageTime", "@now"],
65
+ [
66
+ "if",
67
+ ["<=", "@entity.currentHealth", 0],
68
+ ["emit", "DIE"],
69
+ [
70
+ "do",
71
+ ["set", "@entity.isInvulnerable", true]
72
+ ]
73
+ ]
74
+ ]
75
+ },
76
+ {
77
+ from: "Damaged",
78
+ to: "Alive",
79
+ event: "INVULNERABILITY_END",
80
+ effects: [["set", "@entity.isInvulnerable", false]]
81
+ },
82
+ {
83
+ from: "Invulnerable",
84
+ to: "Alive",
85
+ event: "INVULNERABILITY_END",
86
+ effects: [["set", "@entity.isInvulnerable", false]]
87
+ },
88
+ {
89
+ from: "Alive",
90
+ to: "Alive",
91
+ event: "HEAL",
92
+ effects: [
93
+ ["set", "@entity.currentHealth", ["math/min", "@entity.maxHealth", ["+", "@entity.currentHealth", "@payload.amount"]]]
94
+ ]
95
+ },
96
+ {
97
+ from: "Damaged",
98
+ to: "Damaged",
99
+ event: "HEAL",
100
+ effects: [
101
+ ["set", "@entity.currentHealth", ["math/min", "@entity.maxHealth", ["+", "@entity.currentHealth", "@payload.amount"]]]
102
+ ]
103
+ },
104
+ {
105
+ from: "Alive",
106
+ to: "Dead",
107
+ event: "DIE",
108
+ effects: [
109
+ ["set", "@entity.currentHealth", 0],
110
+ ["if", "@entity.onDeath", ["emit", "@entity.onDeath", { entityId: "@entity.id" }]]
111
+ ]
112
+ },
113
+ {
114
+ from: "Damaged",
115
+ to: "Dead",
116
+ event: "DIE",
117
+ effects: [
118
+ ["set", "@entity.currentHealth", 0],
119
+ ["if", "@entity.onDeath", ["emit", "@entity.onDeath", { entityId: "@entity.id" }]]
120
+ ]
121
+ },
122
+ {
123
+ from: "Dead",
124
+ to: "Alive",
125
+ event: "RESPAWN",
126
+ effects: [["emit", "INIT"]]
127
+ }
71
128
  ]
129
+ },
130
+ ticks: [
131
+ {
132
+ name: "InvulnerabilityTimer",
133
+ interval: "frame",
134
+ guard: ["and", "@entity.isInvulnerable", [">", ["-", "@now", "@entity.lastDamageTime"], "@entity.invulnerabilityTime"]],
135
+ effects: [["emit", "INVULNERABILITY_END"]]
136
+ }
72
137
  ]
73
- ]
74
- },
75
- {
76
- from: ["Damaged", "Invulnerable"],
77
- to: "Alive",
78
- event: "INVULNERABILITY_END",
79
- effects: [
80
- ["set", "@entity.isInvulnerable", false]
81
- ]
82
- },
83
- {
84
- from: ["Alive", "Damaged", "Invulnerable"],
85
- event: "HEAL",
86
- effects: [
87
- ["set", "@entity.currentHealth", ["math/min", "@entity.maxHealth", ["+", "@entity.currentHealth", "@payload.amount"]]],
88
- ["render", "entity.effect", "heal-effect", {}]
89
- ]
90
- },
91
- {
92
- from: ["Alive", "Damaged", "Invulnerable"],
93
- to: "Dead",
94
- event: "DIE",
95
- effects: [
96
- ["set", "@entity.currentHealth", 0],
97
- ["emit", "@config.onDeath", { entityId: "@entity.id" }],
98
- ["render", "entity.sprite", "death-animation", {}]
99
- ]
100
- },
101
- {
102
- from: "Dead",
103
- to: "Alive",
104
- event: "RESPAWN",
105
- effects: [
106
- ["emit", "INIT"]
107
- ]
108
- }
109
- ]
110
- },
111
- ticks: [
112
- {
113
- name: "InvulnerabilityTimer",
114
- interval: "frame",
115
- guard: ["and", "@entity.isInvulnerable", [">", ["-", "@now", "@entity.lastDamageTime"], "@config.invulnerabilityTime"]],
116
- effects: [
117
- ["emit", "INVULNERABILITY_END"]
118
- ]
138
+ }
139
+ ],
140
+ pages: []
119
141
  }
120
- ],
121
- configSchema: {
122
- required: [
123
- { name: "maxHealth", type: "number", description: "Maximum health points" }
124
- ],
125
- optional: [
126
- { name: "invulnerabilityTime", type: "number", description: "Invulnerability duration after damage (ms)", default: 500 },
127
- { name: "onDeath", type: "event", description: "Event to emit on death", default: "ENTITY_DIED" },
128
- { name: "showHealthBar", type: "boolean", description: "Render health bar", default: true }
129
- ]
130
- }
142
+ ]
131
143
  };
132
144
  var SCORE_BEHAVIOR = {
133
- name: "std/Score",
134
- category: "game-entity",
145
+ name: "std-score",
146
+ version: "1.0.0",
135
147
  description: "Score tracking with points, combos, and multipliers",
136
- suggestedFor: [
137
- "Arcade games",
138
- "Puzzle games",
139
- "Platformers with collectibles",
140
- "Competitive games"
141
- ],
142
- dataEntities: [
148
+ orbitals: [
143
149
  {
144
- name: "ScoreState",
145
- runtime: true,
146
- singleton: true,
147
- fields: [
148
- { name: "currentScore", type: "number", default: 0 },
149
- { name: "highScore", type: "number", default: 0 },
150
- { name: "comboCount", type: "number", default: 0 },
151
- { name: "multiplier", type: "number", default: 1 },
152
- { name: "lastScoreTime", type: "number", default: 0 }
153
- ]
154
- }
155
- ],
156
- stateMachine: {
157
- initial: "Active",
158
- states: [
159
- { name: "Active", isInitial: true }
160
- ],
161
- events: [
162
- { key: "INIT" },
163
- { key: "ADD_POINTS" },
164
- { key: "COMBO_HIT" },
165
- { key: "COMBO_BREAK" },
166
- { key: "RESET" },
167
- { key: "SAVE_HIGH_SCORE" }
168
- ],
169
- transitions: [
170
- {
171
- from: "*",
172
- event: "INIT",
173
- effects: [
174
- ["set", "@entity.currentScore", 0],
175
- ["set", "@entity.comboCount", 0],
176
- ["set", "@entity.multiplier", 1],
177
- ["render", "hud.score", "score-display", {
178
- score: "@entity.currentScore",
179
- highScore: "@entity.highScore",
180
- combo: "@entity.comboCount",
181
- multiplier: "@entity.multiplier"
182
- }]
183
- ]
184
- },
185
- {
186
- event: "ADD_POINTS",
187
- effects: [
188
- ["set", "@entity.currentScore", ["+", "@entity.currentScore", ["*", "@payload.points", "@entity.multiplier"]]],
189
- ["set", "@entity.lastScoreTime", "@now"],
190
- ["render", "entity.effect", "score-popup", {
191
- points: ["*", "@payload.points", "@entity.multiplier"],
192
- position: "@payload.position"
193
- }]
194
- ]
195
- },
196
- {
197
- event: "COMBO_HIT",
198
- effects: [
199
- ["set", "@entity.comboCount", ["+", "@entity.comboCount", 1]],
200
- ["set", "@entity.multiplier", ["math/min", "@config.maxMultiplier", ["+", 1, ["/", "@entity.comboCount", 5]]]],
201
- ["set", "@entity.lastScoreTime", "@now"]
150
+ name: "ScoreOrbital",
151
+ entity: {
152
+ name: "ScoreState",
153
+ persistence: "runtime",
154
+ fields: [
155
+ { name: "id", type: "string", required: true },
156
+ { name: "currentScore", type: "number", default: 0 },
157
+ { name: "highScore", type: "number", default: 0 },
158
+ { name: "comboCount", type: "number", default: 0 },
159
+ { name: "multiplier", type: "number", default: 1 },
160
+ { name: "lastScoreTime", type: "number", default: 0 },
161
+ { name: "maxMultiplier", type: "number", default: 5 },
162
+ { name: "comboTimeWindow", type: "number", default: 2e3 }
202
163
  ]
203
164
  },
204
- {
205
- event: "COMBO_BREAK",
206
- effects: [
207
- ["set", "@entity.comboCount", 0],
208
- ["set", "@entity.multiplier", 1]
209
- ]
210
- },
211
- {
212
- event: "RESET",
213
- effects: [
214
- [
215
- "if",
216
- [">", "@entity.currentScore", "@entity.highScore"],
217
- ["set", "@entity.highScore", "@entity.currentScore"]
218
- ],
219
- ["emit", "INIT"]
220
- ]
221
- },
222
- {
223
- event: "SAVE_HIGH_SCORE",
224
- guard: [">", "@entity.currentScore", "@entity.highScore"],
225
- effects: [
226
- ["set", "@entity.highScore", "@entity.currentScore"],
227
- ["persist", "save", "HighScore", { score: "@entity.highScore" }]
228
- ]
229
- }
230
- ]
231
- },
232
- ticks: [
233
- {
234
- name: "ComboTimeout",
235
- interval: "frame",
236
- guard: ["and", [">", "@entity.comboCount", 0], [">", ["-", "@now", "@entity.lastScoreTime"], "@config.comboTimeWindow"]],
237
- effects: [
238
- ["emit", "COMBO_BREAK"]
239
- ]
165
+ traits: [
166
+ {
167
+ name: "Score",
168
+ linkedEntity: "ScoreState",
169
+ category: "interaction",
170
+ stateMachine: {
171
+ states: [{ name: "Active", isInitial: true }],
172
+ events: [
173
+ { key: "INIT", name: "Initialize" },
174
+ { key: "ADD_POINTS", name: "Add Points" },
175
+ { key: "COMBO_HIT", name: "Combo Hit" },
176
+ { key: "COMBO_BREAK", name: "Combo Break" },
177
+ { key: "RESET", name: "Reset" },
178
+ { key: "SAVE_HIGH_SCORE", name: "Save High Score" }
179
+ ],
180
+ transitions: [
181
+ {
182
+ from: "Active",
183
+ to: "Active",
184
+ event: "INIT",
185
+ effects: [
186
+ ["set", "@entity.currentScore", 0],
187
+ ["set", "@entity.comboCount", 0],
188
+ ["set", "@entity.multiplier", 1],
189
+ ["render-ui", "hud-top", {
190
+ type: "stats",
191
+ label: "Score",
192
+ value: "@entity.currentScore",
193
+ subtitle: "High: @entity.highScore"
194
+ }]
195
+ ]
196
+ },
197
+ {
198
+ from: "Active",
199
+ to: "Active",
200
+ event: "ADD_POINTS",
201
+ effects: [
202
+ ["set", "@entity.currentScore", ["+", "@entity.currentScore", ["*", "@payload.points", "@entity.multiplier"]]],
203
+ ["set", "@entity.lastScoreTime", "@now"]
204
+ ]
205
+ },
206
+ {
207
+ from: "Active",
208
+ to: "Active",
209
+ event: "COMBO_HIT",
210
+ effects: [
211
+ ["set", "@entity.comboCount", ["+", "@entity.comboCount", 1]],
212
+ ["set", "@entity.multiplier", ["math/min", "@entity.maxMultiplier", ["+", 1, ["/", "@entity.comboCount", 5]]]],
213
+ ["set", "@entity.lastScoreTime", "@now"]
214
+ ]
215
+ },
216
+ {
217
+ from: "Active",
218
+ to: "Active",
219
+ event: "COMBO_BREAK",
220
+ effects: [
221
+ ["set", "@entity.comboCount", 0],
222
+ ["set", "@entity.multiplier", 1]
223
+ ]
224
+ },
225
+ {
226
+ from: "Active",
227
+ to: "Active",
228
+ event: "RESET",
229
+ effects: [
230
+ [
231
+ "if",
232
+ [">", "@entity.currentScore", "@entity.highScore"],
233
+ ["set", "@entity.highScore", "@entity.currentScore"]
234
+ ],
235
+ ["emit", "INIT"]
236
+ ]
237
+ },
238
+ {
239
+ from: "Active",
240
+ to: "Active",
241
+ event: "SAVE_HIGH_SCORE",
242
+ guard: [">", "@entity.currentScore", "@entity.highScore"],
243
+ effects: [
244
+ ["set", "@entity.highScore", "@entity.currentScore"],
245
+ ["persist", "update", "HighScore", { score: "@entity.highScore" }]
246
+ ]
247
+ }
248
+ ]
249
+ },
250
+ ticks: [
251
+ {
252
+ name: "ComboTimeout",
253
+ interval: "frame",
254
+ guard: ["and", [">", "@entity.comboCount", 0], [">", ["-", "@now", "@entity.lastScoreTime"], "@entity.comboTimeWindow"]],
255
+ effects: [["emit", "COMBO_BREAK"]]
256
+ }
257
+ ]
258
+ }
259
+ ],
260
+ pages: []
240
261
  }
241
- ],
242
- configSchema: {
243
- required: [],
244
- optional: [
245
- { name: "comboTimeWindow", type: "number", description: "Time window for combos (ms)", default: 2e3 },
246
- { name: "maxMultiplier", type: "number", description: "Maximum combo multiplier", default: 10 },
247
- { name: "persistHighScore", type: "boolean", description: "Save high score to storage", default: true }
248
- ]
249
- }
262
+ ]
250
263
  };
251
264
  var MOVEMENT_BEHAVIOR = {
252
- name: "std/Movement",
253
- category: "game-entity",
265
+ name: "std-movement",
266
+ version: "1.0.0",
254
267
  description: "Entity movement with speed and direction",
255
- suggestedFor: [
256
- "Player characters",
257
- "NPCs",
258
- "Enemies",
259
- "Moving platforms"
260
- ],
261
- requiredFields: [
262
- { name: "x", type: "number", description: "Entity X position" },
263
- { name: "y", type: "number", description: "Entity Y position" }
264
- ],
265
- dataEntities: [
268
+ orbitals: [
266
269
  {
267
- name: "MovementState",
268
- runtime: true,
269
- fields: [
270
- { name: "direction", type: "number", default: 0 },
271
- { name: "facingRight", type: "boolean", default: true },
272
- { name: "canJump", type: "boolean", default: true }
273
- ]
274
- }
275
- ],
276
- stateMachine: {
277
- initial: "Idle",
278
- states: [
279
- { name: "Idle", isInitial: true },
280
- { name: "Moving" },
281
- { name: "Jumping" },
282
- { name: "Falling" }
283
- ],
284
- events: [
285
- { key: "MOVE" },
286
- { key: "STOP" },
287
- { key: "JUMP" },
288
- { key: "LAND" }
289
- ],
290
- transitions: [
291
- {
292
- from: "Idle",
293
- to: "Moving",
294
- event: "MOVE",
295
- effects: [
296
- ["set", "@entity.direction", "@payload.direction"],
297
- [
298
- "if",
299
- [">", "@payload.direction", 0],
300
- ["set", "@entity.facingRight", true]
301
- ],
302
- [
303
- "if",
304
- ["<", "@payload.direction", 0],
305
- ["set", "@entity.facingRight", false]
306
- ]
307
- ]
308
- },
309
- {
310
- from: "Moving",
311
- event: "MOVE",
312
- effects: [
313
- ["set", "@entity.direction", "@payload.direction"],
314
- [
315
- "if",
316
- [">", "@payload.direction", 0],
317
- ["set", "@entity.facingRight", true]
318
- ],
319
- [
320
- "if",
321
- ["<", "@payload.direction", 0],
322
- ["set", "@entity.facingRight", false]
323
- ]
324
- ]
325
- },
326
- {
327
- from: "Moving",
328
- to: "Idle",
329
- event: "STOP",
330
- effects: [
331
- ["set", "@entity.direction", 0]
270
+ name: "MovementOrbital",
271
+ entity: {
272
+ name: "MovementState",
273
+ persistence: "runtime",
274
+ fields: [
275
+ { name: "id", type: "string", required: true },
276
+ { name: "x", type: "number", default: 0 },
277
+ { name: "y", type: "number", default: 0 },
278
+ { name: "direction", type: "number", default: 0 },
279
+ { name: "facingRight", type: "boolean", default: true },
280
+ { name: "canJump", type: "boolean", default: true },
281
+ { name: "moveSpeed", type: "number", default: 5 },
282
+ { name: "jumpForce", type: "number", default: -15 }
332
283
  ]
333
284
  },
334
- {
335
- from: ["Idle", "Moving"],
336
- to: "Jumping",
337
- event: "JUMP",
338
- guard: "@entity.canJump",
339
- effects: [
340
- ["set", "@entity.canJump", false],
341
- ["emit", "APPLY_FORCE", { fx: 0, fy: "@config.jumpForce" }]
342
- ]
343
- },
344
- {
345
- from: ["Jumping", "Falling"],
346
- to: "Idle",
347
- event: "LAND",
348
- effects: [
349
- ["set", "@entity.canJump", true],
350
- [
351
- "if",
352
- ["!=", "@entity.direction", 0],
353
- ["emit", "MOVE", { direction: "@entity.direction" }]
285
+ traits: [
286
+ {
287
+ name: "Movement",
288
+ linkedEntity: "MovementState",
289
+ category: "interaction",
290
+ stateMachine: {
291
+ states: [
292
+ { name: "Idle", isInitial: true },
293
+ { name: "Moving" },
294
+ { name: "Jumping" },
295
+ { name: "Falling" }
296
+ ],
297
+ events: [
298
+ { key: "MOVE", name: "Move" },
299
+ { key: "STOP", name: "Stop" },
300
+ { key: "JUMP", name: "Jump" },
301
+ { key: "LAND", name: "Land" }
302
+ ],
303
+ transitions: [
304
+ {
305
+ from: "Idle",
306
+ to: "Moving",
307
+ event: "MOVE",
308
+ effects: [
309
+ ["set", "@entity.direction", "@payload.direction"],
310
+ ["if", [">", "@payload.direction", 0], ["set", "@entity.facingRight", true]],
311
+ ["if", ["<", "@payload.direction", 0], ["set", "@entity.facingRight", false]]
312
+ ]
313
+ },
314
+ {
315
+ from: "Moving",
316
+ to: "Moving",
317
+ event: "MOVE",
318
+ effects: [
319
+ ["set", "@entity.direction", "@payload.direction"],
320
+ ["if", [">", "@payload.direction", 0], ["set", "@entity.facingRight", true]],
321
+ ["if", ["<", "@payload.direction", 0], ["set", "@entity.facingRight", false]]
322
+ ]
323
+ },
324
+ {
325
+ from: "Moving",
326
+ to: "Idle",
327
+ event: "STOP",
328
+ effects: [["set", "@entity.direction", 0]]
329
+ },
330
+ {
331
+ from: "Idle",
332
+ to: "Jumping",
333
+ event: "JUMP",
334
+ guard: "@entity.canJump",
335
+ effects: [
336
+ ["set", "@entity.canJump", false],
337
+ ["emit", "APPLY_FORCE", { fx: 0, fy: "@entity.jumpForce" }]
338
+ ]
339
+ },
340
+ {
341
+ from: "Moving",
342
+ to: "Jumping",
343
+ event: "JUMP",
344
+ guard: "@entity.canJump",
345
+ effects: [
346
+ ["set", "@entity.canJump", false],
347
+ ["emit", "APPLY_FORCE", { fx: 0, fy: "@entity.jumpForce" }]
348
+ ]
349
+ },
350
+ {
351
+ from: "Jumping",
352
+ to: "Idle",
353
+ event: "LAND",
354
+ effects: [
355
+ ["set", "@entity.canJump", true],
356
+ ["if", ["!=", "@entity.direction", 0], ["emit", "MOVE", { direction: "@entity.direction" }]]
357
+ ]
358
+ },
359
+ {
360
+ from: "Falling",
361
+ to: "Idle",
362
+ event: "LAND",
363
+ effects: [
364
+ ["set", "@entity.canJump", true],
365
+ ["if", ["!=", "@entity.direction", 0], ["emit", "MOVE", { direction: "@entity.direction" }]]
366
+ ]
367
+ }
368
+ ]
369
+ },
370
+ ticks: [
371
+ {
372
+ name: "ApplyMovement",
373
+ interval: "frame",
374
+ guard: ["!=", "@entity.direction", 0],
375
+ effects: [
376
+ ["set", "@entity.x", ["+", "@entity.x", ["*", "@entity.direction", "@entity.moveSpeed"]]]
377
+ ]
378
+ }
354
379
  ]
355
- ]
356
- }
357
- ]
358
- },
359
- ticks: [
360
- {
361
- name: "ApplyMovement",
362
- interval: "frame",
363
- guard: ["!=", "@entity.direction", 0],
364
- effects: [
365
- ["set", "@entity.x", ["+", "@entity.x", ["*", "@entity.direction", "@config.moveSpeed"]]]
366
- ]
380
+ }
381
+ ],
382
+ pages: []
367
383
  }
368
- ],
369
- configSchema: {
370
- required: [],
371
- optional: [
372
- { name: "moveSpeed", type: "number", description: "Movement speed (pixels/frame)", default: 5 },
373
- { name: "jumpForce", type: "number", description: "Jump velocity", default: -12 },
374
- { name: "acceleration", type: "number", description: "Acceleration rate", default: 0.5 },
375
- { name: "deceleration", type: "number", description: "Deceleration rate", default: 0.3 }
376
- ]
377
- }
384
+ ]
378
385
  };
379
386
  var COMBAT_BEHAVIOR = {
380
- name: "std/Combat",
381
- category: "game-entity",
387
+ name: "std-combat",
388
+ version: "1.0.0",
382
389
  description: "Combat system with attacks, cooldowns, and hitboxes",
383
- suggestedFor: [
384
- "Fighting games",
385
- "Action RPGs",
386
- "Beat-em-ups",
387
- "Boss encounters"
388
- ],
389
- dataEntities: [
390
+ orbitals: [
390
391
  {
391
- name: "CombatState",
392
- runtime: true,
393
- fields: [
394
- { name: "isAttacking", type: "boolean", default: false },
395
- { name: "attackStartTime", type: "number", default: 0 },
396
- { name: "hitEntities", type: "array", default: [] }
397
- ]
398
- }
399
- ],
400
- stateMachine: {
401
- initial: "Ready",
402
- states: [
403
- { name: "Ready", isInitial: true },
404
- { name: "Attacking" },
405
- { name: "Cooldown" }
406
- ],
407
- events: [
408
- { key: "ATTACK" },
409
- { key: "ATTACK_END" },
410
- { key: "HIT_CONNECT" },
411
- { key: "COOLDOWN_END" }
412
- ],
413
- transitions: [
414
- {
415
- from: "Ready",
416
- to: "Attacking",
417
- event: "ATTACK",
418
- effects: [
419
- ["set", "@entity.isAttacking", true],
420
- ["set", "@entity.attackStartTime", "@now"],
421
- ["set", "@entity.hitEntities", []],
422
- ["render", "entity.sprite", "attack-animation", {}],
423
- ["render", "entity.hitbox", "hitbox", {
424
- active: true,
425
- offset: "@config.hitboxOffset",
426
- size: "@config.hitboxSize"
427
- }]
428
- ]
429
- },
430
- {
431
- from: "Attacking",
432
- event: "HIT_CONNECT",
433
- guard: ["not", ["array/includes", "@entity.hitEntities", "@payload.entityId"]],
434
- effects: [
435
- ["set", "@entity.hitEntities", ["array/append", "@entity.hitEntities", "@payload.entityId"]],
436
- ["emit", "DAMAGE", { target: "@payload.entityId", amount: "@config.attackDamage" }],
437
- ["render", "effect.impact", "hit-effect", { position: "@payload.position" }]
392
+ name: "CombatOrbital",
393
+ entity: {
394
+ name: "CombatState",
395
+ persistence: "runtime",
396
+ fields: [
397
+ { name: "id", type: "string", required: true },
398
+ { name: "isAttacking", type: "boolean", default: false },
399
+ { name: "attackStartTime", type: "number", default: 0 },
400
+ { name: "hitEntities", type: "array", default: [] },
401
+ { name: "attackDamage", type: "number", default: 10 },
402
+ { name: "attackDuration", type: "number", default: 300 },
403
+ { name: "cooldownDuration", type: "number", default: 500 },
404
+ { name: "hitboxOffset", type: "object", default: { x: 20, y: 0 } },
405
+ { name: "hitboxSize", type: "object", default: { width: 30, height: 30 } }
438
406
  ]
439
407
  },
440
- {
441
- from: "Attacking",
442
- to: "Cooldown",
443
- event: "ATTACK_END",
444
- effects: [
445
- ["set", "@entity.isAttacking", false],
446
- ["render", "entity.hitbox", null]
447
- ]
448
- },
449
- {
450
- from: "Cooldown",
451
- to: "Ready",
452
- event: "COOLDOWN_END",
453
- effects: []
454
- }
455
- ]
456
- },
457
- ticks: [
458
- {
459
- name: "AttackDuration",
460
- interval: "frame",
461
- guard: ["and", "@entity.isAttacking", [">", ["-", "@now", "@entity.attackStartTime"], "@config.attackDuration"]],
462
- effects: [
463
- ["emit", "ATTACK_END"]
464
- ]
465
- },
466
- {
467
- name: "CooldownTimer",
468
- interval: "frame",
469
- guard: ["and", ["=", "@state", "Cooldown"], [">", ["-", "@now", "@entity.attackStartTime"], ["+", "@config.attackDuration", "@config.cooldownDuration"]]],
470
- effects: [
471
- ["emit", "COOLDOWN_END"]
472
- ]
408
+ traits: [
409
+ {
410
+ name: "Combat",
411
+ linkedEntity: "CombatState",
412
+ category: "interaction",
413
+ stateMachine: {
414
+ states: [
415
+ { name: "Ready", isInitial: true },
416
+ { name: "Attacking" },
417
+ { name: "Cooldown" }
418
+ ],
419
+ events: [
420
+ { key: "ATTACK", name: "Attack" },
421
+ { key: "ATTACK_END", name: "Attack End" },
422
+ { key: "HIT_CONNECT", name: "Hit Connect" },
423
+ { key: "COOLDOWN_END", name: "Cooldown End" }
424
+ ],
425
+ transitions: [
426
+ {
427
+ from: "Ready",
428
+ to: "Attacking",
429
+ event: "ATTACK",
430
+ effects: [
431
+ ["set", "@entity.isAttacking", true],
432
+ ["set", "@entity.attackStartTime", "@now"],
433
+ ["set", "@entity.hitEntities", []]
434
+ ]
435
+ },
436
+ {
437
+ from: "Attacking",
438
+ to: "Attacking",
439
+ event: "HIT_CONNECT",
440
+ guard: ["not", ["array/includes", "@entity.hitEntities", "@payload.entityId"]],
441
+ effects: [
442
+ ["set", "@entity.hitEntities", ["array/append", "@entity.hitEntities", "@payload.entityId"]],
443
+ ["emit", "DAMAGE", { target: "@payload.entityId", amount: "@entity.attackDamage" }]
444
+ ]
445
+ },
446
+ {
447
+ from: "Attacking",
448
+ to: "Cooldown",
449
+ event: "ATTACK_END",
450
+ effects: [["set", "@entity.isAttacking", false]]
451
+ },
452
+ {
453
+ from: "Cooldown",
454
+ to: "Ready",
455
+ event: "COOLDOWN_END",
456
+ effects: []
457
+ }
458
+ ]
459
+ },
460
+ ticks: [
461
+ {
462
+ name: "AttackDuration",
463
+ interval: "frame",
464
+ guard: ["and", "@entity.isAttacking", [">", ["-", "@now", "@entity.attackStartTime"], "@entity.attackDuration"]],
465
+ effects: [["emit", "ATTACK_END"]]
466
+ },
467
+ {
468
+ name: "CooldownTimer",
469
+ interval: "frame",
470
+ guard: ["and", ["=", "@state", "Cooldown"], [">", ["-", "@now", "@entity.attackStartTime"], ["+", "@entity.attackDuration", "@entity.cooldownDuration"]]],
471
+ effects: [["emit", "COOLDOWN_END"]]
472
+ }
473
+ ]
474
+ }
475
+ ],
476
+ pages: []
473
477
  }
474
- ],
475
- configSchema: {
476
- required: [],
477
- optional: [
478
- { name: "attackDamage", type: "number", description: "Damage per attack", default: 10 },
479
- { name: "attackDuration", type: "number", description: "Attack animation duration (ms)", default: 200 },
480
- { name: "cooldownDuration", type: "number", description: "Cooldown between attacks (ms)", default: 300 },
481
- { name: "hitboxOffset", type: "object", description: "Hitbox offset from entity", default: { x: 20, y: 0 } },
482
- { name: "hitboxSize", type: "object", description: "Hitbox dimensions", default: { width: 30, height: 40 } }
483
- ]
484
- }
478
+ ]
485
479
  };
486
480
  var INVENTORY_BEHAVIOR = {
487
- name: "std/Inventory",
488
- category: "game-entity",
481
+ name: "std-inventory",
482
+ version: "1.0.0",
489
483
  description: "Item collection, storage, and usage",
490
- suggestedFor: [
491
- "RPGs",
492
- "Adventure games",
493
- "Survival games",
494
- "Collectible-based games"
495
- ],
496
- dataEntities: [
484
+ orbitals: [
497
485
  {
498
- name: "InventoryState",
499
- runtime: true,
500
- fields: [
501
- { name: "items", type: "array", default: [] },
502
- { name: "selectedSlot", type: "number", default: 0 },
503
- { name: "isOpen", type: "boolean", default: false },
504
- { name: "equipped", type: "object", default: {} }
505
- ]
506
- }
507
- ],
508
- stateMachine: {
509
- initial: "Empty",
510
- states: [
511
- { name: "Empty", isInitial: true },
512
- { name: "HasItems" },
513
- { name: "Full" }
514
- ],
515
- events: [
516
- { key: "COLLECT" },
517
- { key: "USE" },
518
- { key: "DROP" },
519
- { key: "EQUIP" },
520
- { key: "UNEQUIP" },
521
- { key: "OPEN" },
522
- { key: "CLOSE" },
523
- { key: "INVENTORY_EMPTY" }
524
- ],
525
- transitions: [
526
- {
527
- from: ["Empty", "HasItems"],
528
- to: "HasItems",
529
- event: "COLLECT",
530
- guard: ["<", ["array/len", "@entity.items"], "@config.maxSlots"],
531
- effects: [
532
- ["set", "@entity.items", ["array/append", "@entity.items", "@payload.item"]],
533
- ["render", "effect.collect", "collect-effect", { item: "@payload.item" }],
534
- ["notify", { type: "info", message: ["str/concat", "Collected ", "@payload.item.name"] }]
486
+ name: "InventoryOrbital",
487
+ entity: {
488
+ name: "InventoryState",
489
+ persistence: "runtime",
490
+ fields: [
491
+ { name: "id", type: "string", required: true },
492
+ { name: "x", type: "number", default: 0 },
493
+ { name: "y", type: "number", default: 0 },
494
+ { name: "items", type: "array", default: [] },
495
+ { name: "selectedSlot", type: "number", default: 0 },
496
+ { name: "isOpen", type: "boolean", default: false },
497
+ { name: "equipped", type: "object", default: {} },
498
+ { name: "maxSlots", type: "number", default: 20 }
535
499
  ]
536
500
  },
537
- {
538
- from: "HasItems",
539
- event: "USE",
540
- effects: [
541
- [
542
- "let",
543
- [["item", ["array/nth", "@entity.items", "@payload.slot"]]],
544
- [
545
- "if",
546
- "@item.onUse",
547
- ["emit", "@item.onUse", { item: "@item" }]
501
+ traits: [
502
+ {
503
+ name: "Inventory",
504
+ linkedEntity: "InventoryState",
505
+ category: "interaction",
506
+ stateMachine: {
507
+ states: [
508
+ { name: "Empty", isInitial: true },
509
+ { name: "HasItems" },
510
+ { name: "Full" }
511
+ ],
512
+ events: [
513
+ { key: "COLLECT", name: "Collect" },
514
+ { key: "USE", name: "Use" },
515
+ { key: "DROP", name: "Drop" },
516
+ { key: "EQUIP", name: "Equip" },
517
+ { key: "UNEQUIP", name: "Unequip" },
518
+ { key: "OPEN", name: "Open" },
519
+ { key: "CLOSE", name: "Close" },
520
+ { key: "INVENTORY_EMPTY", name: "Inventory Empty" }
548
521
  ],
549
- [
550
- "if",
551
- "@item.consumable",
552
- ["set", "@entity.items", ["array/filter", "@entity.items", ["fn", "i", "idx", ["!=", "@idx", "@payload.slot"]]]]
522
+ transitions: [
523
+ {
524
+ from: "Empty",
525
+ to: "HasItems",
526
+ event: "COLLECT",
527
+ guard: ["<", ["array/len", "@entity.items"], "@entity.maxSlots"],
528
+ effects: [
529
+ ["set", "@entity.items", ["array/append", "@entity.items", "@payload.item"]],
530
+ ["notify", "in_app", ["str/concat", "Collected ", "@payload.item.name"]]
531
+ ]
532
+ },
533
+ {
534
+ from: "HasItems",
535
+ to: "HasItems",
536
+ event: "COLLECT",
537
+ guard: ["<", ["array/len", "@entity.items"], "@entity.maxSlots"],
538
+ effects: [
539
+ ["set", "@entity.items", ["array/append", "@entity.items", "@payload.item"]],
540
+ ["notify", "in_app", ["str/concat", "Collected ", "@payload.item.name"]]
541
+ ]
542
+ },
543
+ {
544
+ from: "HasItems",
545
+ to: "HasItems",
546
+ event: "USE",
547
+ effects: [
548
+ [
549
+ "let",
550
+ [["item", ["array/nth", "@entity.items", "@payload.slot"]]],
551
+ ["if", "@item.onUse", ["emit", "@item.onUse", { item: "@item" }]],
552
+ [
553
+ "if",
554
+ "@item.consumable",
555
+ ["set", "@entity.items", ["array/filter", "@entity.items", ["fn", "i", "idx", ["!=", "@idx", "@payload.slot"]]]]
556
+ ]
557
+ ],
558
+ ["if", ["=", ["array/len", "@entity.items"], 0], ["emit", "INVENTORY_EMPTY"]]
559
+ ]
560
+ },
561
+ {
562
+ from: "HasItems",
563
+ to: "HasItems",
564
+ event: "DROP",
565
+ effects: [
566
+ [
567
+ "let",
568
+ [["item", ["array/nth", "@entity.items", "@payload.slot"]]],
569
+ ["set", "@entity.items", ["array/filter", "@entity.items", ["fn", "i", "idx", ["!=", "@idx", "@payload.slot"]]]],
570
+ ["emit", "ITEM_DROPPED", { item: "@item", position: { x: "@entity.x", y: "@entity.y" } }]
571
+ ],
572
+ ["if", ["=", ["array/len", "@entity.items"], 0], ["emit", "INVENTORY_EMPTY"]]
573
+ ]
574
+ },
575
+ {
576
+ from: "HasItems",
577
+ to: "Empty",
578
+ event: "INVENTORY_EMPTY",
579
+ effects: []
580
+ },
581
+ {
582
+ from: "Empty",
583
+ to: "Empty",
584
+ event: "EQUIP",
585
+ effects: [
586
+ ["set", "@entity.equipped", ["object/set", "@entity.equipped", "@payload.slot", "@payload.item"]],
587
+ ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
588
+ ]
589
+ },
590
+ {
591
+ from: "HasItems",
592
+ to: "HasItems",
593
+ event: "EQUIP",
594
+ effects: [
595
+ ["set", "@entity.equipped", ["object/set", "@entity.equipped", "@payload.slot", "@payload.item"]],
596
+ ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
597
+ ]
598
+ },
599
+ {
600
+ from: "Empty",
601
+ to: "Empty",
602
+ event: "UNEQUIP",
603
+ effects: [
604
+ ["set", "@entity.equipped", ["object/remove", "@entity.equipped", "@payload.slot"]],
605
+ ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
606
+ ]
607
+ },
608
+ {
609
+ from: "HasItems",
610
+ to: "HasItems",
611
+ event: "UNEQUIP",
612
+ effects: [
613
+ ["set", "@entity.equipped", ["object/remove", "@entity.equipped", "@payload.slot"]],
614
+ ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
615
+ ]
616
+ },
617
+ {
618
+ from: "Empty",
619
+ to: "Empty",
620
+ event: "OPEN",
621
+ effects: [
622
+ ["render-ui", "modal", {
623
+ type: "modal",
624
+ title: "Inventory",
625
+ isOpen: "@entity.isOpen",
626
+ onClose: "CLOSE"
627
+ }]
628
+ ]
629
+ },
630
+ {
631
+ from: "HasItems",
632
+ to: "HasItems",
633
+ event: "OPEN",
634
+ effects: [
635
+ ["render-ui", "modal", {
636
+ type: "modal",
637
+ title: "Inventory",
638
+ isOpen: "@entity.isOpen",
639
+ onClose: "CLOSE"
640
+ }]
641
+ ]
642
+ },
643
+ {
644
+ from: "Empty",
645
+ to: "Empty",
646
+ event: "CLOSE",
647
+ effects: [["set", "@entity.isOpen", false]]
648
+ },
649
+ {
650
+ from: "HasItems",
651
+ to: "HasItems",
652
+ event: "CLOSE",
653
+ effects: [["set", "@entity.isOpen", false]]
654
+ }
553
655
  ]
554
- ],
555
- [
556
- "if",
557
- ["=", ["array/len", "@entity.items"], 0],
558
- ["emit", "INVENTORY_EMPTY"]
559
- ]
560
- ]
561
- },
562
- {
563
- from: "HasItems",
564
- event: "DROP",
565
- effects: [
566
- [
567
- "let",
568
- [["item", ["array/nth", "@entity.items", "@payload.slot"]]],
569
- ["set", "@entity.items", ["array/filter", "@entity.items", ["fn", "i", "idx", ["!=", "@idx", "@payload.slot"]]]],
570
- ["emit", "ITEM_DROPPED", { item: "@item", position: { x: "@entity.x", y: "@entity.y" } }]
571
- ],
572
- [
573
- "if",
574
- ["=", ["array/len", "@entity.items"], 0],
575
- ["emit", "INVENTORY_EMPTY"]
576
- ]
577
- ]
578
- },
579
- {
580
- from: "HasItems",
581
- to: "Empty",
582
- event: "INVENTORY_EMPTY",
583
- effects: []
584
- },
585
- {
586
- event: "EQUIP",
587
- effects: [
588
- ["set", "@entity.equipped", ["object/set", "@entity.equipped", "@payload.slot", "@payload.item"]],
589
- ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
590
- ]
591
- },
592
- {
593
- event: "UNEQUIP",
594
- effects: [
595
- ["set", "@entity.equipped", ["object/remove", "@entity.equipped", "@payload.slot"]],
596
- ["emit", "STATS_UPDATED", { equipped: "@entity.equipped" }]
597
- ]
598
- },
599
- {
600
- event: "OPEN",
601
- effects: [
602
- ["set", "@entity.isOpen", true],
603
- ["render", "overlay.inventory", "inventory-panel", {
604
- items: "@entity.items",
605
- selectedSlot: "@entity.selectedSlot",
606
- equipped: "@entity.equipped",
607
- maxSlots: "@config.maxSlots",
608
- onUse: "USE",
609
- onDrop: "DROP",
610
- onEquip: "EQUIP",
611
- onClose: "CLOSE"
612
- }]
613
- ]
614
- },
615
- {
616
- event: "CLOSE",
617
- effects: [
618
- ["set", "@entity.isOpen", false],
619
- ["render", "overlay.inventory", null]
620
- ]
621
- }
622
- ]
623
- },
624
- configSchema: {
625
- required: [],
626
- optional: [
627
- { name: "maxSlots", type: "number", description: "Maximum inventory slots", default: 20 },
628
- { name: "stackable", type: "boolean", description: "Allow item stacking", default: true },
629
- { name: "maxStack", type: "number", description: "Maximum stack size", default: 99 }
630
- ]
631
- }
656
+ }
657
+ }
658
+ ],
659
+ pages: []
660
+ }
661
+ ]
632
662
  };
633
663
  var GAME_ENTITY_BEHAVIORS = [
634
664
  HEALTH_BEHAVIOR,