@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,486 +1,549 @@
1
1
  // behaviors/game-ui.ts
2
2
  var GAME_FLOW_BEHAVIOR = {
3
- name: "std/GameFlow",
4
- category: "game-ui",
3
+ name: "std-gameflow",
4
+ version: "1.0.0",
5
5
  description: "Master game flow: menu, play, pause, game over, victory",
6
- suggestedFor: [
7
- "All games",
8
- "Game state management",
9
- "Menu systems",
10
- "Win/lose conditions"
11
- ],
12
- dataEntities: [
6
+ orbitals: [
13
7
  {
14
- name: "GameFlowState",
15
- runtime: true,
16
- singleton: true,
17
- fields: [
18
- { name: "playTime", type: "number", default: 0 },
19
- { name: "attempts", type: "number", default: 0 },
20
- { name: "lastState", type: "string", default: "Menu" }
21
- ]
22
- }
23
- ],
24
- stateMachine: {
25
- initial: "Menu",
26
- states: [
27
- { name: "Menu", isInitial: true },
28
- { name: "Playing" },
29
- { name: "Paused" },
30
- { name: "GameOver" },
31
- { name: "Victory" }
32
- ],
33
- events: [
34
- { key: "START" },
35
- { key: "PAUSE" },
36
- { key: "RESUME" },
37
- { key: "GAME_OVER" },
38
- { key: "VICTORY" },
39
- { key: "RESTART" },
40
- { key: "QUIT" }
41
- ],
42
- transitions: [
43
- {
44
- from: "*",
45
- to: "Menu",
46
- event: "QUIT",
47
- effects: [
48
- ["emit", "STOP"],
49
- ["render", "screen", "game-menu", {
50
- title: "@config.title",
51
- onStart: "START"
52
- }]
53
- ]
54
- },
55
- {
56
- from: "Menu",
57
- to: "Playing",
58
- event: "START",
59
- effects: [
60
- ["set", "@entity.attempts", ["+", "@entity.attempts", 1]],
61
- ["set", "@entity.playTime", 0],
62
- ["emit", "GAME_LOOP_START"],
63
- ["render", "screen", null],
64
- ["render", "canvas", "game-canvas", {}]
65
- ]
66
- },
67
- {
68
- from: "Playing",
69
- to: "Paused",
70
- event: "PAUSE",
71
- guard: "@config.allowPause",
72
- effects: [
73
- ["set", "@entity.lastState", "Playing"],
74
- ["emit", "GAME_LOOP_PAUSE"],
75
- ["render", "overlay", "game-pause-overlay", {
76
- onResume: "RESUME",
77
- onQuit: "QUIT",
78
- playTime: "@entity.playTime"
79
- }]
80
- ]
81
- },
82
- {
83
- from: "Paused",
84
- to: "Playing",
85
- event: "RESUME",
86
- effects: [
87
- ["emit", "GAME_LOOP_RESUME"],
88
- ["render", "overlay", null]
89
- ]
90
- },
91
- {
92
- from: "Playing",
93
- to: "GameOver",
94
- event: "GAME_OVER",
95
- effects: [
96
- ["emit", "STOP"],
97
- ["render", "overlay", "game-over-screen", {
98
- victory: false,
99
- playTime: "@entity.playTime",
100
- attempts: "@entity.attempts",
101
- onRestart: "RESTART",
102
- onQuit: "QUIT"
103
- }]
8
+ name: "GameFlowOrbital",
9
+ entity: {
10
+ name: "GameFlowState",
11
+ persistence: "runtime",
12
+ fields: [
13
+ { name: "id", type: "string", required: true },
14
+ { name: "playTime", type: "number", default: 0 },
15
+ { name: "attempts", type: "number", default: 0 },
16
+ { name: "lastState", type: "string", default: "Menu" },
17
+ { name: "title", type: "string", default: "Game" },
18
+ { name: "allowPause", type: "boolean", default: true }
104
19
  ]
105
20
  },
106
- {
107
- from: "Playing",
108
- to: "Victory",
109
- event: "VICTORY",
110
- effects: [
111
- ["emit", "STOP"],
112
- ["render", "overlay", "game-over-screen", {
113
- victory: true,
114
- playTime: "@entity.playTime",
115
- attempts: "@entity.attempts",
116
- onRestart: "RESTART",
117
- onQuit: "QUIT"
118
- }]
119
- ]
120
- },
121
- {
122
- from: ["GameOver", "Victory"],
123
- to: "Playing",
124
- event: "RESTART",
125
- effects: [
126
- ["render", "overlay", null],
127
- ["emit", "GAME_RESET"],
128
- ["emit", "START"]
129
- ]
130
- }
131
- ]
132
- },
133
- configSchema: {
134
- required: [],
135
- optional: [
136
- { name: "title", type: "string", description: "Game title", default: "Game" },
137
- { name: "showMenu", type: "boolean", description: "Show main menu", default: true },
138
- { name: "allowPause", type: "boolean", description: "Allow pausing", default: true }
139
- ]
140
- }
21
+ traits: [
22
+ {
23
+ name: "GameFlow",
24
+ linkedEntity: "GameFlowState",
25
+ category: "interaction",
26
+ stateMachine: {
27
+ states: [
28
+ { name: "Menu", isInitial: true },
29
+ { name: "Playing" },
30
+ { name: "Paused" },
31
+ { name: "GameOver", isTerminal: true },
32
+ { name: "Victory", isTerminal: true }
33
+ ],
34
+ events: [
35
+ { key: "START", name: "Start" },
36
+ { key: "PAUSE", name: "Pause" },
37
+ { key: "RESUME", name: "Resume" },
38
+ { key: "GAME_OVER", name: "Game Over" },
39
+ { key: "VICTORY", name: "Victory" },
40
+ { key: "RESTART", name: "Restart" },
41
+ { key: "QUIT", name: "Quit" }
42
+ ],
43
+ transitions: [
44
+ {
45
+ from: "Menu",
46
+ to: "Menu",
47
+ event: "QUIT",
48
+ effects: [
49
+ ["emit", "STOP"],
50
+ ["render-ui", "screen", {
51
+ type: "game-menu",
52
+ title: "@entity.title",
53
+ options: [{ event: "START", label: "Start Game" }],
54
+ onSelect: "START"
55
+ }]
56
+ ]
57
+ },
58
+ {
59
+ from: "Menu",
60
+ to: "Playing",
61
+ event: "START",
62
+ effects: [
63
+ ["set", "@entity.attempts", ["+", "@entity.attempts", 1]],
64
+ ["set", "@entity.playTime", 0],
65
+ ["emit", "GAME_LOOP_START"]
66
+ ]
67
+ },
68
+ {
69
+ from: "Playing",
70
+ to: "Paused",
71
+ event: "PAUSE",
72
+ guard: "@entity.allowPause",
73
+ effects: [
74
+ ["set", "@entity.lastState", "Playing"],
75
+ ["emit", "GAME_LOOP_PAUSE"],
76
+ ["render-ui", "overlay", {
77
+ type: "game-pause-overlay",
78
+ title: "Paused",
79
+ visible: true,
80
+ options: [
81
+ { event: "RESUME", label: "Resume" },
82
+ { event: "QUIT", label: "Quit" }
83
+ ]
84
+ }]
85
+ ]
86
+ },
87
+ {
88
+ from: "Paused",
89
+ to: "Playing",
90
+ event: "RESUME",
91
+ effects: [["emit", "GAME_LOOP_RESUME"]]
92
+ },
93
+ {
94
+ from: "Playing",
95
+ to: "GameOver",
96
+ event: "GAME_OVER",
97
+ effects: [
98
+ ["emit", "STOP"],
99
+ ["render-ui", "overlay", {
100
+ type: "game-over-screen",
101
+ title: "Game Over",
102
+ stats: [
103
+ { label: "Play Time", value: "@entity.playTime" },
104
+ { label: "Attempts", value: "@entity.attempts" }
105
+ ],
106
+ actions: [
107
+ { event: "RESTART", label: "Try Again" },
108
+ { event: "QUIT", label: "Quit" }
109
+ ]
110
+ }]
111
+ ]
112
+ },
113
+ {
114
+ from: "Playing",
115
+ to: "Victory",
116
+ event: "VICTORY",
117
+ effects: [
118
+ ["emit", "STOP"],
119
+ ["render-ui", "overlay", {
120
+ type: "game-over-screen",
121
+ title: "Victory!",
122
+ variant: "success",
123
+ stats: [
124
+ { label: "Play Time", value: "@entity.playTime" },
125
+ { label: "Attempts", value: "@entity.attempts" }
126
+ ],
127
+ actions: [
128
+ { event: "RESTART", label: "Play Again" },
129
+ { event: "QUIT", label: "Quit" }
130
+ ]
131
+ }]
132
+ ]
133
+ },
134
+ {
135
+ from: "GameOver",
136
+ to: "Playing",
137
+ event: "RESTART",
138
+ effects: [
139
+ ["emit", "GAME_RESET"],
140
+ ["emit", "START"]
141
+ ]
142
+ },
143
+ {
144
+ from: "Victory",
145
+ to: "Playing",
146
+ event: "RESTART",
147
+ effects: [
148
+ ["emit", "GAME_RESET"],
149
+ ["emit", "START"]
150
+ ]
151
+ },
152
+ {
153
+ from: "Playing",
154
+ to: "Menu",
155
+ event: "QUIT",
156
+ effects: [["emit", "STOP"]]
157
+ },
158
+ {
159
+ from: "Paused",
160
+ to: "Menu",
161
+ event: "QUIT",
162
+ effects: [["emit", "STOP"]]
163
+ },
164
+ {
165
+ from: "GameOver",
166
+ to: "Menu",
167
+ event: "QUIT",
168
+ effects: [["emit", "STOP"]]
169
+ },
170
+ {
171
+ from: "Victory",
172
+ to: "Menu",
173
+ event: "QUIT",
174
+ effects: [["emit", "STOP"]]
175
+ }
176
+ ]
177
+ }
178
+ }
179
+ ],
180
+ pages: []
181
+ }
182
+ ]
141
183
  };
142
184
  var DIALOGUE_BEHAVIOR = {
143
- name: "std/Dialogue",
144
- category: "game-ui",
185
+ name: "std-dialogue",
186
+ version: "1.0.0",
145
187
  description: "NPC dialogue system with branching conversations",
146
- suggestedFor: [
147
- "RPGs",
148
- "Adventure games",
149
- "Story-driven games",
150
- "NPC interactions"
151
- ],
152
- dataEntities: [
188
+ orbitals: [
153
189
  {
154
- name: "DialogueState",
155
- runtime: true,
156
- fields: [
157
- { name: "dialogueTree", type: "array", default: [] },
158
- { name: "currentNode", type: "number", default: 0 },
159
- { name: "displayedText", type: "string", default: "" },
160
- { name: "isTyping", type: "boolean", default: false },
161
- { name: "speaker", type: "string", default: "" },
162
- { name: "typeIndex", type: "number", default: 0 },
163
- { name: "lastTypeTime", type: "number", default: 0 }
164
- ]
165
- }
166
- ],
167
- stateMachine: {
168
- initial: "Hidden",
169
- states: [
170
- { name: "Hidden", isInitial: true },
171
- { name: "Typing" },
172
- { name: "Showing" },
173
- { name: "Choice" }
174
- ],
175
- events: [
176
- { key: "SHOW" },
177
- { key: "NEXT" },
178
- { key: "SELECT_CHOICE" },
179
- { key: "SKIP" },
180
- { key: "CLOSE" },
181
- { key: "TYPE_CHAR" },
182
- { key: "TYPE_COMPLETE" }
183
- ],
184
- transitions: [
185
- {
186
- from: "Hidden",
187
- to: "Typing",
188
- event: "SHOW",
189
- effects: [
190
- ["set", "@entity.dialogueTree", "@payload.dialogue"],
191
- ["set", "@entity.currentNode", 0],
192
- ["set", "@entity.isTyping", true],
193
- ["set", "@entity.displayedText", ""],
194
- ["set", "@entity.typeIndex", 0],
195
- ["set", "@entity.lastTypeTime", "@now"],
196
- ["emit", "GAME_PAUSE"],
197
- ["render", "overlay.dialogue", "dialogue-box", {
198
- speaker: "@entity.speaker",
199
- text: "@entity.displayedText",
200
- isTyping: "@entity.isTyping",
201
- onNext: "NEXT",
202
- onSkip: "SKIP"
203
- }]
204
- ]
205
- },
206
- {
207
- from: "Typing",
208
- event: "TYPE_CHAR",
209
- effects: [
210
- [
211
- "let",
212
- [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
213
- [
214
- "do",
215
- ["set", "@entity.typeIndex", ["+", "@entity.typeIndex", 1]],
216
- ["set", "@entity.displayedText", ["str/slice", "@currentDialogue.text", 0, "@entity.typeIndex"]],
217
- ["set", "@entity.lastTypeTime", "@now"]
218
- ]
219
- ]
220
- ]
221
- },
222
- {
223
- from: "Typing",
224
- to: "Showing",
225
- event: "TYPE_COMPLETE",
226
- effects: [
227
- ["set", "@entity.isTyping", false]
228
- ]
229
- },
230
- {
231
- from: "Typing",
232
- to: "Showing",
233
- event: "SKIP",
234
- effects: [
235
- [
236
- "let",
237
- [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
238
- [
239
- "do",
240
- ["set", "@entity.isTyping", false],
241
- ["set", "@entity.displayedText", "@currentDialogue.text"]
242
- ]
243
- ]
190
+ name: "DialogueOrbital",
191
+ entity: {
192
+ name: "DialogueState",
193
+ persistence: "runtime",
194
+ fields: [
195
+ { name: "id", type: "string", required: true },
196
+ { name: "dialogueTree", type: "array", default: [] },
197
+ { name: "currentNode", type: "number", default: 0 },
198
+ { name: "displayedText", type: "string", default: "" },
199
+ { name: "isTyping", type: "boolean", default: false },
200
+ { name: "speaker", type: "string", default: "" },
201
+ { name: "typeIndex", type: "number", default: 0 },
202
+ { name: "lastTypeTime", type: "number", default: 0 },
203
+ { name: "typingSpeed", type: "number", default: 50 }
244
204
  ]
245
205
  },
246
- {
247
- from: "Showing",
248
- event: "NEXT",
249
- guard: ["not", ["object/get", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"], "choices"]],
250
- effects: [
251
- [
252
- "if",
253
- [">=", "@entity.currentNode", ["-", ["array/len", "@entity.dialogueTree"], 1]],
254
- ["emit", "CLOSE"],
255
- [
256
- "do",
257
- ["set", "@entity.currentNode", ["+", "@entity.currentNode", 1]],
258
- ["set", "@entity.isTyping", true],
259
- ["set", "@entity.displayedText", ""],
260
- ["set", "@entity.typeIndex", 0]
206
+ traits: [
207
+ {
208
+ name: "Dialogue",
209
+ linkedEntity: "DialogueState",
210
+ category: "interaction",
211
+ stateMachine: {
212
+ states: [
213
+ { name: "Hidden", isInitial: true },
214
+ { name: "Typing" },
215
+ { name: "Showing" },
216
+ { name: "Choice" }
217
+ ],
218
+ events: [
219
+ { key: "SHOW", name: "Show" },
220
+ { key: "NEXT", name: "Next" },
221
+ { key: "SELECT_CHOICE", name: "Select Choice" },
222
+ { key: "SKIP", name: "Skip" },
223
+ { key: "CLOSE", name: "Close" },
224
+ { key: "TYPE_CHAR", name: "Type Char" },
225
+ { key: "TYPE_COMPLETE", name: "Type Complete" }
226
+ ],
227
+ transitions: [
228
+ {
229
+ from: "Hidden",
230
+ to: "Typing",
231
+ event: "SHOW",
232
+ effects: [
233
+ ["set", "@entity.dialogueTree", "@payload.dialogue"],
234
+ ["set", "@entity.currentNode", 0],
235
+ ["set", "@entity.isTyping", true],
236
+ ["set", "@entity.displayedText", ""],
237
+ ["set", "@entity.typeIndex", 0],
238
+ ["set", "@entity.lastTypeTime", "@now"],
239
+ ["emit", "GAME_PAUSE"],
240
+ ["render-ui", "overlay.dialogue", {
241
+ type: "dialogue-box",
242
+ dialogue: {
243
+ speaker: "@entity.speaker",
244
+ text: "@entity.displayedText",
245
+ isTyping: "@entity.isTyping"
246
+ },
247
+ onAdvance: "NEXT"
248
+ }]
249
+ ]
250
+ },
251
+ {
252
+ from: "Typing",
253
+ to: "Typing",
254
+ event: "TYPE_CHAR",
255
+ effects: [
256
+ [
257
+ "let",
258
+ [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
259
+ [
260
+ "do",
261
+ ["set", "@entity.typeIndex", ["+", "@entity.typeIndex", 1]],
262
+ ["set", "@entity.displayedText", ["str/slice", "@currentDialogue.text", 0, "@entity.typeIndex"]],
263
+ ["set", "@entity.lastTypeTime", "@now"]
264
+ ]
265
+ ]
266
+ ]
267
+ },
268
+ {
269
+ from: "Typing",
270
+ to: "Showing",
271
+ event: "TYPE_COMPLETE",
272
+ effects: [["set", "@entity.isTyping", false]]
273
+ },
274
+ {
275
+ from: "Typing",
276
+ to: "Showing",
277
+ event: "SKIP",
278
+ effects: [
279
+ [
280
+ "let",
281
+ [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
282
+ [
283
+ "do",
284
+ ["set", "@entity.isTyping", false],
285
+ ["set", "@entity.displayedText", "@currentDialogue.text"]
286
+ ]
287
+ ]
288
+ ]
289
+ },
290
+ {
291
+ from: "Showing",
292
+ to: "Typing",
293
+ event: "NEXT",
294
+ guard: ["not", ["object/get", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"], "choices"]],
295
+ effects: [
296
+ [
297
+ "if",
298
+ [">=", "@entity.currentNode", ["-", ["array/len", "@entity.dialogueTree"], 1]],
299
+ ["emit", "CLOSE"],
300
+ [
301
+ "do",
302
+ ["set", "@entity.currentNode", ["+", "@entity.currentNode", 1]],
303
+ ["set", "@entity.isTyping", true],
304
+ ["set", "@entity.displayedText", ""],
305
+ ["set", "@entity.typeIndex", 0]
306
+ ]
307
+ ]
308
+ ]
309
+ },
310
+ {
311
+ from: "Showing",
312
+ to: "Choice",
313
+ event: "NEXT",
314
+ guard: ["object/get", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"], "choices"],
315
+ effects: [
316
+ [
317
+ "let",
318
+ [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
319
+ ["render-ui", "overlay.dialogue", {
320
+ type: "dialogue-box",
321
+ dialogue: {
322
+ speaker: "Choose",
323
+ choices: "@currentDialogue.choices"
324
+ },
325
+ onChoice: "SELECT_CHOICE"
326
+ }]
327
+ ]
328
+ ]
329
+ },
330
+ {
331
+ from: "Choice",
332
+ to: "Typing",
333
+ event: "SELECT_CHOICE",
334
+ effects: [
335
+ [
336
+ "let",
337
+ [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
338
+ [
339
+ "let",
340
+ [["choice", ["array/nth", "@currentDialogue.choices", "@payload.index"]]],
341
+ [
342
+ "do",
343
+ [
344
+ "if",
345
+ "@choice.nextNode",
346
+ ["set", "@entity.currentNode", "@choice.nextNode"],
347
+ ["set", "@entity.currentNode", ["+", "@entity.currentNode", 1]]
348
+ ],
349
+ ["if", "@choice.effect", ["emit", "@choice.effect"]]
350
+ ]
351
+ ]
352
+ ],
353
+ ["set", "@entity.isTyping", true],
354
+ ["set", "@entity.displayedText", ""],
355
+ ["set", "@entity.typeIndex", 0]
356
+ ]
357
+ },
358
+ {
359
+ from: "Typing",
360
+ to: "Hidden",
361
+ event: "CLOSE",
362
+ effects: [
363
+ ["set", "@entity.dialogueTree", []],
364
+ ["set", "@entity.currentNode", 0],
365
+ ["emit", "GAME_RESUME"]
366
+ ]
367
+ },
368
+ {
369
+ from: "Showing",
370
+ to: "Hidden",
371
+ event: "CLOSE",
372
+ effects: [
373
+ ["set", "@entity.dialogueTree", []],
374
+ ["set", "@entity.currentNode", 0],
375
+ ["emit", "GAME_RESUME"]
376
+ ]
377
+ },
378
+ {
379
+ from: "Choice",
380
+ to: "Hidden",
381
+ event: "CLOSE",
382
+ effects: [
383
+ ["set", "@entity.dialogueTree", []],
384
+ ["set", "@entity.currentNode", 0],
385
+ ["emit", "GAME_RESUME"]
386
+ ]
387
+ }
261
388
  ]
262
- ]
263
- ]
264
- },
265
- {
266
- from: "Showing",
267
- to: "Choice",
268
- event: "NEXT",
269
- guard: ["object/get", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"], "choices"],
270
- effects: [
271
- [
272
- "let",
273
- [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
274
- ["render", "overlay.dialogue", "dialogue-box", {
275
- choices: "@currentDialogue.choices",
276
- onSelect: "SELECT_CHOICE"
277
- }]
278
- ]
279
- ]
280
- },
281
- {
282
- from: "Choice",
283
- to: "Typing",
284
- event: "SELECT_CHOICE",
285
- effects: [
286
- [
287
- "let",
288
- [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
289
- [
290
- "let",
291
- [["choice", ["array/nth", "@currentDialogue.choices", "@payload.index"]]],
292
- [
293
- "do",
294
- [
295
- "if",
296
- "@choice.nextNode",
297
- ["set", "@entity.currentNode", "@choice.nextNode"],
298
- ["set", "@entity.currentNode", ["+", "@entity.currentNode", 1]]
299
- ],
389
+ },
390
+ ticks: [
391
+ {
392
+ name: "TypewriterEffect",
393
+ interval: "frame",
394
+ guard: ["and", "@entity.isTyping", [">", ["-", "@now", "@entity.lastTypeTime"], ["/", 1e3, "@entity.typingSpeed"]]],
395
+ effects: [
300
396
  [
301
- "if",
302
- "@choice.effect",
303
- ["emit", "@choice.effect"]
397
+ "let",
398
+ [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
399
+ [
400
+ "if",
401
+ ["<", "@entity.typeIndex", ["str/len", "@currentDialogue.text"]],
402
+ ["emit", "TYPE_CHAR"],
403
+ ["emit", "TYPE_COMPLETE"]
404
+ ]
304
405
  ]
305
406
  ]
306
- ]
307
- ],
308
- ["set", "@entity.isTyping", true],
309
- ["set", "@entity.displayedText", ""],
310
- ["set", "@entity.typeIndex", 0]
311
- ]
312
- },
313
- {
314
- from: ["Typing", "Showing", "Choice"],
315
- to: "Hidden",
316
- event: "CLOSE",
317
- effects: [
318
- ["set", "@entity.dialogueTree", []],
319
- ["set", "@entity.currentNode", 0],
320
- ["emit", "GAME_RESUME"],
321
- ["render", "overlay.dialogue", null]
322
- ]
323
- }
324
- ]
325
- },
326
- ticks: [
327
- {
328
- name: "TypewriterEffect",
329
- interval: "frame",
330
- guard: ["and", "@entity.isTyping", [">", ["-", "@now", "@entity.lastTypeTime"], ["/", 1e3, "@config.typingSpeed"]]],
331
- effects: [
332
- [
333
- "let",
334
- [["currentDialogue", ["array/nth", "@entity.dialogueTree", "@entity.currentNode"]]],
335
- [
336
- "if",
337
- ["<", "@entity.typeIndex", ["str/len", "@currentDialogue.text"]],
338
- ["emit", "TYPE_CHAR"],
339
- ["emit", "TYPE_COMPLETE"]
407
+ }
340
408
  ]
341
- ]
342
- ]
409
+ }
410
+ ],
411
+ pages: []
343
412
  }
344
- ],
345
- configSchema: {
346
- required: [],
347
- optional: [
348
- { name: "typingSpeed", type: "number", description: "Characters per second", default: 30 },
349
- { name: "autoAdvance", type: "boolean", description: "Auto-advance after typing", default: false },
350
- { name: "autoAdvanceDelay", type: "number", description: "Delay before auto-advance (ms)", default: 2e3 },
351
- { name: "showPortrait", type: "boolean", description: "Show speaker portrait", default: true }
352
- ]
353
- }
413
+ ]
354
414
  };
355
415
  var LEVEL_PROGRESS_BEHAVIOR = {
356
- name: "std/LevelProgress",
357
- category: "game-ui",
416
+ name: "std-levelprogress",
417
+ version: "1.0.0",
358
418
  description: "Level progression with unlock, selection, and completion tracking",
359
- suggestedFor: [
360
- "Level-based games",
361
- "Puzzle games",
362
- "Platformers with levels",
363
- "Mobile games"
364
- ],
365
- dataEntities: [
419
+ orbitals: [
366
420
  {
367
- name: "LevelProgressState",
368
- runtime: true,
369
- singleton: true,
370
- fields: [
371
- { name: "currentLevel", type: "number", default: 0 },
372
- { name: "unlockedLevels", type: "array", default: [0] },
373
- { name: "levelStars", type: "object", default: {} },
374
- { name: "totalStars", type: "number", default: 0 }
375
- ]
376
- }
377
- ],
378
- stateMachine: {
379
- initial: "Browsing",
380
- states: [
381
- { name: "Browsing", isInitial: true },
382
- { name: "LevelLoading" },
383
- { name: "InLevel" }
384
- ],
385
- events: [
386
- { key: "INIT" },
387
- { key: "SELECT_LEVEL" },
388
- { key: "LEVEL_LOADED" },
389
- { key: "COMPLETE_LEVEL" },
390
- { key: "UNLOCK_LEVEL" },
391
- { key: "BACK_TO_SELECT" }
392
- ],
393
- transitions: [
394
- {
395
- from: "*",
396
- to: "Browsing",
397
- event: "INIT",
398
- effects: [
399
- ["render", "screen", "level-select", {
400
- levels: "@config.levels",
401
- unlockedLevels: "@entity.unlockedLevels",
402
- levelStars: "@entity.levelStars",
403
- starsPerLevel: "@config.starsPerLevel",
404
- totalStars: "@entity.totalStars",
405
- onSelect: "SELECT_LEVEL"
406
- }]
407
- ]
408
- },
409
- {
410
- from: "Browsing",
411
- to: "LevelLoading",
412
- event: "SELECT_LEVEL",
413
- guard: ["array/includes", "@entity.unlockedLevels", "@payload.levelIndex"],
414
- effects: [
415
- ["set", "@entity.currentLevel", "@payload.levelIndex"],
416
- ["render", "screen", "loading-screen", {
417
- level: ["array/nth", "@config.levels", "@payload.levelIndex"]
418
- }],
419
- ["emit", "LOAD_LEVEL", { levelData: ["array/nth", "@config.levels", "@payload.levelIndex"] }]
420
- ]
421
- },
422
- {
423
- from: "LevelLoading",
424
- to: "InLevel",
425
- event: "LEVEL_LOADED",
426
- effects: [
427
- ["render", "screen", null],
428
- ["emit", "START"]
421
+ name: "LevelProgressOrbital",
422
+ entity: {
423
+ name: "LevelProgressState",
424
+ persistence: "runtime",
425
+ fields: [
426
+ { name: "id", type: "string", required: true },
427
+ { name: "currentLevel", type: "number", default: 0 },
428
+ { name: "unlockedLevels", type: "array", default: [0] },
429
+ { name: "levelStars", type: "object", default: {} },
430
+ { name: "totalStars", type: "number", default: 0 },
431
+ { name: "levels", type: "array", default: [] },
432
+ { name: "starsPerLevel", type: "number", default: 3 },
433
+ { name: "unlockNext", type: "boolean", default: true },
434
+ { name: "persistProgress", type: "boolean", default: true }
429
435
  ]
430
436
  },
431
- {
432
- from: "InLevel",
433
- event: "COMPLETE_LEVEL",
434
- effects: [
435
- ["set", "@entity.levelStars", [
436
- "object/set",
437
- "@entity.levelStars",
438
- ["str/toString", "@entity.currentLevel"],
439
- ["math/max", "@payload.stars", ["object/get", "@entity.levelStars", ["str/toString", "@entity.currentLevel"], 0]]
440
- ]],
441
- ["set", "@entity.totalStars", ["array/reduce", ["object/values", "@entity.levelStars"], ["fn", "sum", "v", ["+", "@sum", "@v"]], 0]],
442
- [
443
- "if",
444
- ["and", "@config.unlockNext", ["<", "@entity.currentLevel", ["-", ["array/len", "@config.levels"], 1]]],
445
- ["emit", "UNLOCK_LEVEL", { levelIndex: ["+", "@entity.currentLevel", 1] }]
446
- ],
447
- [
448
- "if",
449
- "@config.persistProgress",
450
- ["persist", "save", "LevelProgress", {
451
- unlockedLevels: "@entity.unlockedLevels",
452
- levelStars: "@entity.levelStars"
453
- }]
454
- ]
455
- ]
456
- },
457
- {
458
- event: "UNLOCK_LEVEL",
459
- guard: ["not", ["array/includes", "@entity.unlockedLevels", "@payload.levelIndex"]],
460
- effects: [
461
- ["set", "@entity.unlockedLevels", ["array/append", "@entity.unlockedLevels", "@payload.levelIndex"]]
462
- ]
463
- },
464
- {
465
- from: "InLevel",
466
- to: "Browsing",
467
- event: "BACK_TO_SELECT",
468
- effects: [
469
- ["emit", "INIT"]
470
- ]
471
- }
472
- ]
473
- },
474
- configSchema: {
475
- required: [
476
- { name: "levels", type: "array", description: "Level definitions" }
477
- ],
478
- optional: [
479
- { name: "starsPerLevel", type: "number", description: "Max stars per level", default: 3 },
480
- { name: "unlockNext", type: "boolean", description: "Auto-unlock next level on complete", default: true },
481
- { name: "persistProgress", type: "boolean", description: "Save progress to storage", default: true }
482
- ]
483
- }
437
+ traits: [
438
+ {
439
+ name: "LevelProgress",
440
+ linkedEntity: "LevelProgressState",
441
+ category: "interaction",
442
+ stateMachine: {
443
+ states: [
444
+ { name: "Browsing", isInitial: true },
445
+ { name: "LevelLoading" },
446
+ { name: "InLevel" }
447
+ ],
448
+ events: [
449
+ { key: "INIT", name: "Initialize" },
450
+ { key: "SELECT_LEVEL", name: "Select Level" },
451
+ { key: "LEVEL_LOADED", name: "Level Loaded" },
452
+ { key: "COMPLETE_LEVEL", name: "Complete Level" },
453
+ { key: "UNLOCK_LEVEL", name: "Unlock Level" },
454
+ { key: "BACK_TO_SELECT", name: "Back To Select" }
455
+ ],
456
+ transitions: [
457
+ {
458
+ from: "Browsing",
459
+ to: "Browsing",
460
+ event: "INIT",
461
+ effects: [
462
+ ["render-ui", "screen", {
463
+ type: "level-select",
464
+ title: "Select Level",
465
+ levels: "@entity.levels",
466
+ onSelect: "SELECT_LEVEL"
467
+ }]
468
+ ]
469
+ },
470
+ {
471
+ from: "Browsing",
472
+ to: "LevelLoading",
473
+ event: "SELECT_LEVEL",
474
+ guard: ["array/includes", "@entity.unlockedLevels", "@payload.levelIndex"],
475
+ effects: [
476
+ ["set", "@entity.currentLevel", "@payload.levelIndex"],
477
+ ["emit", "LOAD_LEVEL", { levelData: ["array/nth", "@entity.levels", "@payload.levelIndex"] }]
478
+ ]
479
+ },
480
+ {
481
+ from: "LevelLoading",
482
+ to: "InLevel",
483
+ event: "LEVEL_LOADED",
484
+ effects: [["emit", "START"]]
485
+ },
486
+ {
487
+ from: "InLevel",
488
+ to: "InLevel",
489
+ event: "COMPLETE_LEVEL",
490
+ effects: [
491
+ ["set", "@entity.levelStars", [
492
+ "object/set",
493
+ "@entity.levelStars",
494
+ ["str/toString", "@entity.currentLevel"],
495
+ ["math/max", "@payload.stars", ["object/get", "@entity.levelStars", ["str/toString", "@entity.currentLevel"], 0]]
496
+ ]],
497
+ ["set", "@entity.totalStars", ["array/reduce", ["object/values", "@entity.levelStars"], ["fn", "sum", "v", ["+", "@sum", "@v"]], 0]],
498
+ [
499
+ "if",
500
+ ["and", "@entity.unlockNext", ["<", "@entity.currentLevel", ["-", ["array/len", "@entity.levels"], 1]]],
501
+ ["emit", "UNLOCK_LEVEL", { levelIndex: ["+", "@entity.currentLevel", 1] }]
502
+ ],
503
+ [
504
+ "if",
505
+ "@entity.persistProgress",
506
+ ["persist", "save", "LevelProgress", {
507
+ unlockedLevels: "@entity.unlockedLevels",
508
+ levelStars: "@entity.levelStars"
509
+ }]
510
+ ]
511
+ ]
512
+ },
513
+ {
514
+ from: "InLevel",
515
+ to: "InLevel",
516
+ event: "UNLOCK_LEVEL",
517
+ guard: ["not", ["array/includes", "@entity.unlockedLevels", "@payload.levelIndex"]],
518
+ effects: [
519
+ ["set", "@entity.unlockedLevels", ["array/append", "@entity.unlockedLevels", "@payload.levelIndex"]]
520
+ ]
521
+ },
522
+ {
523
+ from: "InLevel",
524
+ to: "Browsing",
525
+ event: "BACK_TO_SELECT",
526
+ effects: [["emit", "INIT"]]
527
+ },
528
+ {
529
+ from: "LevelLoading",
530
+ to: "Browsing",
531
+ event: "INIT",
532
+ effects: []
533
+ },
534
+ {
535
+ from: "InLevel",
536
+ to: "Browsing",
537
+ event: "INIT",
538
+ effects: []
539
+ }
540
+ ]
541
+ }
542
+ }
543
+ ],
544
+ pages: []
545
+ }
546
+ ]
484
547
  };
485
548
  var GAME_UI_BEHAVIORS = [
486
549
  GAME_FLOW_BEHAVIOR,