@pix3/cli 1.6.0 → 1.6.3
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.
- package/LICENSE +201 -201
- package/README.md +788 -754
- package/dist/index.js +208 -203
- package/dist/runtime-types.json +1 -1
- package/dist/smoke/prebuilt/{chunk-J2SJVMDO.mjs → chunk-CBFYKDS7.mjs} +1 -1
- package/dist/smoke/prebuilt/chunk-VJHJ5BCO.mjs +239 -0
- package/dist/smoke/prebuilt/runtime.mjs +1 -1
- package/dist/smoke/prebuilt/smoke-worker.mjs +1 -1
- package/dist/smoke/prebuilt/tree-defaults.mjs +1 -1
- package/dist/validate/prebuilt/bundle-main.js +13 -13
- package/dist/validate/prebuilt/chunk-CFQFEI52.js +239 -0
- package/dist/validate/prebuilt/runtime.js +1 -1
- package/kit/files/.claude/skills/pix3-nodes/SKILL.md +210 -210
- package/kit/files/.claude/skills/pix3-nodes/reference.md +39 -24
- package/kit/files/.claude/skills/pix3-scene-format/SKILL.md +238 -235
- package/kit/files/.claude/skills/pix3-scene-format/reference.md +43 -28
- package/kit/files/.claude/skills/pix3-scripts/SKILL.md +285 -281
- package/kit/files/.claude/skills/pix3-scripts/reference.md +69 -52
- package/kit/files/.claude/skills/pix3-verify/SKILL.md +298 -256
- package/kit/files/.claude/skills/pix3-verify/reference.md +21 -21
- package/kit/files/AGENTS.md +203 -203
- package/kit/files/CLAUDE.md +1 -1
- package/kit/kit.json +2 -2
- package/package.json +54 -54
- package/templates/empty-2d/files/README.md +20 -20
- package/templates/empty-2d/files/scenes/main.pix3scene +68 -68
- package/templates/empty-2d/template.yaml +7 -7
- package/templates/empty-3d/files/README.md +20 -20
- package/templates/empty-3d/files/scenes/main.pix3scene +108 -108
- package/templates/empty-3d/template.yaml +7 -7
- package/templates/idea-blank/files/README.md +22 -22
- package/templates/idea-blank/files/scenes/main.pix3scene +37 -37
- package/templates/idea-blank/template.yaml +10 -10
- package/templates/minigame-2d/files/README.md +44 -44
- package/templates/minigame-2d/files/design/tests/reachability.json +1 -1
- package/templates/minigame-2d/files/design/tests/routines/mute-music.json +44 -44
- package/templates/minigame-2d/files/scenes/main.pix3scene +84 -84
- package/templates/minigame-2d/files/scenes/menu.pix3scene +118 -118
- package/templates/minigame-2d/files/scenes/ui/settings-window.pix3scene +138 -138
- package/templates/minigame-2d/files/scripts/GameFlow.ts +133 -133
- package/templates/minigame-2d/files/scripts/MenuFlow.ts +217 -217
- package/templates/minigame-2d/files/scripts/SettingsWindow.ts +198 -198
- package/templates/minigame-2d/template.yaml +10 -10
- package/templates/playable-2d/files/README.md +30 -30
- package/templates/playable-2d/files/design/recipe.md +83 -83
- package/templates/playable-2d/files/design/tests/reachability.json +4 -4
- package/templates/playable-2d/files/design/tests/routines/intro-to-cta.json +32 -32
- package/templates/playable-2d/files/scenes/main.pix3scene +111 -111
- package/templates/playable-2d/files/scenes/ui/end-screen.pix3scene +91 -91
- package/templates/playable-2d/files/scenes/ui/intro.pix3scene +65 -65
- package/templates/playable-2d/files/scripts/GameFlow.ts +256 -256
- package/templates/playable-2d/template.yaml +9 -9
- package/templates/playable-3d/files/README.md +32 -32
- package/templates/playable-3d/files/design/recipe.md +127 -127
- package/templates/playable-3d/files/design/tests/reachability.json +4 -4
- package/templates/playable-3d/files/design/tests/routines/intro-to-cta.json +32 -32
- package/templates/playable-3d/files/scenes/main.pix3scene +230 -230
- package/templates/playable-3d/files/scenes/ui/end-screen.pix3scene +91 -91
- package/templates/playable-3d/files/scenes/ui/intro.pix3scene +65 -65
- package/templates/playable-3d/files/scripts/GameFlow.ts +309 -309
- package/templates/playable-3d/files/scripts/GameRules.ts +290 -290
- package/templates/playable-3d/files/scripts/ScoreHud.ts +113 -113
- package/templates/playable-3d/template.yaml +9 -9
- package/templates/recipe-arena-2d/files/README.md +48 -48
- package/templates/recipe-arena-2d/files/design/recipe.md +127 -127
- package/templates/recipe-arena-2d/files/scenes/main.pix3scene +292 -292
- package/templates/recipe-arena-2d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-arena-2d/files/scenes/prefabs/hazard.pix3scene +42 -42
- package/templates/recipe-arena-2d/files/scenes/prefabs/pickup.pix3scene +45 -45
- package/templates/recipe-arena-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-arena-2d/files/scripts/GameRules.ts +368 -368
- package/templates/recipe-arena-2d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-arena-2d/files/scripts/PlayerController.ts +151 -151
- package/templates/recipe-arena-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-arena-2d/files/scripts/Spawner.ts +214 -214
- package/templates/recipe-arena-2d/files/scripts/TouchRules.ts +174 -174
- package/templates/recipe-arena-2d/template.yaml +10 -10
- package/templates/recipe-blank-2d/files/README.md +61 -61
- package/templates/recipe-blank-2d/files/design/recipe.md +148 -148
- package/templates/recipe-blank-2d/files/design/tests/reachability.json +4 -4
- package/templates/recipe-blank-2d/files/design/tests/routines/restart.json +27 -27
- package/templates/recipe-blank-2d/files/scenes/main.pix3scene +224 -224
- package/templates/recipe-blank-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-blank-2d/files/scripts/GameRules.ts +350 -350
- package/templates/recipe-blank-2d/files/scripts/ScoreHud.ts +110 -110
- package/templates/recipe-blank-2d/template.yaml +10 -10
- package/templates/recipe-bouncer-2d/files/README.md +81 -81
- package/templates/recipe-bouncer-2d/files/design/recipe.md +146 -146
- package/templates/recipe-bouncer-2d/files/scenes/main.pix3scene +615 -615
- package/templates/recipe-bouncer-2d/files/scenes/menu.pix3scene +191 -191
- package/templates/recipe-bouncer-2d/files/scenes/ui/result.pix3scene +87 -87
- package/templates/recipe-bouncer-2d/files/scripts/BallBody.ts +298 -298
- package/templates/recipe-bouncer-2d/files/scripts/GameRules.ts +377 -377
- package/templates/recipe-bouncer-2d/files/scripts/MenuFlow.ts +109 -109
- package/templates/recipe-bouncer-2d/files/scripts/PaddleController.ts +112 -112
- package/templates/recipe-bouncer-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-bouncer-2d/files/scripts/TouchRules.ts +263 -263
- package/templates/recipe-bouncer-2d/files/scripts/ball-collision.ts +307 -307
- package/templates/recipe-bouncer-2d/template.yaml +10 -10
- package/templates/recipe-grid-3d/files/README.md +22 -22
- package/templates/recipe-grid-3d/files/design/recipe.md +110 -110
- package/templates/recipe-grid-3d/files/scenes/main.pix3scene +169 -169
- package/templates/recipe-grid-3d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-grid-3d/files/scenes/ui/result.pix3scene +105 -105
- package/templates/recipe-grid-3d/files/scripts/GridBoard.ts +319 -319
- package/templates/recipe-grid-3d/files/scripts/GridRules.ts +278 -278
- package/templates/recipe-grid-3d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-grid-3d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-grid-3d/template.yaml +10 -10
- package/templates/recipe-tapper-2d/files/README.md +39 -39
- package/templates/recipe-tapper-2d/files/design/recipe.md +132 -132
- package/templates/recipe-tapper-2d/files/design/tests/reachability.json +4 -4
- package/templates/recipe-tapper-2d/files/design/tests/routines/terminal-retry.json +23 -23
- package/templates/recipe-tapper-2d/files/scenes/main.pix3scene +269 -269
- package/templates/recipe-tapper-2d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-tapper-2d/files/scenes/prefabs/hazard.pix3scene +42 -42
- package/templates/recipe-tapper-2d/files/scenes/prefabs/target.pix3scene +45 -45
- package/templates/recipe-tapper-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-tapper-2d/files/scripts/GameRules.ts +368 -368
- package/templates/recipe-tapper-2d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-tapper-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-tapper-2d/files/scripts/Spawner.ts +214 -214
- package/templates/recipe-tapper-2d/files/scripts/TouchRules.ts +192 -192
- package/templates/recipe-tapper-2d/template.yaml +10 -10
- package/dist/smoke/prebuilt/chunk-OJXQXIIQ.mjs +0 -239
- package/dist/validate/prebuilt/chunk-BS2OZM7U.js +0 -239
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GameFlow — drives the game scene (main.pix3scene).
|
|
3
|
-
*
|
|
4
|
-
* Attach to the game scene root. Wires the MENU button to transition back to the
|
|
5
|
-
* menu scene via a fade. Extend this with your win/lose flow — call
|
|
6
|
-
* `this.scene.changeScene('res://scenes/menu.pix3scene')` on game over
|
|
7
|
-
* to return to the menu, or transition to a results scene of your own.
|
|
8
|
-
*
|
|
9
|
-
* Two conventions in here are worth keeping as you build on this template:
|
|
10
|
-
*
|
|
11
|
-
* 1. **Intent-first handlers.** Every reaction to the UI lives in a named public
|
|
12
|
-
* method marked `Intent:`, registered as a **command** (`scene.commands`)
|
|
13
|
-
* that the signal handler dispatches. Tools (and you, from the console) then
|
|
14
|
-
* trigger the behaviour with `scene.commands.dispatch('return-to-menu')`
|
|
15
|
-
* instead of faking a click, and every raised intent is journalled with the
|
|
16
|
-
* frame it happened on.
|
|
17
|
-
* 2. **A debug provider.** `registerGameDebug` publishes a JSON snapshot of the
|
|
18
|
-
* game's state so agents and dev tooling can read what the game is doing
|
|
19
|
-
* instead of guessing from pixels. Add YOUR state to `snapshot()` — score,
|
|
20
|
-
* lives, level, whatever the game owns — and keep every value JSON-safe.
|
|
21
|
-
*/
|
|
22
|
-
import { Script, registerGameDebug, type PropertySchema } from '@pix3/runtime';
|
|
23
|
-
|
|
24
|
-
/** Coarse state of the game scene; extend with your own phases (`won`, `lost`, …). */
|
|
25
|
-
type GamePhase = 'idle' | 'playing' | 'leaving';
|
|
26
|
-
|
|
27
|
-
export class GameFlow extends Script {
|
|
28
|
-
private phase: GamePhase = 'idle';
|
|
29
|
-
private menuButtonReady = false;
|
|
30
|
-
private disposeDebug: (() => void) | null = null;
|
|
31
|
-
private disposeCommands: (() => void)[] = [];
|
|
32
|
-
|
|
33
|
-
constructor(id: string, type: string) {
|
|
34
|
-
super(id, type);
|
|
35
|
-
this.config = {
|
|
36
|
-
// res:// path of the scene the MENU button transitions to.
|
|
37
|
-
menuScene: 'res://scenes/menu.pix3scene',
|
|
38
|
-
// Node id/name of the button that returns to the menu.
|
|
39
|
-
menuButton: 'menu-button',
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static getPropertySchema(): PropertySchema {
|
|
44
|
-
const stringProp = (name: string, label: string) => ({
|
|
45
|
-
name,
|
|
46
|
-
type: 'string' as const,
|
|
47
|
-
ui: { label, group: 'Game' },
|
|
48
|
-
getValue: (s: unknown) => (s as GameFlow).config[name],
|
|
49
|
-
setValue: (s: unknown, v: unknown) => {
|
|
50
|
-
(s as GameFlow).config[name] = typeof v === 'string' ? v : '';
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
nodeType: 'GameFlow',
|
|
56
|
-
properties: [stringProp('menuScene', 'Menu Scene'), stringProp('menuButton', 'Menu Button')],
|
|
57
|
-
groups: { Game: { label: 'Game Flow', expanded: true } },
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
onStart(): void {
|
|
62
|
-
this.phase = 'playing';
|
|
63
|
-
const commands = this.scene?.commands;
|
|
64
|
-
this.disposeCommands = [
|
|
65
|
-
commands?.register('return-to-menu', () => this.returnToMenu(), {
|
|
66
|
-
description: 'Leave the game and transition back to the menu scene.',
|
|
67
|
-
}),
|
|
68
|
-
].filter((dispose): dispose is () => void => dispose !== undefined);
|
|
69
|
-
|
|
70
|
-
this.disposeDebug = registerGameDebug({
|
|
71
|
-
name: 'minigame-2d',
|
|
72
|
-
version: 1,
|
|
73
|
-
// The registry IS the action list — never a second, hand-kept copy.
|
|
74
|
-
actions: () => this.scene?.commands.list().map(command => command.name) ?? [],
|
|
75
|
-
// What "the start" means for this scene, so a test can put the game back
|
|
76
|
-
// without restarting it. All this template owns is `phase`, and `playing`
|
|
77
|
-
// is the value `onStart` sets — a run that had already dispatched
|
|
78
|
-
// `return-to-menu` would otherwise be stuck in `leaving`. Reset YOUR state
|
|
79
|
-
// here as you add it (score, level, spawned things), and seed your RNG from
|
|
80
|
-
// `seed` if you want two runs to be comparable and not merely to start
|
|
81
|
-
// from the same values.
|
|
82
|
-
reset: () => {
|
|
83
|
-
this.phase = 'playing';
|
|
84
|
-
},
|
|
85
|
-
// Everything returned here must be JSON-serialisable — plain values only,
|
|
86
|
-
// never live nodes or Three.js objects. Add your own state as you build.
|
|
87
|
-
snapshot: () => ({
|
|
88
|
-
phase: this.phase,
|
|
89
|
-
menuScene: String(this.config.menuScene ?? ''),
|
|
90
|
-
menuButtonReady: this.menuButtonReady,
|
|
91
|
-
}),
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const query = String(this.config.menuButton ?? '');
|
|
95
|
-
if (!query) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const button = this.findNode(query);
|
|
99
|
-
if (button) {
|
|
100
|
-
this.menuButtonReady = true;
|
|
101
|
-
// The button raises the intent through the registry, so a single tap in a
|
|
102
|
-
// test proves this binding and every later scenario can skip the tap.
|
|
103
|
-
button.connect('pressed', this, () => {
|
|
104
|
-
this.scene?.commands.dispatch('return-to-menu');
|
|
105
|
-
});
|
|
106
|
-
} else {
|
|
107
|
-
console.warn(`[GameFlow] Button "${query}" not found.`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
onDetach(): void {
|
|
112
|
-
this.disposeDebug?.();
|
|
113
|
-
this.disposeDebug = null;
|
|
114
|
-
for (const dispose of this.disposeCommands) {
|
|
115
|
-
dispose();
|
|
116
|
-
}
|
|
117
|
-
this.disposeCommands = [];
|
|
118
|
-
this.phase = 'idle';
|
|
119
|
-
this.menuButtonReady = false;
|
|
120
|
-
super.onDetach();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** Intent: leave the game and transition back to the menu scene (also on game over). */
|
|
124
|
-
returnToMenu(): void {
|
|
125
|
-
const menuScene = String(this.config.menuScene ?? '');
|
|
126
|
-
if (!menuScene) {
|
|
127
|
-
console.warn('[GameFlow] No menu scene configured.');
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
this.phase = 'leaving';
|
|
131
|
-
void this.scene?.changeScene(menuScene, { transition: 'fade', durationSec: 0.3 });
|
|
132
|
-
}
|
|
133
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* GameFlow — drives the game scene (main.pix3scene).
|
|
3
|
+
*
|
|
4
|
+
* Attach to the game scene root. Wires the MENU button to transition back to the
|
|
5
|
+
* menu scene via a fade. Extend this with your win/lose flow — call
|
|
6
|
+
* `this.scene.changeScene('res://scenes/menu.pix3scene')` on game over
|
|
7
|
+
* to return to the menu, or transition to a results scene of your own.
|
|
8
|
+
*
|
|
9
|
+
* Two conventions in here are worth keeping as you build on this template:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Intent-first handlers.** Every reaction to the UI lives in a named public
|
|
12
|
+
* method marked `Intent:`, registered as a **command** (`scene.commands`)
|
|
13
|
+
* that the signal handler dispatches. Tools (and you, from the console) then
|
|
14
|
+
* trigger the behaviour with `scene.commands.dispatch('return-to-menu')`
|
|
15
|
+
* instead of faking a click, and every raised intent is journalled with the
|
|
16
|
+
* frame it happened on.
|
|
17
|
+
* 2. **A debug provider.** `registerGameDebug` publishes a JSON snapshot of the
|
|
18
|
+
* game's state so agents and dev tooling can read what the game is doing
|
|
19
|
+
* instead of guessing from pixels. Add YOUR state to `snapshot()` — score,
|
|
20
|
+
* lives, level, whatever the game owns — and keep every value JSON-safe.
|
|
21
|
+
*/
|
|
22
|
+
import { Script, registerGameDebug, type PropertySchema } from '@pix3/runtime';
|
|
23
|
+
|
|
24
|
+
/** Coarse state of the game scene; extend with your own phases (`won`, `lost`, …). */
|
|
25
|
+
type GamePhase = 'idle' | 'playing' | 'leaving';
|
|
26
|
+
|
|
27
|
+
export class GameFlow extends Script {
|
|
28
|
+
private phase: GamePhase = 'idle';
|
|
29
|
+
private menuButtonReady = false;
|
|
30
|
+
private disposeDebug: (() => void) | null = null;
|
|
31
|
+
private disposeCommands: (() => void)[] = [];
|
|
32
|
+
|
|
33
|
+
constructor(id: string, type: string) {
|
|
34
|
+
super(id, type);
|
|
35
|
+
this.config = {
|
|
36
|
+
// res:// path of the scene the MENU button transitions to.
|
|
37
|
+
menuScene: 'res://scenes/menu.pix3scene',
|
|
38
|
+
// Node id/name of the button that returns to the menu.
|
|
39
|
+
menuButton: 'menu-button',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static getPropertySchema(): PropertySchema {
|
|
44
|
+
const stringProp = (name: string, label: string) => ({
|
|
45
|
+
name,
|
|
46
|
+
type: 'string' as const,
|
|
47
|
+
ui: { label, group: 'Game' },
|
|
48
|
+
getValue: (s: unknown) => (s as GameFlow).config[name],
|
|
49
|
+
setValue: (s: unknown, v: unknown) => {
|
|
50
|
+
(s as GameFlow).config[name] = typeof v === 'string' ? v : '';
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
nodeType: 'GameFlow',
|
|
56
|
+
properties: [stringProp('menuScene', 'Menu Scene'), stringProp('menuButton', 'Menu Button')],
|
|
57
|
+
groups: { Game: { label: 'Game Flow', expanded: true } },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onStart(): void {
|
|
62
|
+
this.phase = 'playing';
|
|
63
|
+
const commands = this.scene?.commands;
|
|
64
|
+
this.disposeCommands = [
|
|
65
|
+
commands?.register('return-to-menu', () => this.returnToMenu(), {
|
|
66
|
+
description: 'Leave the game and transition back to the menu scene.',
|
|
67
|
+
}),
|
|
68
|
+
].filter((dispose): dispose is () => void => dispose !== undefined);
|
|
69
|
+
|
|
70
|
+
this.disposeDebug = registerGameDebug({
|
|
71
|
+
name: 'minigame-2d',
|
|
72
|
+
version: 1,
|
|
73
|
+
// The registry IS the action list — never a second, hand-kept copy.
|
|
74
|
+
actions: () => this.scene?.commands.list().map(command => command.name) ?? [],
|
|
75
|
+
// What "the start" means for this scene, so a test can put the game back
|
|
76
|
+
// without restarting it. All this template owns is `phase`, and `playing`
|
|
77
|
+
// is the value `onStart` sets — a run that had already dispatched
|
|
78
|
+
// `return-to-menu` would otherwise be stuck in `leaving`. Reset YOUR state
|
|
79
|
+
// here as you add it (score, level, spawned things), and seed your RNG from
|
|
80
|
+
// `seed` if you want two runs to be comparable and not merely to start
|
|
81
|
+
// from the same values.
|
|
82
|
+
reset: () => {
|
|
83
|
+
this.phase = 'playing';
|
|
84
|
+
},
|
|
85
|
+
// Everything returned here must be JSON-serialisable — plain values only,
|
|
86
|
+
// never live nodes or Three.js objects. Add your own state as you build.
|
|
87
|
+
snapshot: () => ({
|
|
88
|
+
phase: this.phase,
|
|
89
|
+
menuScene: String(this.config.menuScene ?? ''),
|
|
90
|
+
menuButtonReady: this.menuButtonReady,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const query = String(this.config.menuButton ?? '');
|
|
95
|
+
if (!query) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const button = this.findNode(query);
|
|
99
|
+
if (button) {
|
|
100
|
+
this.menuButtonReady = true;
|
|
101
|
+
// The button raises the intent through the registry, so a single tap in a
|
|
102
|
+
// test proves this binding and every later scenario can skip the tap.
|
|
103
|
+
button.connect('pressed', this, () => {
|
|
104
|
+
this.scene?.commands.dispatch('return-to-menu');
|
|
105
|
+
});
|
|
106
|
+
} else {
|
|
107
|
+
console.warn(`[GameFlow] Button "${query}" not found.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
onDetach(): void {
|
|
112
|
+
this.disposeDebug?.();
|
|
113
|
+
this.disposeDebug = null;
|
|
114
|
+
for (const dispose of this.disposeCommands) {
|
|
115
|
+
dispose();
|
|
116
|
+
}
|
|
117
|
+
this.disposeCommands = [];
|
|
118
|
+
this.phase = 'idle';
|
|
119
|
+
this.menuButtonReady = false;
|
|
120
|
+
super.onDetach();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Intent: leave the game and transition back to the menu scene (also on game over). */
|
|
124
|
+
returnToMenu(): void {
|
|
125
|
+
const menuScene = String(this.config.menuScene ?? '');
|
|
126
|
+
if (!menuScene) {
|
|
127
|
+
console.warn('[GameFlow] No menu scene configured.');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.phase = 'leaving';
|
|
131
|
+
void this.scene?.changeScene(menuScene, { transition: 'fade', durationSec: 0.3 });
|
|
132
|
+
}
|
|
133
|
+
}
|