@moku-labs/game 0.14.12 → 0.14.13
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/README.md +13 -12
- package/dist/app/page.d.mts +8 -3
- package/dist/app/page.mjs +57 -12
- package/dist/app/system.d.mts +5 -3
- package/dist/app/system.mjs +2 -0
- package/dist/app.d.mts +15 -7
- package/dist/app.mjs +131 -27
- package/dist/{assets-BrKSg1O6.mjs → assets-CEMfBogh.mjs} +471 -120
- package/dist/assets.d.mts +30 -13
- package/dist/assets.mjs +1 -1
- package/dist/cli.d.mts +105 -8
- package/dist/cli.mjs +1036 -128
- package/dist/{commands-BaCx2B9j.d.mts → commands-DAETmK86.d.mts} +43 -7
- package/dist/{config-CdARrrhU.mjs → config-B87aFTW-.mjs} +25 -4
- package/dist/control.d.mts +130 -17
- package/dist/control.mjs +4 -4
- package/dist/{define-Ce8SVEN-.d.mts → define-BASd9ZUh.d.mts} +32 -4
- package/dist/dev-DbHgx-R-.mjs +89 -0
- package/dist/{fake-MpzwZhIZ.mjs → fake-6mazmHK3.mjs} +20 -2
- package/dist/features-DowEilZm.mjs +266 -0
- package/dist/{headless-CMHNsKjW.d.mts → headless-cFveciuY.d.mts} +1 -1
- package/dist/hot.d.mts +4 -2
- package/dist/hot.mjs +7 -4
- package/dist/{index-CLQ8NOTw.d.mts → index-DedbED3T.d.mts} +317 -69
- package/dist/index.d.mts +5 -6
- package/dist/index.mjs +3 -3
- package/dist/inspect.d.mts +12 -7
- package/dist/inspect.mjs +2 -2
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/lint.d.mts +8 -3
- package/dist/lint.mjs +432 -20
- package/dist/project.d.mts +15 -1
- package/dist/project.mjs +1 -1
- package/dist/{run-Bf2hKyjZ.mjs → run-BbipFRc6.mjs} +250 -51
- package/dist/{runtime-BCnKn0xf.d.mts → runtime-DoSlRx8X.d.mts} +1 -1
- package/dist/{session-DgukhR_7.mjs → session-CeKgO2hy.mjs} +30 -2
- package/dist/{sources-Duzj6lhV.mjs → sources-Cdvb0rOS.mjs} +33 -6
- package/dist/{src-CtC8w3_z.mjs → src-BEbJ_sSx.mjs} +35536 -17789
- package/dist/testing.d.mts +23 -13
- package/dist/testing.mjs +10 -6
- package/dist/{types-DOlpeuGx.d.mts → types-7GXcXxxv.d.mts} +174 -242
- package/dist/{types-BjTtGSFb.d.mts → types-BGcda5Le.d.mts} +4459 -732
- package/dist/{types-gisvSHoC.d.mts → types-C73hbmxi.d.mts} +129 -17
- package/dist/{types-CAPv9l29.d.mts → types-DngFQJro.d.mts} +43 -5
- package/dist/{types-Y_rCuXtj.d.mts → types-GHE4J5Uf.d.mts} +1025 -191
- package/dist/{visual-dMW8iqAE.mjs → visual-2m4wJL_z.mjs} +111 -7
- package/dist/visual-_XhoGeIC.d.mts +345 -0
- package/dist/visual.d.mts +1 -332
- package/dist/visual.mjs +130 -20
- package/dist/{watch-CWI_on4T.mjs → watch-BEdrp80i.mjs} +149 -30
- package/llms.txt +99 -48
- package/package.json +8 -6
- package/dist/dev-Cc50Dk7H.mjs +0 -47
- package/dist/memory-pUQ7YZWC.d.mts +0 -50
- package/dist/types-BX4Ge_j5.d.mts +0 -656
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as HeadlessApp } from "./headless-
|
|
5
|
-
import { n as Command, r as ControlApp } from "./types-
|
|
1
|
+
import { Hn as FlowState, I as Captured, Ir as Time, Mr as FrameRate, S as ScenesApi, T as Api$1, ht as DebugSwitches, wr as Api, xr as StoreApi, yr as Snapshot, zn as Bookmark, zt as Api$2 } from "./types-BGcda5Le.mjs";
|
|
2
|
+
import { P as AnimApi, a as AudioApi, h as EffectsApi, r as UiApi } from "./types-GHE4J5Uf.mjs";
|
|
3
|
+
import { j as InputApi } from "./types-7GXcXxxv.mjs";
|
|
4
|
+
import { t as HeadlessApp } from "./headless-cFveciuY.mjs";
|
|
5
|
+
import { n as Command, r as ControlApp } from "./types-DngFQJro.mjs";
|
|
6
6
|
|
|
7
7
|
//#region src/plugins/flow/doors/commands.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* Every command of the engine, keyed by its short name: what an editor lists as buttons and MCP
|
|
10
|
-
* tools. Frozen. Each runs
|
|
10
|
+
* tools. Frozen. Each runs on the dev page and on a debug page, by the profile `run` checks: a
|
|
11
|
+
* `--debug` page runs the read and cosmetic ones.
|
|
11
12
|
*
|
|
12
13
|
* @example
|
|
13
14
|
* ```ts
|
|
@@ -62,6 +63,28 @@ declare const commands: Readonly<{
|
|
|
62
63
|
} & {
|
|
63
64
|
readonly scenes?: ScenesApi;
|
|
64
65
|
}>;
|
|
66
|
+
saveExport: Command<{}, Snapshot, HeadlessApp & {
|
|
67
|
+
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
68
|
+
} & {
|
|
69
|
+
readonly scenes?: ScenesApi;
|
|
70
|
+
} & {
|
|
71
|
+
readonly model: {
|
|
72
|
+
readonly store: Pick<StoreApi, "snapshot" | "flush">;
|
|
73
|
+
};
|
|
74
|
+
}>;
|
|
75
|
+
saveImport: Command<{
|
|
76
|
+
save: "json";
|
|
77
|
+
}, {
|
|
78
|
+
restored: boolean;
|
|
79
|
+
}, HeadlessApp & {
|
|
80
|
+
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
81
|
+
} & {
|
|
82
|
+
readonly scenes?: ScenesApi;
|
|
83
|
+
} & {
|
|
84
|
+
readonly model: {
|
|
85
|
+
readonly store: Pick<StoreApi, "snapshot" | "flush">;
|
|
86
|
+
};
|
|
87
|
+
}>;
|
|
65
88
|
step: Command<{
|
|
66
89
|
frames: "number";
|
|
67
90
|
deltaMs: "number?";
|
|
@@ -89,7 +112,9 @@ declare const commands: Readonly<{
|
|
|
89
112
|
readonly world: Api$2;
|
|
90
113
|
}>;
|
|
91
114
|
debug: Command<{
|
|
92
|
-
nineSlice: "boolean";
|
|
115
|
+
nineSlice: "boolean?";
|
|
116
|
+
verifyFrames: "boolean?";
|
|
117
|
+
kept: "boolean?";
|
|
93
118
|
}, DebugSwitches, HeadlessApp & {
|
|
94
119
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
95
120
|
} & {
|
|
@@ -113,6 +138,9 @@ declare const commands: Readonly<{
|
|
|
113
138
|
timeScale: Command<{
|
|
114
139
|
scale: "number";
|
|
115
140
|
}, Readonly<Time>, ControlApp>;
|
|
141
|
+
frameRate: Command<{
|
|
142
|
+
fps: "number?";
|
|
143
|
+
}, Readonly<FrameRate>, ControlApp>;
|
|
116
144
|
mute: Command<{
|
|
117
145
|
muted: "boolean";
|
|
118
146
|
}, boolean, HeadlessApp & {
|
|
@@ -127,6 +155,14 @@ declare const commands: Readonly<{
|
|
|
127
155
|
} & {
|
|
128
156
|
readonly input: InputApi;
|
|
129
157
|
}>;
|
|
158
|
+
filter: Command<{
|
|
159
|
+
kind: "string";
|
|
160
|
+
on: "boolean";
|
|
161
|
+
}, readonly string[], HeadlessApp & {
|
|
162
|
+
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
163
|
+
} & {
|
|
164
|
+
readonly effects?: EffectsApi;
|
|
165
|
+
}>;
|
|
130
166
|
}>;
|
|
131
167
|
//#endregion
|
|
132
168
|
export { commands as t };
|
|
@@ -35,10 +35,27 @@ function systemNames() {
|
|
|
35
35
|
]);
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
+
* The modes a debug page may start the overlay in.
|
|
39
|
+
*
|
|
40
|
+
* @returns The set of `debug.overlay` values.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* overlayStarts().has("pill"); // true
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
function overlayStarts() {
|
|
47
|
+
return /* @__PURE__ */ new Set([
|
|
48
|
+
"closed",
|
|
49
|
+
"pill",
|
|
50
|
+
"open"
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
38
54
|
* Throws for the first value of a config that TypeScript would have refused.
|
|
39
55
|
*
|
|
40
56
|
* @param config - The default export of `config.ts`.
|
|
41
|
-
* @throws {Error} When `save` is not a save kind, a `system` name is not wired,
|
|
57
|
+
* @throws {Error} When `save` is not a save kind, a `system` name is not wired, the title is empty, or
|
|
58
|
+
* `debug.overlay` is not a start mode.
|
|
42
59
|
*/
|
|
43
60
|
function checkConfig(config) {
|
|
44
61
|
if (config.save !== void 0 && !saveKinds().has(config.save)) throw new Error(`[game] config.save is "${config.save}".\n Use "memory", "local" or "store".`);
|
|
@@ -46,15 +63,18 @@ function checkConfig(config) {
|
|
|
46
63
|
const unwired = config.system?.find((name) => !wired.has(name));
|
|
47
64
|
if (unwired !== void 0) throw new Error(`[game] config.system names "${unwired}", which the game shell does not wire.\n Use lifecycle, back, haptics, keepAwake or store.`);
|
|
48
65
|
if (config.page.title.trim() === "") throw new Error("[game] config.page.title is empty.\n Give the page a title in config.ts.");
|
|
66
|
+
const overlay = config.debug?.overlay;
|
|
67
|
+
if (overlay !== void 0 && !overlayStarts().has(overlay)) throw new Error(`[game] config.ts: debug.overlay must be "closed", "pill" or "open", got "${String(overlay)}".`);
|
|
49
68
|
}
|
|
50
69
|
/**
|
|
51
70
|
* Fills every default of a game's `config.ts`: `lang` `"en"`, `background` `"#000000"`,
|
|
52
71
|
* `orientation` `"portrait"`, no icons, no head tags, no system plugin, the memory save, no asset
|
|
53
|
-
* layers.
|
|
72
|
+
* layers, the overlay of a debug page closed at its start.
|
|
54
73
|
*
|
|
55
74
|
* @param config - The default export of `config.ts`.
|
|
56
75
|
* @returns The config with every field set.
|
|
57
|
-
* @throws {Error} When `save` is not a save kind, a `system` name is not wired,
|
|
76
|
+
* @throws {Error} When `save` is not a save kind, a `system` name is not wired, the title is empty, or
|
|
77
|
+
* `debug.overlay` is not a start mode.
|
|
58
78
|
* @example
|
|
59
79
|
* ```ts
|
|
60
80
|
* resolveConfig({ page: { title: "T" } }).save; // "memory"
|
|
@@ -74,7 +94,8 @@ function resolveConfig(config) {
|
|
|
74
94
|
native: config.native,
|
|
75
95
|
system: config.system ?? [],
|
|
76
96
|
save: config.save ?? "memory",
|
|
77
|
-
assets: { layers: config.assets?.layers ?? {} }
|
|
97
|
+
assets: { layers: config.assets?.layers ?? {} },
|
|
98
|
+
debug: { overlay: config.debug?.overlay ?? "closed" }
|
|
78
99
|
};
|
|
79
100
|
}
|
|
80
101
|
//#endregion
|
package/dist/control.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { t as HeadlessApp } from "./headless-
|
|
2
|
-
import { i as InputArguments, n as Command, o as InputSchema, s as Ran } from "./types-
|
|
3
|
-
import { t as commands } from "./commands-
|
|
4
|
-
import { t as defineCommand } from "./define-
|
|
1
|
+
import { t as HeadlessApp } from "./headless-cFveciuY.mjs";
|
|
2
|
+
import { i as InputArguments, n as Command, o as InputSchema, s as Ran } from "./types-DngFQJro.mjs";
|
|
3
|
+
import { t as commands } from "./commands-DAETmK86.mjs";
|
|
4
|
+
import { t as defineCommand } from "./define-BASd9ZUh.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/plugins/flow/doors/dev.d.ts
|
|
7
7
|
/**
|
|
8
|
-
* @file flow/doors — the
|
|
9
|
-
* the engine never replaces: `moku-game dev` defines it `true` (bunfig `define`) and sets
|
|
8
|
+
* @file flow/doors — the flags of a page and the errors a door throws. `__MOKU_GAME_DEV__` is a
|
|
9
|
+
* global the engine never replaces: `moku-game dev` defines it `true` (bunfig `define`) and sets
|
|
10
10
|
* `globalThis.__MOKU_GAME_DEV__` in `.moku/dev.ts` before the engine runs; `moku-game build`
|
|
11
11
|
* defines it `false`; undefined means a production build.
|
|
12
12
|
*
|
|
@@ -14,6 +14,8 @@ import { t as defineCommand } from "./define-Ce8SVEN-.mjs";
|
|
|
14
14
|
* vanish from a production bundle writes the guard inline:
|
|
15
15
|
* `if (typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) throw controlRefused();`.
|
|
16
16
|
* A `define` of `false` folds that condition, and the minifier drops the code behind it.
|
|
17
|
+
* `__MOKU_GAME_AGENT__` and `__MOKU_GAME_CONTROL__` follow the same rules: a define of `false`
|
|
18
|
+
* folds their guard.
|
|
17
19
|
*/
|
|
18
20
|
declare global {
|
|
19
21
|
/**
|
|
@@ -27,40 +29,150 @@ declare global {
|
|
|
27
29
|
* ```
|
|
28
30
|
*/
|
|
29
31
|
var __MOKU_GAME_DEV__: boolean | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* The agent flag: the editor's page agent is on the page, and measurement code runs. `moku-game dev` and
|
|
34
|
+
* `moku-game build --debug` set it, `moku-game build` defines it `false`. A game never re-declares it.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // The in-memory agent.ts of `moku-game build --debug`, the first import of its main.ts.
|
|
39
|
+
* globalThis.__MOKU_GAME_AGENT__ = true;
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
var __MOKU_GAME_AGENT__: boolean | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* The control flag: every /control command runs, the state-changing ones too (`route`, `cheat`, `raw`).
|
|
45
|
+
* `moku-game dev` and `moku-game build --debug=full` set it; `--debug` and `moku-game build` define it `false`.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* // The in-memory agent.ts of `moku-game build --debug=full`.
|
|
50
|
+
* globalThis.__MOKU_GAME_CONTROL__ = true;
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
var __MOKU_GAME_CONTROL__: boolean | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The id of the build the page came from: `"dev"` on the dev page, `"debug-20261014T153012Z"` or
|
|
56
|
+
* `"debug-full-20261014T153012Z"` on a debug build, undefined on a release build.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* // The overlay shows which build runs on the phone.
|
|
61
|
+
* globalThis.__MOKU_GAME_BUILD__; // "debug-20261014T153012Z"
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
var __MOKU_GAME_BUILD__: string | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* The engine the page runs: the id of `engineFingerprint` (E), its version plus a hash of its bundled `dist` and of
|
|
67
|
+
* any patch of that version. Set on the dev page and on a debug build; undefined on a release build. The editor's
|
|
68
|
+
* overlay and the header of the performance log (spec 11) read it; the engine's plugins never do.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* // The overlay names the engine the phone runs.
|
|
73
|
+
* globalThis.__MOKU_GAME_ENGINE__; // "0.14.12+9c41e0.patch.3f2a7b"
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
var __MOKU_GAME_ENGINE__: string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Where the page agent of a debug build finds the editor: `host:port`, written by `--editor` (default
|
|
79
|
+
* `"127.0.0.1:47600"`). Undefined on the dev page, whose agent talks to the server that served it, and on a release
|
|
80
|
+
* build.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* // moku-game build --debug --editor 192.168.1.20:47600
|
|
85
|
+
* globalThis.__MOKU_GAME_EDITOR__; // "192.168.1.20:47600"
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
var __MOKU_GAME_EDITOR__: string | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* The overlay channel of the page agent: the editor's page agent sets it when it starts and deletes it when it stops.
|
|
91
|
+
* `open()` shows the card; `open({ mode: "pill" })` the small pill; `toggle()` switches between hidden and the last
|
|
92
|
+
* visible mode; `isOpen()` is true for the pill or the card. A game never sets it: it calls `app.debug.overlay`.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* // The editor's page agent, at start:
|
|
97
|
+
* globalThis.__MOKU_GAME_OVERLAY__ = { open: options => overlay.show(options?.mode ?? "card"), close, toggle, isOpen };
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
var __MOKU_GAME_OVERLAY__: {
|
|
101
|
+
open(options?: {
|
|
102
|
+
mode?: "pill" | "card";
|
|
103
|
+
}): void;
|
|
104
|
+
close(): void;
|
|
105
|
+
toggle(): void;
|
|
106
|
+
isOpen(): boolean;
|
|
107
|
+
} | undefined;
|
|
30
108
|
}
|
|
31
109
|
/**
|
|
32
|
-
*
|
|
110
|
+
* The error `run` throws on a `--debug` page for a command that changes the game: its `reason`
|
|
111
|
+
* tells it apart from any other failure.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // The editor greys the command out instead of reporting a failure.
|
|
116
|
+
* const refused: ControlReadOnlyError = controlReadOnly("game.tap");
|
|
117
|
+
* refused.reason; // "read-only"
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
type ControlReadOnlyError = Error & {
|
|
121
|
+
readonly reason: "read-only";
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* The error a control command throws when its body runs outside the builds its guard allows. It
|
|
125
|
+
* carries `reason: "dev-only"`, so an editor tells a refusal by the body's guard apart from a
|
|
126
|
+
* failure, as `reason: "read-only"` tells the refusal of `run` on a `--debug` page.
|
|
33
127
|
*
|
|
34
|
-
* @returns True only when `__MOKU_GAME_DEV__` is exactly `true`.
|
|
35
128
|
* @example
|
|
36
129
|
* ```ts
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* isDev(); // true
|
|
130
|
+
* const refused: ControlRefusedError = controlRefused();
|
|
131
|
+
* refused.reason; // "dev-only"
|
|
40
132
|
* ```
|
|
41
133
|
*/
|
|
134
|
+
type ControlRefusedError = Error & {
|
|
135
|
+
readonly reason: "dev-only";
|
|
136
|
+
};
|
|
42
137
|
/**
|
|
43
|
-
* Builds the error a control command throws outside a dev build.
|
|
138
|
+
* Builds the error a control command throws outside a dev build. It carries `reason: "dev-only"`.
|
|
44
139
|
*
|
|
45
140
|
* @returns The error, ready to throw.
|
|
46
141
|
* @example
|
|
47
142
|
* ```ts
|
|
48
143
|
* // A production build called a /control command.
|
|
49
144
|
* controlRefused().message; // "[game] Control commands run in dev builds only.\n Define __MOKU_GAME_DEV__ as true in the dev build."
|
|
145
|
+
* controlRefused().reason; // "dev-only"
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function controlRefused(): ControlRefusedError;
|
|
149
|
+
/**
|
|
150
|
+
* Builds the error `run` throws on a `--debug` page for a command whose effect is `route`,
|
|
151
|
+
* `cheat` or `raw`. It carries `reason: "read-only"`, so an editor tells it apart from a failure.
|
|
152
|
+
*
|
|
153
|
+
* @param id - The id of the refused command.
|
|
154
|
+
* @returns The error, ready to throw.
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* // The editor on a --debug page.
|
|
158
|
+
* try { await run(app, commands.tap, { key: "play" }); } catch (error) { Reflect.get(Object(error), "reason"); // "read-only" }
|
|
50
159
|
* ```
|
|
51
160
|
*/
|
|
52
|
-
declare function
|
|
161
|
+
declare function controlReadOnly(id: string): ControlReadOnlyError;
|
|
53
162
|
//#endregion
|
|
54
163
|
//#region src/plugins/flow/doors/run.d.ts
|
|
55
164
|
/**
|
|
56
|
-
* Runs a command in a dev build. A
|
|
57
|
-
*
|
|
165
|
+
* Runs a command in a dev build or a debug build. A debug build of `--debug` runs the read and
|
|
166
|
+
* cosmetic commands only; `--debug=full` and the dev page run every command. A `cheat` or `raw`
|
|
167
|
+
* command taints the session and is journaled before it runs, so a failing one still counts.
|
|
58
168
|
*
|
|
59
169
|
* @param app - The app the command acts on.
|
|
60
170
|
* @param command - The command.
|
|
61
171
|
* @param input - Its input; left out when every field of its schema is optional.
|
|
62
172
|
* @returns The command's value and the envelope read after it.
|
|
63
|
-
* @throws {Error} Outside
|
|
173
|
+
* @throws {Error} Outside dev builds and debug builds (read and cosmetic commands; every command
|
|
174
|
+
* with `--debug=full`), the read-only refusal of `controlReadOnly` for a `route`, `cheat` or
|
|
175
|
+
* `raw` command on a `--debug` page, and whatever the command throws.
|
|
64
176
|
* @example
|
|
65
177
|
* ```ts
|
|
66
178
|
* // An e2e script: load the bug report, then tap Play.
|
|
@@ -68,8 +180,9 @@ declare function controlRefused(): Error;
|
|
|
68
180
|
* const ran = await run(app, commands.answer, { intent: "play" });
|
|
69
181
|
* ran.value; // true
|
|
70
182
|
* ran.state; // { path: "board/awaitIntent", frame: 14, tainted: true }
|
|
183
|
+
* // On a --debug page: await run(app, commands.tap, { key: "play" }); // throws "[game] The command game.tap changes the game: …"
|
|
71
184
|
* ```
|
|
72
185
|
*/
|
|
73
186
|
declare function run<S extends InputSchema, O, App extends HeadlessApp>(app: App, command: Command<S, O, App>, ...input: InputArguments<S>): Promise<Ran<O>>;
|
|
74
187
|
//#endregion
|
|
75
|
-
export { type Command, type Ran, commands, controlRefused, defineCommand, run };
|
|
188
|
+
export { type Command, type ControlReadOnlyError, type ControlRefusedError, type Ran, commands, controlReadOnly, controlRefused, defineCommand, run };
|
package/dist/control.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { s as defineCommand } from "./session-
|
|
3
|
-
import { n as commands, t as run } from "./run-
|
|
4
|
-
export { commands, controlRefused, defineCommand, run };
|
|
1
|
+
import { n as controlRefused, t as controlReadOnly } from "./dev-DbHgx-R-.mjs";
|
|
2
|
+
import { s as defineCommand } from "./session-CeKgO2hy.mjs";
|
|
3
|
+
import { n as commands, t as run } from "./run-BbipFRc6.mjs";
|
|
4
|
+
export { commands, controlReadOnly, controlRefused, defineCommand, run };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as HeadlessApp } from "./headless-
|
|
2
|
-
import { c as Source, n as Command, o as InputSchema } from "./types-
|
|
1
|
+
import { t as HeadlessApp } from "./headless-cFveciuY.mjs";
|
|
2
|
+
import { c as Source, n as Command, o as InputSchema } from "./types-DngFQJro.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/flow/doors/define.d.ts
|
|
5
5
|
/**
|
|
@@ -25,8 +25,13 @@ import { c as Source, n as Command, o as InputSchema } from "./types-CAPv9l29.mj
|
|
|
25
25
|
*/
|
|
26
26
|
declare function defineSource<S extends InputSchema, O, App = HeadlessApp>(source: Source<S, O, App>): Source<S, O, App>;
|
|
27
27
|
/**
|
|
28
|
-
* Declares a command:
|
|
29
|
-
*
|
|
28
|
+
* Declares a command: an action the editor lists and runs on the dev page and on a debug page.
|
|
29
|
+
* Its body starts with the guard of its effect: the agent form for `read` and `cosmetic`, the
|
|
30
|
+
* control form for the others (see docs/doors.md), so a production build drops it. A game's
|
|
31
|
+
* `.dev` command with only the `__MOKU_GAME_DEV__` guard runs in dev and is refused on a debug
|
|
32
|
+
* page. `overlay` shows it in the editor's overlay: `"toggle"` with the input `{ on: "boolean" }`
|
|
33
|
+
* and a `value(app)` the switch is drawn from, `"button"` with no required input and no value;
|
|
34
|
+
* any other combination is a type error.
|
|
30
35
|
*
|
|
31
36
|
* @param command - The descriptor.
|
|
32
37
|
* @returns The same descriptor, frozen.
|
|
@@ -46,6 +51,29 @@ declare function defineSource<S extends InputSchema, O, App = HeadlessApp>(sourc
|
|
|
46
51
|
* });
|
|
47
52
|
* (await run(app, openShop)).state.path; // "shop"
|
|
48
53
|
* ```
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // features/ward/glow.dev.ts — the overlay's "Glow" switch of this game.
|
|
57
|
+
* export const glowSwitch = defineCommand({
|
|
58
|
+
* id: "ward.glow",
|
|
59
|
+
* title: "Glow",
|
|
60
|
+
* input: { on: "boolean" },
|
|
61
|
+
* effect: "cosmetic",
|
|
62
|
+
* overlay: "toggle",
|
|
63
|
+
* value: (app: { readonly effects: Effects.EffectsApi }) =>
|
|
64
|
+
* !app.effects.diagnostics.disabled().includes("effects.glow"),
|
|
65
|
+
* run: (app, { on }) => {
|
|
66
|
+
* if (
|
|
67
|
+
* (typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) &&
|
|
68
|
+
* (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)
|
|
69
|
+
* ) {
|
|
70
|
+
* throw controlRefused();
|
|
71
|
+
* }
|
|
72
|
+
* return on ? app.effects.diagnostics.enable("effects.glow") : app.effects.diagnostics.disable("effects.glow");
|
|
73
|
+
* }
|
|
74
|
+
* });
|
|
75
|
+
* // The overlay draws a switch "Glow", on; a tap runs it with { on: false } and the next frame draws no glow.
|
|
76
|
+
* ```
|
|
49
77
|
*/
|
|
50
78
|
declare function defineCommand<S extends InputSchema, O, App = HeadlessApp>(command: Command<S, O, App>): Command<S, O, App>;
|
|
51
79
|
//#endregion
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//#region src/plugins/flow/doors/dev.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads the dev flag at call time. Undefined means off: production is the default.
|
|
4
|
+
*
|
|
5
|
+
* @returns True only when `__MOKU_GAME_DEV__` is exactly `true`.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // The dev page set the flag in .moku/dev.ts before the engine started.
|
|
9
|
+
* globalThis.__MOKU_GAME_DEV__ = true;
|
|
10
|
+
* isDev(); // true
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
function isDev() {
|
|
14
|
+
return typeof __MOKU_GAME_DEV__ !== "undefined" && __MOKU_GAME_DEV__ === true;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reads the agent flag at call time, for a runtime check; a branch that must leave a bundle
|
|
18
|
+
* writes the inline guard instead.
|
|
19
|
+
*
|
|
20
|
+
* @returns True only when `__MOKU_GAME_AGENT__` is exactly `true`.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* isAgent(); // true on the page of moku-game build --debug, false on a release page
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
function isAgent() {
|
|
27
|
+
return typeof __MOKU_GAME_AGENT__ !== "undefined" && __MOKU_GAME_AGENT__ === true;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Reads the control flag at call time, for a runtime check; a branch that must leave a bundle
|
|
31
|
+
* writes the inline guard instead.
|
|
32
|
+
*
|
|
33
|
+
* @returns True only when `__MOKU_GAME_CONTROL__` is exactly `true`.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* isControl(); // true on the page of moku-game build --debug=full, false on a --debug page
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
function isControl() {
|
|
40
|
+
return typeof __MOKU_GAME_CONTROL__ !== "undefined" && __MOKU_GAME_CONTROL__ === true;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Builds the error a control command throws outside a dev build. It carries `reason: "dev-only"`.
|
|
44
|
+
*
|
|
45
|
+
* @returns The error, ready to throw.
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // A production build called a /control command.
|
|
49
|
+
* controlRefused().message; // "[game] Control commands run in dev builds only.\n Define __MOKU_GAME_DEV__ as true in the dev build."
|
|
50
|
+
* controlRefused().reason; // "dev-only"
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function controlRefused() {
|
|
54
|
+
return Object.assign(/* @__PURE__ */ new Error("[game] Control commands run in dev builds only.\n Define __MOKU_GAME_DEV__ as true in the dev build."), { reason: "dev-only" });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds the error `run` throws on a `--debug` page for a command whose effect is `route`,
|
|
58
|
+
* `cheat` or `raw`. It carries `reason: "read-only"`, so an editor tells it apart from a failure.
|
|
59
|
+
*
|
|
60
|
+
* @param id - The id of the refused command.
|
|
61
|
+
* @returns The error, ready to throw.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* // The editor on a --debug page.
|
|
65
|
+
* try { await run(app, commands.tap, { key: "play" }); } catch (error) { Reflect.get(Object(error), "reason"); // "read-only" }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
function controlReadOnly(id) {
|
|
69
|
+
return Object.assign(/* @__PURE__ */ new Error(`[game] The command ${id} changes the game: this debug build runs read and cosmetic commands only.\n Build with moku-game build --debug=full to run it.`), { reason: "read-only" });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Builds the error a door source or command throws when the opt-in plugin it uses is not
|
|
73
|
+
* installed.
|
|
74
|
+
*
|
|
75
|
+
* @param id - The id of the source or the command.
|
|
76
|
+
* @param plugin - The export name of the plugin it uses.
|
|
77
|
+
* @param kind - What the door descriptor is. A source by default.
|
|
78
|
+
* @returns The error, ready to throw.
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* notInstalled("game.sounds", "audioPlugin").message; // "[game] The source game.sounds needs audioPlugin.\n Add audioPlugin to createApp({ plugins })."
|
|
82
|
+
* notInstalled("game.mute", "audioPlugin", "command").message; // "[game] The command game.mute needs audioPlugin.\n Add audioPlugin to createApp({ plugins })."
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
function notInstalled(id, plugin, kind = "source") {
|
|
86
|
+
return /* @__PURE__ */ new Error(`[game] The ${kind} ${id} needs ${plugin}.\n Add ${plugin} to createApp({ plugins }).`);
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { isDev as a, isControl as i, controlRefused as n, notInstalled as o, isAgent as r, controlReadOnly as t };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
//#region src/plugins/clock/fake.ts
|
|
2
|
+
/** Every source `fakeClock` made: the app shell keeps a fake clock's app from adapting its frame rate. */
|
|
3
|
+
const fakeClocks = /*#__PURE__*/ new WeakSet();
|
|
2
4
|
/**
|
|
3
5
|
* Removes and returns the timer that is due first, up to and including `until`.
|
|
4
6
|
* Timers due at the same moment come out in the order they were scheduled.
|
|
@@ -59,7 +61,7 @@ function fakeClock(start = 0) {
|
|
|
59
61
|
nextId: 1,
|
|
60
62
|
timers: []
|
|
61
63
|
};
|
|
62
|
-
|
|
64
|
+
const clock = {
|
|
63
65
|
now: () => state.now,
|
|
64
66
|
setTimer: (callback, delayMs) => {
|
|
65
67
|
const id = state.nextId;
|
|
@@ -82,6 +84,22 @@ function fakeClock(start = 0) {
|
|
|
82
84
|
state.now = moment;
|
|
83
85
|
}
|
|
84
86
|
};
|
|
87
|
+
fakeClocks.add(clock);
|
|
88
|
+
return clock;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Tells a source `fakeClock` made from any other: the app shell's test seams run on it, and their
|
|
92
|
+
* apps never adapt their frame rate. Not in the root.
|
|
93
|
+
*
|
|
94
|
+
* @param source - A clock source.
|
|
95
|
+
* @returns True for a fake source.
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* isFakeClock(fakeClock()); // true
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
function isFakeClock(source) {
|
|
102
|
+
return fakeClocks.has(source);
|
|
85
103
|
}
|
|
86
104
|
//#endregion
|
|
87
|
-
export { fakeClock as t };
|
|
105
|
+
export { isFakeClock as n, fakeClock as t };
|