@moku-labs/game 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/page.d.mts +6 -3
- package/dist/app/page.mjs +5 -2
- package/dist/app/system.d.mts +39 -24
- package/dist/app/system.mjs +71 -49
- package/dist/app.d.mts +1 -1
- package/dist/app.mjs +1 -1
- package/dist/cli.mjs +44 -9
- package/dist/{index-xxSxKJJW.d.mts → index-8TiJQjQA.d.mts} +13 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-DSl1eNB1.mjs → src-BSbtHZWk.mjs} +22 -9
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/{types-hQgI_wrq.d.mts → types-Ca_z_4tQ.d.mts} +50 -8
- package/llms.txt +3 -2
- package/package.json +1 -1
package/dist/app/page.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions } from "../types-Ca_z_4tQ.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/app/page.d.ts
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ import { h as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions }
|
|
|
20
20
|
* // Written by moku-game dev. Do not edit.
|
|
21
21
|
* import "./dev.ts";
|
|
22
22
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
23
|
-
* import {
|
|
23
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
24
24
|
* import game from "../index.ts";
|
|
25
25
|
* import config from "../config.ts";
|
|
26
26
|
* import scenario0 from "../tests/scenarios/empty.ts";
|
|
@@ -30,7 +30,10 @@ import { h as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions }
|
|
|
30
30
|
*
|
|
31
31
|
* await startPage(game, config, {
|
|
32
32
|
* scenarios: { "empty": scenario0, "full": scenario1 },
|
|
33
|
-
* system:
|
|
33
|
+
* system: systemShellOf({
|
|
34
|
+
* system: () => import("@moku-labs/system"),
|
|
35
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle")
|
|
36
|
+
* }),
|
|
34
37
|
* agents: [agent0],
|
|
35
38
|
* devModules: [devModule0]
|
|
36
39
|
* });
|
package/dist/app/page.mjs
CHANGED
|
@@ -322,7 +322,7 @@ async function startAgents(app, settings, options) {
|
|
|
322
322
|
* // Written by moku-game dev. Do not edit.
|
|
323
323
|
* import "./dev.ts";
|
|
324
324
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
325
|
-
* import {
|
|
325
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
326
326
|
* import game from "../index.ts";
|
|
327
327
|
* import config from "../config.ts";
|
|
328
328
|
* import scenario0 from "../tests/scenarios/empty.ts";
|
|
@@ -332,7 +332,10 @@ async function startAgents(app, settings, options) {
|
|
|
332
332
|
*
|
|
333
333
|
* await startPage(game, config, {
|
|
334
334
|
* scenarios: { "empty": scenario0, "full": scenario1 },
|
|
335
|
-
* system:
|
|
335
|
+
* system: systemShellOf({
|
|
336
|
+
* system: () => import("@moku-labs/system"),
|
|
337
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle")
|
|
338
|
+
* }),
|
|
336
339
|
* agents: [agent0],
|
|
337
340
|
* devModules: [devModule0]
|
|
338
341
|
* });
|
package/dist/app/system.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tn as PlayerStateProvider } from "../types-ZQLYXo5X.mjs";
|
|
2
|
-
import { ot as PlatformProvider } from "../index-
|
|
3
|
-
import { _ as
|
|
2
|
+
import { ot as PlatformProvider } from "../index-8TiJQjQA.mjs";
|
|
3
|
+
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-Ca_z_4tQ.mjs";
|
|
4
4
|
import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
5
5
|
|
|
6
6
|
//#region src/app/system.d.ts
|
|
@@ -11,7 +11,8 @@ import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
|
-
* const
|
|
14
|
+
* const modules = { system: () => import("@moku-labs/system"), haptics: () => import("@moku-labs/system/haptics") };
|
|
15
|
+
* const slice: SystemSlice = await createSystemApp(["haptics"], "moku-game", modules); // slice.haptics only
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
17
18
|
type SystemSlice = {
|
|
@@ -36,7 +37,11 @@ type StoreSlice = Pick<Store.StoreApi, "get" | "set">;
|
|
|
36
37
|
*
|
|
37
38
|
* @example
|
|
38
39
|
* ```ts
|
|
39
|
-
* const system: SystemApp = await createSystemApp(["lifecycle", "store"], "com.mokulabs.timber"
|
|
40
|
+
* const system: SystemApp = await createSystemApp(["lifecycle", "store"], "com.mokulabs.timber", {
|
|
41
|
+
* system: () => import("@moku-labs/system"),
|
|
42
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle"),
|
|
43
|
+
* store: () => import("@moku-labs/system/store")
|
|
44
|
+
* });
|
|
40
45
|
* await system.start(); // system.lifecycle and system.store answer from here on
|
|
41
46
|
* ```
|
|
42
47
|
*/
|
|
@@ -64,22 +69,28 @@ declare function fromSystem(system: SystemSlice): PlatformProvider;
|
|
|
64
69
|
/**
|
|
65
70
|
* Creates the `@moku-labs/system` app of the named plugins, in the fixed order `lifecycle`,
|
|
66
71
|
* `back`, `haptics`, `keepAwake`, `store`, each name once. The store is named after `namespace`.
|
|
67
|
-
* Each plugin is loaded by its
|
|
68
|
-
* The app is not started.
|
|
72
|
+
* Each plugin is loaded by its loader in `modules`, and only the named ones are called, so a page
|
|
73
|
+
* loads only the plugins its game names. The app is not started.
|
|
69
74
|
*
|
|
70
75
|
* @param names - The system plugins the game names, in any order.
|
|
71
76
|
* @param namespace - The store name: the native identifier, or `"moku-game"`.
|
|
77
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
72
78
|
* @returns The system app, not started.
|
|
73
|
-
* @throws {Error} When
|
|
79
|
+
* @throws {Error} When a named plugin has no loader in `modules`, or a loader rejects because
|
|
80
|
+
* `@moku-labs/system` is not installed.
|
|
74
81
|
* @example
|
|
75
82
|
* ```ts
|
|
76
83
|
* // A shell of its own: the store named after the app, and the haptics.
|
|
77
|
-
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber"
|
|
84
|
+
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber", {
|
|
85
|
+
* system: () => import("@moku-labs/system"),
|
|
86
|
+
* haptics: () => import("@moku-labs/system/haptics"),
|
|
87
|
+
* store: () => import("@moku-labs/system/store")
|
|
88
|
+
* });
|
|
78
89
|
* await system.start();
|
|
79
90
|
* await system.haptics?.selection(); // { ok: false, provider: "web", reason: "unsupported" } in iOS Safari
|
|
80
91
|
* ```
|
|
81
92
|
*/
|
|
82
|
-
declare function createSystemApp(names: readonly SystemName[], namespace: string): Promise<SystemApp>;
|
|
93
|
+
declare function createSystemApp(names: readonly SystemName[], namespace: string, modules: SystemModules): Promise<SystemApp>;
|
|
83
94
|
/**
|
|
84
95
|
* Builds the save provider over the system store: idb on the web, the Tauri store in the native
|
|
85
96
|
* app. It holds the document it loaded and applies each commit's patches to it, then queues one
|
|
@@ -102,28 +113,32 @@ declare function createSystemApp(names: readonly SystemName[], namespace: string
|
|
|
102
113
|
*/
|
|
103
114
|
declare function storeSave(store: StoreSlice, key: string, report: (problem: string) => void): PlayerStateProvider;
|
|
104
115
|
/**
|
|
105
|
-
*
|
|
106
|
-
* `config.system`
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
116
|
+
* Makes the system shell factory of a page over its loaders. The factory builds the shell from the
|
|
117
|
+
* resolved `config.ts`: the `@moku-labs/system` app of the names `config.system` lists, plus the
|
|
118
|
+
* store when `config.save` is `"store"`, in the fixed order. It hands the engine the platform
|
|
119
|
+
* provider over that app and, for a store save, the save provider. Nothing loads until the page
|
|
120
|
+
* calls the factory, and the page starts the shell before the game. The generated `main.ts`
|
|
121
|
+
* passes it to `startPage` with one loader per name, only when `config.ts` names a system plugin
|
|
122
|
+
* or the store save.
|
|
111
123
|
*
|
|
112
|
-
* @param
|
|
113
|
-
* @
|
|
114
|
-
* @returns The shell, not started.
|
|
115
|
-
* @throws {Error} When `@moku-labs/system` is not installed.
|
|
124
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
125
|
+
* @returns The factory the page calls; it throws the messages of `createSystemApp`.
|
|
116
126
|
* @example
|
|
117
127
|
* ```ts
|
|
118
|
-
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names
|
|
128
|
+
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names back.
|
|
119
129
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
120
|
-
* import {
|
|
130
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
121
131
|
* import game from "../../index.ts";
|
|
122
132
|
* import config from "../../config.ts";
|
|
123
133
|
*
|
|
124
|
-
* await startPage(game, config, {
|
|
134
|
+
* await startPage(game, config, {
|
|
135
|
+
* system: systemShellOf({
|
|
136
|
+
* system: () => import("@moku-labs/system"),
|
|
137
|
+
* back: () => import("@moku-labs/system/back")
|
|
138
|
+
* })
|
|
139
|
+
* });
|
|
125
140
|
* ```
|
|
126
141
|
*/
|
|
127
|
-
declare function
|
|
142
|
+
declare function systemShellOf(modules: SystemModules): SystemShellFactory;
|
|
128
143
|
//#endregion
|
|
129
|
-
export { StoreSlice, SystemApp, SystemSlice, createSystemApp, fromSystem, storeSave,
|
|
144
|
+
export { StoreSlice, SystemApp, type SystemModules, SystemSlice, createSystemApp, fromSystem, storeSave, systemShellOf };
|
package/dist/app/system.mjs
CHANGED
|
@@ -8,21 +8,6 @@ const systemOrder = [
|
|
|
8
8
|
"keepAwake",
|
|
9
9
|
"store"
|
|
10
10
|
];
|
|
11
|
-
/** One lazy import per capability plugin: the page loads only the plugins the game names. */
|
|
12
|
-
const capabilityLoaders = {
|
|
13
|
-
lifecycle: () => import("@moku-labs/system/lifecycle").then((module) => module.lifecyclePlugin),
|
|
14
|
-
back: () => import("@moku-labs/system/back").then((module) => module.backPlugin),
|
|
15
|
-
haptics: () => import("@moku-labs/system/haptics").then((module) => module.hapticsPlugin),
|
|
16
|
-
keepAwake: () => import("@moku-labs/system/keep-awake").then((module) => module.keepAwakePlugin)
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Loads the store plugin, by its own lazy import.
|
|
20
|
-
*
|
|
21
|
-
* @returns The store plugin.
|
|
22
|
-
*/
|
|
23
|
-
function loadStore() {
|
|
24
|
-
return import("@moku-labs/system/store").then((module) => module.storePlugin);
|
|
25
|
-
}
|
|
26
11
|
/** The store namespace of a game with no native identifier. */
|
|
27
12
|
const defaultNamespace = "moku-game";
|
|
28
13
|
/** The store key of the save, inside the game's namespace. */
|
|
@@ -99,20 +84,45 @@ function fromSystem(system) {
|
|
|
99
84
|
};
|
|
100
85
|
}
|
|
101
86
|
/**
|
|
102
|
-
*
|
|
87
|
+
* Refuses a named plugin the page has no loader for, before anything loads. The generated
|
|
88
|
+
* `main.ts` writes a loader per name; a page of its own may miss one.
|
|
89
|
+
*
|
|
90
|
+
* @param names - The system plugins of the shell.
|
|
91
|
+
* @param modules - The loaders of the page.
|
|
92
|
+
* @throws {Error} When a name has no loader.
|
|
93
|
+
*/
|
|
94
|
+
function checkLoaders(names, modules) {
|
|
95
|
+
const missing = names.find((name) => modules[name] === void 0);
|
|
96
|
+
if (missing !== void 0) throw new Error(`[game] config.system names "${missing}", but main.ts has no loader for it.`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* One plugin per capability, through the loader of the page. The loaders are checked first, so
|
|
100
|
+
* each one called is there.
|
|
101
|
+
*/
|
|
102
|
+
const capabilityPlugins = {
|
|
103
|
+
lifecycle: (modules) => modules.lifecycle?.().then((module) => module.lifecyclePlugin),
|
|
104
|
+
back: (modules) => modules.back?.().then((module) => module.backPlugin),
|
|
105
|
+
haptics: (modules) => modules.haptics?.().then((module) => module.hapticsPlugin),
|
|
106
|
+
keepAwake: (modules) => modules.keepAwake?.().then((module) => module.keepAwakePlugin)
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Loads `@moku-labs/system` and the plugins of the names, all at once, with the loaders of the
|
|
110
|
+
* page.
|
|
103
111
|
*
|
|
104
112
|
* @param names - The system plugins, in the fixed order.
|
|
113
|
+
* @param modules - The loaders of the page.
|
|
105
114
|
* @returns The `createApp` of the package, the capability plugins in the order of the names, and
|
|
106
115
|
* the store plugin when the names hold it.
|
|
107
|
-
* @throws {Error} When the package is not installed.
|
|
116
|
+
* @throws {Error} When a name has no loader, or a loader rejects: the package is not installed.
|
|
108
117
|
*/
|
|
109
|
-
async function loadSystem(names) {
|
|
118
|
+
async function loadSystem(names, modules) {
|
|
119
|
+
checkLoaders(names, modules);
|
|
110
120
|
const capabilities = names.filter((name) => name !== "store");
|
|
111
121
|
try {
|
|
112
122
|
const [system, store, ...plugins] = await Promise.all([
|
|
113
|
-
|
|
114
|
-
names.includes("store") ?
|
|
115
|
-
...capabilities.map((name) =>
|
|
123
|
+
modules.system(),
|
|
124
|
+
names.includes("store") ? modules.store?.().then((module) => module.storePlugin) : void 0,
|
|
125
|
+
...capabilities.map((name) => capabilityPlugins[name](modules))
|
|
116
126
|
]);
|
|
117
127
|
return {
|
|
118
128
|
createApp: system.createApp,
|
|
@@ -126,23 +136,29 @@ async function loadSystem(names) {
|
|
|
126
136
|
/**
|
|
127
137
|
* Creates the `@moku-labs/system` app of the named plugins, in the fixed order `lifecycle`,
|
|
128
138
|
* `back`, `haptics`, `keepAwake`, `store`, each name once. The store is named after `namespace`.
|
|
129
|
-
* Each plugin is loaded by its
|
|
130
|
-
* The app is not started.
|
|
139
|
+
* Each plugin is loaded by its loader in `modules`, and only the named ones are called, so a page
|
|
140
|
+
* loads only the plugins its game names. The app is not started.
|
|
131
141
|
*
|
|
132
142
|
* @param names - The system plugins the game names, in any order.
|
|
133
143
|
* @param namespace - The store name: the native identifier, or `"moku-game"`.
|
|
144
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
134
145
|
* @returns The system app, not started.
|
|
135
|
-
* @throws {Error} When
|
|
146
|
+
* @throws {Error} When a named plugin has no loader in `modules`, or a loader rejects because
|
|
147
|
+
* `@moku-labs/system` is not installed.
|
|
136
148
|
* @example
|
|
137
149
|
* ```ts
|
|
138
150
|
* // A shell of its own: the store named after the app, and the haptics.
|
|
139
|
-
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber"
|
|
151
|
+
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber", {
|
|
152
|
+
* system: () => import("@moku-labs/system"),
|
|
153
|
+
* haptics: () => import("@moku-labs/system/haptics"),
|
|
154
|
+
* store: () => import("@moku-labs/system/store")
|
|
155
|
+
* });
|
|
140
156
|
* await system.start();
|
|
141
157
|
* await system.haptics?.selection(); // { ok: false, provider: "web", reason: "unsupported" } in iOS Safari
|
|
142
158
|
* ```
|
|
143
159
|
*/
|
|
144
|
-
async function createSystemApp(names, namespace) {
|
|
145
|
-
const { createApp, capabilities, store } = await loadSystem(systemOrder.filter((name) => names.includes(name)));
|
|
160
|
+
async function createSystemApp(names, namespace, modules) {
|
|
161
|
+
const { createApp, capabilities, store } = await loadSystem(systemOrder.filter((name) => names.includes(name)), modules);
|
|
146
162
|
if (store === void 0) return createApp({ plugins: capabilities });
|
|
147
163
|
return createApp({
|
|
148
164
|
plugins: [...capabilities, store],
|
|
@@ -271,37 +287,43 @@ function storeSave(store, key, report) {
|
|
|
271
287
|
};
|
|
272
288
|
}
|
|
273
289
|
/**
|
|
274
|
-
*
|
|
275
|
-
* `config.system`
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
290
|
+
* Makes the system shell factory of a page over its loaders. The factory builds the shell from the
|
|
291
|
+
* resolved `config.ts`: the `@moku-labs/system` app of the names `config.system` lists, plus the
|
|
292
|
+
* store when `config.save` is `"store"`, in the fixed order. It hands the engine the platform
|
|
293
|
+
* provider over that app and, for a store save, the save provider. Nothing loads until the page
|
|
294
|
+
* calls the factory, and the page starts the shell before the game. The generated `main.ts`
|
|
295
|
+
* passes it to `startPage` with one loader per name, only when `config.ts` names a system plugin
|
|
296
|
+
* or the store save.
|
|
280
297
|
*
|
|
281
|
-
* @param
|
|
282
|
-
* @
|
|
283
|
-
* @returns The shell, not started.
|
|
284
|
-
* @throws {Error} When `@moku-labs/system` is not installed.
|
|
298
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
299
|
+
* @returns The factory the page calls; it throws the messages of `createSystemApp`.
|
|
285
300
|
* @example
|
|
286
301
|
* ```ts
|
|
287
|
-
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names
|
|
302
|
+
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names back.
|
|
288
303
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
289
|
-
* import {
|
|
304
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
290
305
|
* import game from "../../index.ts";
|
|
291
306
|
* import config from "../../config.ts";
|
|
292
307
|
*
|
|
293
|
-
* await startPage(game, config, {
|
|
308
|
+
* await startPage(game, config, {
|
|
309
|
+
* system: systemShellOf({
|
|
310
|
+
* system: () => import("@moku-labs/system"),
|
|
311
|
+
* back: () => import("@moku-labs/system/back")
|
|
312
|
+
* })
|
|
313
|
+
* });
|
|
294
314
|
* ```
|
|
295
315
|
*/
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
316
|
+
function systemShellOf(modules) {
|
|
317
|
+
return async (config, report) => {
|
|
318
|
+
const app = await createSystemApp(config.save === "store" ? [...config.system, "store"] : config.system, config.native?.identifier ?? defaultNamespace, modules);
|
|
319
|
+
return {
|
|
320
|
+
handle: app,
|
|
321
|
+
platform: fromSystem(app),
|
|
322
|
+
save: app.store === void 0 ? void 0 : storeSave(app.store, saveKey, report),
|
|
323
|
+
start: () => app.start(),
|
|
324
|
+
stop: () => app.stop()
|
|
325
|
+
};
|
|
304
326
|
};
|
|
305
327
|
}
|
|
306
328
|
//#endregion
|
|
307
|
-
export { createSystemApp, fromSystem, storeSave,
|
|
329
|
+
export { createSystemApp, fromSystem, storeSave, systemShellOf };
|
package/dist/app.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Xt as Json } from "./types-ZQLYXo5X.mjs";
|
|
2
|
-
import { a as GameHandle, c as MemoryProvider,
|
|
2
|
+
import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-Ca_z_4tQ.mjs";
|
|
3
3
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
4
4
|
|
|
5
5
|
//#region src/app/define.d.ts
|
package/dist/app.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as platformPlugin, i as screen, jt as audioPlugin, t as createApp, xt as effectsPlugin } from "./src-
|
|
1
|
+
import { H as platformPlugin, i as screen, jt as audioPlugin, t as createApp, xt as effectsPlugin } from "./src-BSbtHZWk.mjs";
|
|
2
2
|
import { t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
|
|
4
4
|
//#region src/app/define.ts
|
package/dist/cli.mjs
CHANGED
|
@@ -13,6 +13,17 @@ const SAFE_VALUE = /^[#\w(),.%\s-]+$/;
|
|
|
13
13
|
/** The files of `tests/scenarios/` that are not scenarios. */
|
|
14
14
|
const NOT_SCENARIO = /\.(?:test|spec|d)\.ts$|^index\.ts$/;
|
|
15
15
|
/**
|
|
16
|
+
* The entry of `@moku-labs/system` each system plugin loads from, in the order the shell composes
|
|
17
|
+
* them.
|
|
18
|
+
*/
|
|
19
|
+
const SYSTEM_ENTRIES = [
|
|
20
|
+
["lifecycle", "lifecycle"],
|
|
21
|
+
["back", "back"],
|
|
22
|
+
["haptics", "haptics"],
|
|
23
|
+
["keepAwake", "keep-awake"],
|
|
24
|
+
["store", "store"]
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
16
27
|
* Escapes the five characters HTML reads as markup.
|
|
17
28
|
*
|
|
18
29
|
* @param text - The text.
|
|
@@ -133,7 +144,7 @@ function scenarioFiles(files) {
|
|
|
133
144
|
* Whether the page needs the system shell: a system plugin is named, or the save is the store.
|
|
134
145
|
*
|
|
135
146
|
* @param settings - The resolved `config.ts`.
|
|
136
|
-
* @returns True when `main.ts` imports `
|
|
147
|
+
* @returns True when `main.ts` imports `systemShellOf`.
|
|
137
148
|
* @example
|
|
138
149
|
* ```ts
|
|
139
150
|
* needsShell(resolveConfig({ page: { title: "T" }, save: "store" })); // true
|
|
@@ -143,6 +154,26 @@ function needsShell(settings) {
|
|
|
143
154
|
return settings.system.length > 0 || settings.save === "store";
|
|
144
155
|
}
|
|
145
156
|
/**
|
|
157
|
+
* The `system` option of `startPage`: `systemShellOf` over the loader of the package and one
|
|
158
|
+
* loader per plugin the shell composes, in the fixed order. The store is one when `config.system`
|
|
159
|
+
* names it or the save is the store. Only these `import()`s are written, so the page bundles no
|
|
160
|
+
* other plugin and never needs its native package.
|
|
161
|
+
*
|
|
162
|
+
* @param settings - The resolved `config.ts`.
|
|
163
|
+
* @returns The option, indented two spaces, with no comma after it.
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* shellOption(resolveConfig({ page: { title: "T" }, system: ["haptics"] })).split("\n")[2]; // ' haptics: () => import("@moku-labs/system/haptics")'
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
function shellOption(settings) {
|
|
170
|
+
return [
|
|
171
|
+
" system: systemShellOf({",
|
|
172
|
+
[" system: () => import(\"@moku-labs/system\")", ...SYSTEM_ENTRIES.filter(([name]) => settings.system.includes(name) || name === "store" && settings.save === "store").map(([name, entry]) => ` ${name}: () => import("@moku-labs/system/${entry}")`)].join(",\n"),
|
|
173
|
+
" })"
|
|
174
|
+
].join("\n");
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
146
177
|
* The imports of `main.ts` every page has: the page entry, the shell when needed, the game and its
|
|
147
178
|
* config.
|
|
148
179
|
*
|
|
@@ -157,7 +188,7 @@ function needsShell(settings) {
|
|
|
157
188
|
function pageImports(settings, toRoot) {
|
|
158
189
|
return [
|
|
159
190
|
"import { startPage } from \"@moku-labs/game/app/page\";",
|
|
160
|
-
...needsShell(settings) ? ["import {
|
|
191
|
+
...needsShell(settings) ? ["import { systemShellOf } from \"@moku-labs/game/app/system\";"] : [],
|
|
161
192
|
`import game from "${toRoot}index.ts";`,
|
|
162
193
|
`import config from "${toRoot}config.ts";`
|
|
163
194
|
];
|
|
@@ -194,8 +225,8 @@ function importLine(binding, specifier) {
|
|
|
194
225
|
/**
|
|
195
226
|
* The `main.ts` of the dev page: the dev flag first, then the page entry, the game, its config,
|
|
196
227
|
* one import per scenario, and, with agents, one per `.dev` module and one per agent. It calls
|
|
197
|
-
* `startPage` with the scenarios by file stem, the shell
|
|
198
|
-
* the `.dev` modules.
|
|
228
|
+
* `startPage` with the scenarios by file stem, the shell with the loaders of the named plugins
|
|
229
|
+
* when the game needs it, the agents and the `.dev` modules.
|
|
199
230
|
*
|
|
200
231
|
* @param settings - The resolved `config.ts`.
|
|
201
232
|
* @param sources - The scenario files, the `.dev` modules and the agents.
|
|
@@ -212,7 +243,7 @@ function devMain(settings, sources) {
|
|
|
212
243
|
const keys = scenarios.map((file, index) => `${JSON.stringify(file.slice(0, -3))}: scenario${index}`);
|
|
213
244
|
const options = [
|
|
214
245
|
` scenarios: ${keys.length === 0 ? "{}" : `{ ${keys.join(", ")} }`}`,
|
|
215
|
-
...needsShell(settings) ? [
|
|
246
|
+
...needsShell(settings) ? [shellOption(settings)] : [],
|
|
216
247
|
...agents.length === 0 ? [] : [` agents: [${numbered("agent", agents.length)}]`],
|
|
217
248
|
...devModules.length === 0 ? [] : [` devModules: [${numbered("devModule", devModules.length)}]`]
|
|
218
249
|
];
|
|
@@ -232,8 +263,8 @@ function devMain(settings, sources) {
|
|
|
232
263
|
}
|
|
233
264
|
/**
|
|
234
265
|
* The `main.ts` of the production page: the page entry, the game and its config, and the shell
|
|
235
|
-
* when the game needs it. No dev flag, no scenario, no
|
|
236
|
-
* them ships.
|
|
266
|
+
* with the loaders of the named plugins when the game needs it. No dev flag, no scenario, no
|
|
267
|
+
* agent, no `.dev` module, no door: none of them ships.
|
|
237
268
|
*
|
|
238
269
|
* @param settings - The resolved `config.ts`.
|
|
239
270
|
* @returns The text of the in-memory `.moku/build/main.ts`.
|
|
@@ -243,11 +274,15 @@ function devMain(settings, sources) {
|
|
|
243
274
|
* ```
|
|
244
275
|
*/
|
|
245
276
|
function buildMain(settings) {
|
|
246
|
-
const call = needsShell(settings) ?
|
|
277
|
+
const call = needsShell(settings) ? [
|
|
278
|
+
"await startPage(game, config, {",
|
|
279
|
+
shellOption(settings),
|
|
280
|
+
"});"
|
|
281
|
+
] : ["await startPage(game, config);"];
|
|
247
282
|
return [
|
|
248
283
|
...pageImports(settings, "../../"),
|
|
249
284
|
"",
|
|
250
|
-
call,
|
|
285
|
+
...call,
|
|
251
286
|
""
|
|
252
287
|
].join("\n");
|
|
253
288
|
}
|
|
@@ -476,6 +476,19 @@ type PlatformApi = {
|
|
|
476
476
|
* ```
|
|
477
477
|
*/
|
|
478
478
|
back(): BackResult;
|
|
479
|
+
/**
|
|
480
|
+
* Leaves the app through the provider, as the last step of `back()` does: no Escape, no intent
|
|
481
|
+
* `back`. A provider `exit` that throws is logged, never thrown. Without a provider it does
|
|
482
|
+
* nothing.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```ts
|
|
486
|
+
* // merge-game's exit plugin answers the fx "exit" of the Leave button.
|
|
487
|
+
* ctx.require(flowPlugin).fx.handle("exit", () => ctx.require(platformPlugin).exit());
|
|
488
|
+
* // a press of Leave: the provider leaves the app; on the web page without a provider, nothing
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
exit(): void;
|
|
479
492
|
};
|
|
480
493
|
/**
|
|
481
494
|
* What the kernel context offers the files of the plugin.
|
package/dist/index.d.mts
CHANGED
|
@@ -2,5 +2,5 @@ import { $ as DescriptionNode, $t as types_d_exports$9, C as types_d_exports$11,
|
|
|
2
2
|
import { B as sequence, F as frames, G as stagger, H as sfx, I as haptic, J as wait, K as tween, L as mark, M as HAPTIC_KINDS, N as defineAnimation, O as types_d_exports, P as external, R as parallel, U as spawn, V as set, W as spawned, b as types_d_exports$12, f as types_d_exports$2, i as types_d_exports$15, k as HapticKind, q as use, z as play } from "./types-BM4shh8K.mjs";
|
|
3
3
|
import { a as types_d_exports$4 } from "./types-CefgYzFt.mjs";
|
|
4
4
|
import { C as TextFormat, D as types_d_exports$13, H as Transform, I as Parent, L as Shape, M as types_d_exports$7, N as Display, O as defineComponent, P as NineSlice, W as sprite, Z as types_d_exports$6, d as popup, f as defineTokens, g as BindOptions, l as Box, u as LocalWrite, v as CountdownValue, z as Sprite } from "./types-BUwDHKXm.mjs";
|
|
5
|
-
import { $ as uiPlugin, A as Pointer, B as Layer, C as defineScene, Ct as label, D as DropTarget, E as Draggable, F as Tappable, G as resource, H as Tree, I as Touchable, J as guide, K as system, L as Traceable, M as Pressable, N as Pressed, O as Held, P as Swipeable, Q as worldPlugin, R as Traced, S as Frames, St as defineTextStyles, T as load, U as component, V as Order, W as mut, X as schedule, Y as hint, Z as defineFeature, _ as defineStyle, _t as animPlugin, a as defineEmitter, at as BackResult, b as AnimPlayer, bt as Text, c as Alpha, ct as modelPlugin, d as Displacement, dt as i18nPlugin, et as timePlugin, f as Glow, ft as flowPlugin, g as resolve, gt as assetsPlugin, h as music, ht as audioPlugin, i as screen, it as platformPlugin, j as PointerOver, k as Hovered, l as Blur, lt as lifecyclePlugin, m as Outline, mt as clockPlugin, n as createPlugin, nt as scenesPlugin, o as Emitter, ot as PlatformProvider, p as Noise, pt as effectsPlugin, q as tag, r as defineGame, rt as rendererPlugin, s as defineFilter, st as types_d_exports$10, t as createApp, tt as textPlugin, u as ColorMatrix, ut as inputPlugin, v as tr, vt as projection, w as defineBundles, x as Animation, xt as bind, y as defineMotion, yt as Countdown, z as Exiting } from "./index-
|
|
5
|
+
import { $ as uiPlugin, A as Pointer, B as Layer, C as defineScene, Ct as label, D as DropTarget, E as Draggable, F as Tappable, G as resource, H as Tree, I as Touchable, J as guide, K as system, L as Traceable, M as Pressable, N as Pressed, O as Held, P as Swipeable, Q as worldPlugin, R as Traced, S as Frames, St as defineTextStyles, T as load, U as component, V as Order, W as mut, X as schedule, Y as hint, Z as defineFeature, _ as defineStyle, _t as animPlugin, a as defineEmitter, at as BackResult, b as AnimPlayer, bt as Text, c as Alpha, ct as modelPlugin, d as Displacement, dt as i18nPlugin, et as timePlugin, f as Glow, ft as flowPlugin, g as resolve, gt as assetsPlugin, h as music, ht as audioPlugin, i as screen, it as platformPlugin, j as PointerOver, k as Hovered, l as Blur, lt as lifecyclePlugin, m as Outline, mt as clockPlugin, n as createPlugin, nt as scenesPlugin, o as Emitter, ot as PlatformProvider, p as Noise, pt as effectsPlugin, q as tag, r as defineGame, rt as rendererPlugin, s as defineFilter, st as types_d_exports$10, t as createApp, tt as textPlugin, u as ColorMatrix, ut as inputPlugin, v as tr, vt as projection, w as defineBundles, x as Animation, xt as bind, y as defineMotion, yt as Countdown, z as Exiting } from "./index-8TiJQjQA.mjs";
|
|
6
6
|
export { Alpha, types_d_exports as Anim, AnimPlayer, Animation, types_d_exports$1 as Assets, types_d_exports$2 as Audio, type BackResult, type BindOptions, Blur, Box, types_d_exports$3 as Clock, ColorMatrix, Countdown, type CountdownValue, type DescriptionNode, Displacement, Display, Draggable, DropTarget, types_d_exports$4 as Effects, Emitter, Exiting, types_d_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, type HapticKind, Held, Hovered, types_d_exports$6 as I18n, types_d_exports$7 as Input, Layer, types_d_exports$8 as Lifecycle, LocalWrite, types_d_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_d_exports$10 as Platform, type PlatformProvider, Pointer, PointerOver, Pressable, Pressed, types_d_exports$11 as Renderer, SaveUnreadableError, types_d_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, type TextFormat, types_d_exports$13 as TextTypes, types_d_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_d_exports$15 as Ui, types_d_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, modelPlugin, music, mut, parallel, platformPlugin, play, popup, projection, rendererPlugin, resolve, resource, scenesPlugin, schedule, screen, sequence, set, sfx, slot, spawn, spawned, sprite, stagger, system, tag, textPlugin, timePlugin, to, tr, tween, type, uiPlugin, use, wait, worldPlugin };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as sfx, A as types_exports$3, At as defineFilter, B as defineStyle, Bt as flowPlugin, C as types_exports$10, Ct as Alpha, D as types_exports$6, Dt as Glow, E as types_exports$7, Et as Displacement, F as resolve, Ft as AnimPlayer, G as external, Gt as modelPlugin, H as platformPlugin, Ht as slot, I as Box, It as Animation, J as mark, Jt as timePlugin, K as frames, Kt as SaveUnreadableError, L as LocalWrite, Lt as Frames, M as types_exports$1, Mt as scenesPlugin, N as types_exports, Nt as assetsPlugin, O as types_exports$5, Ot as Noise, P as uiPlugin, Pt as animPlugin, Q as set, R as popup, Rt as rendererPlugin, S as types_exports$11, St as Emitter, T as types_exports$8, Tt as ColorMatrix, U as HAPTIC_KINDS, Ut as to, V as textPlugin, Vt as exit, W as defineAnimation, Wt as type, X as play, Y as parallel, Yt as clockPlugin, Z as sequence, _ as types_exports$16, _t as Touchable, a as defineMotion, at as wait, b as types_exports$13, bt as i18nPlugin, c as schedule, ct as DropTarget, d as tr, dt as Pointer, et as spawn, f as defineFeature, ft as PointerOver, g as load, gt as Tappable, h as defineBundles, ht as Swipeable, i as screen, it as use, j as types_exports$2, jt as audioPlugin, k as types_exports$4, kt as Outline, l as projection, lt as Held, m as music, mt as Pressed, n as createPlugin, nt as stagger, o as guide, ot as inputPlugin, p as defineEmitter, pt as Pressable, q as haptic, qt as lifecyclePlugin, r as defineGame, rt as tween, s as hint, st as Draggable, t as createApp, tt as spawned, u as defineScene, ut as Hovered, v as types_exports$15, vt as Traceable, w as types_exports$9, wt as Blur, x as types_exports$12, xt as effectsPlugin, y as types_exports$14, yt as Traced, z as defineTokens, zt as worldPlugin } from "./src-
|
|
1
|
+
import { $ as sfx, A as types_exports$3, At as defineFilter, B as defineStyle, Bt as flowPlugin, C as types_exports$10, Ct as Alpha, D as types_exports$6, Dt as Glow, E as types_exports$7, Et as Displacement, F as resolve, Ft as AnimPlayer, G as external, Gt as modelPlugin, H as platformPlugin, Ht as slot, I as Box, It as Animation, J as mark, Jt as timePlugin, K as frames, Kt as SaveUnreadableError, L as LocalWrite, Lt as Frames, M as types_exports$1, Mt as scenesPlugin, N as types_exports, Nt as assetsPlugin, O as types_exports$5, Ot as Noise, P as uiPlugin, Pt as animPlugin, Q as set, R as popup, Rt as rendererPlugin, S as types_exports$11, St as Emitter, T as types_exports$8, Tt as ColorMatrix, U as HAPTIC_KINDS, Ut as to, V as textPlugin, Vt as exit, W as defineAnimation, Wt as type, X as play, Y as parallel, Yt as clockPlugin, Z as sequence, _ as types_exports$16, _t as Touchable, a as defineMotion, at as wait, b as types_exports$13, bt as i18nPlugin, c as schedule, ct as DropTarget, d as tr, dt as Pointer, et as spawn, f as defineFeature, ft as PointerOver, g as load, gt as Tappable, h as defineBundles, ht as Swipeable, i as screen, it as use, j as types_exports$2, jt as audioPlugin, k as types_exports$4, kt as Outline, l as projection, lt as Held, m as music, mt as Pressed, n as createPlugin, nt as stagger, o as guide, ot as inputPlugin, p as defineEmitter, pt as Pressable, q as haptic, qt as lifecyclePlugin, r as defineGame, rt as tween, s as hint, st as Draggable, t as createApp, tt as spawned, u as defineScene, ut as Hovered, v as types_exports$15, vt as Traceable, w as types_exports$9, wt as Blur, x as types_exports$12, xt as effectsPlugin, y as types_exports$14, yt as Traced, z as defineTokens, zt as worldPlugin } from "./src-BSbtHZWk.mjs";
|
|
2
2
|
import { A as system, C as Exiting, D as component, E as Tree, O as mut, S as sprite, T as Order, _ as Parent, b as Transform, c as Text, d as defineTextStyles, f as label, g as NineSlice, h as Display, j as tag, k as resource, l as bind, s as Countdown, v as Shape, w as Layer, y as Sprite } from "./visual-dMW8iqAE.mjs";
|
|
3
3
|
import { r as defineComponent } from "./flatten-BkXuscAV.mjs";
|
|
4
4
|
export { Alpha, types_exports as Anim, AnimPlayer, Animation, types_exports$1 as Assets, types_exports$2 as Audio, Blur, Box, types_exports$3 as Clock, ColorMatrix, Countdown, Displacement, Display, Draggable, DropTarget, types_exports$4 as Effects, Emitter, Exiting, types_exports$5 as Flow, Frames, Glow, HAPTIC_KINDS, Held, Hovered, types_exports$6 as I18n, types_exports$7 as Input, Layer, types_exports$8 as Lifecycle, LocalWrite, types_exports$9 as Model, NineSlice, Noise, Order, Outline, Parent, types_exports$10 as Platform, Pointer, PointerOver, Pressable, Pressed, types_exports$11 as Renderer, SaveUnreadableError, types_exports$12 as Scenes, Shape, Sprite, Swipeable, Tappable, Text, types_exports$13 as TextTypes, types_exports$14 as Time, Touchable, Traceable, Traced, Transform, Tree, types_exports$15 as Ui, types_exports$16 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, defineAnimation, defineBundles, defineComponent, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flowPlugin, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, modelPlugin, music, mut, parallel, platformPlugin, play, popup, projection, rendererPlugin, resolve, resource, scenesPlugin, schedule, screen, sequence, set, sfx, slot, spawn, spawned, sprite, stagger, system, tag, textPlugin, timePlugin, to, tr, tween, type, uiPlugin, use, wait, worldPlugin };
|
|
@@ -23490,13 +23490,24 @@ function setAwake(ctx, provider, on) {
|
|
|
23490
23490
|
//#endregion
|
|
23491
23491
|
//#region src/plugins/platform/api.ts
|
|
23492
23492
|
/**
|
|
23493
|
-
* @file platform plugin — API factory
|
|
23494
|
-
* first that takes it wins: the Escape button of the top popup, the intent `back` of the
|
|
23495
|
-
* node, the provider leaving the app.
|
|
23493
|
+
* @file platform plugin — API factory, the Back chain and the exit. One press runs three steps and
|
|
23494
|
+
* the first that takes it wins: the Escape button of the top popup, the intent `back` of the
|
|
23495
|
+
* resting node, the provider leaving the app. `exit()` is that last step alone.
|
|
23496
23496
|
*/
|
|
23497
23497
|
/** The intent a resting node lists to take the Back press itself. */
|
|
23498
23498
|
const BACK_INTENT = "back";
|
|
23499
23499
|
/**
|
|
23500
|
+
* Leaves the app through the provider, guarded like every provider call. Without a provider it
|
|
23501
|
+
* does nothing. The last step of the Back chain and `exit()` both go through here.
|
|
23502
|
+
*
|
|
23503
|
+
* @param ctx - Kernel context of the platform plugin.
|
|
23504
|
+
*/
|
|
23505
|
+
function leave(ctx) {
|
|
23506
|
+
const provider = ctx.config.provider;
|
|
23507
|
+
if (provider === void 0) return;
|
|
23508
|
+
safely(ctx.log, "exit", () => provider.exit());
|
|
23509
|
+
}
|
|
23510
|
+
/**
|
|
23500
23511
|
* Runs the Back chain once. `back()` and the provider's `onBack` both go through here, so a test
|
|
23501
23512
|
* and a real press end the same way. Escape is what ui answers with the `escape` button of its
|
|
23502
23513
|
* top root; it also ends the editing of a text field. While the graph moves between nodes the gate
|
|
@@ -23507,22 +23518,24 @@ const BACK_INTENT = "back";
|
|
|
23507
23518
|
* @returns What took the press, `"none"` without a provider.
|
|
23508
23519
|
*/
|
|
23509
23520
|
function runBack(ctx) {
|
|
23510
|
-
|
|
23511
|
-
if (provider === void 0) return "none";
|
|
23521
|
+
if (ctx.config.provider === void 0) return "none";
|
|
23512
23522
|
if (ctx.require(inputPlugin).pressKey("Escape")) return "popup";
|
|
23513
23523
|
const gate = ctx.require(flowPlugin).gate;
|
|
23514
23524
|
if (gate.answer({ intent: BACK_INTENT }) || !gate.state().open) return "intent";
|
|
23515
|
-
|
|
23525
|
+
leave(ctx);
|
|
23516
23526
|
return "exit";
|
|
23517
23527
|
}
|
|
23518
23528
|
/**
|
|
23519
|
-
* Creates the platform API: the Back chain on demand.
|
|
23529
|
+
* Creates the platform API: the Back chain and the exit on demand.
|
|
23520
23530
|
*
|
|
23521
23531
|
* @param ctx - Kernel context of the platform plugin.
|
|
23522
23532
|
* @returns The plugin API.
|
|
23523
23533
|
*/
|
|
23524
23534
|
function createPlatformApi(ctx) {
|
|
23525
|
-
return {
|
|
23535
|
+
return {
|
|
23536
|
+
back: () => runBack(ctx),
|
|
23537
|
+
exit: () => leave(ctx)
|
|
23538
|
+
};
|
|
23526
23539
|
}
|
|
23527
23540
|
//#endregion
|
|
23528
23541
|
//#region src/plugins/platform/state.ts
|
|
@@ -34254,7 +34267,7 @@ function defineMotion(spec) {
|
|
|
34254
34267
|
* |---|---|
|
|
34255
34268
|
* | `@moku-labs/game/app` | `defineGameApp`, the game as one data object with `headless()` and `screen()`; `startMoment`; the types of `index.ts` and `config.ts` (`GameConfig`) |
|
|
34256
34269
|
* | `@moku-labs/game/app/page` | `startPage`, the page the generated `.moku/main.ts` calls: `?player=` scenarios, the system shell, the dev agents |
|
|
34257
|
-
* | `@moku-labs/game/app/system` | the system shell over the optional peer `@moku-labs/system`: `
|
|
34270
|
+
* | `@moku-labs/game/app/system` | the system shell over the optional peer `@moku-labs/system`: `systemShellOf`, `fromSystem`, `storeSave`, `createSystemApp` |
|
|
34258
34271
|
* | `@moku-labs/game/cli` | `runCli` of the bin `moku-game` and `preparePage` for the editor, node and bun only |
|
|
34259
34272
|
* | `@moku-labs/game/testing` | headless play, repro runs, isolated feature tests (`isolate`, `stub`), the in-memory save, the fake clock |
|
|
34260
34273
|
* | `@moku-labs/game/visual` | the visual tests, node and bun only |
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Dt as AnyFlow, Ht as ClockSource, Nt as NodeTable, Wt as FakeClock, Xt as Json, ht as FeaturePlugin } from "./types-ZQLYXo5X.mjs";
|
|
2
|
-
import { t as createApp } from "./index-
|
|
2
|
+
import { t as createApp } from "./index-8TiJQjQA.mjs";
|
|
3
3
|
import { n as saveOf, t as memory } from "./memory-DwDhfFWK.mjs";
|
|
4
4
|
import { a as createHeadless, i as ReproResult, n as HeadlessGame, o as runRepro, r as Repro, s as stepFrames, t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
|
|
5
5
|
import { AnyPluginInstance } from "@moku-labs/core";
|
package/dist/testing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vt as exit, Wt as type, t as createApp } from "./src-
|
|
1
|
+
import { Vt as exit, Wt as type, t as createApp } from "./src-BSbtHZWk.mjs";
|
|
2
2
|
import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
|
|
4
4
|
import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BsNdJs9W.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Dt as AnyFlow, Ht as ClockSource, Jt as Config, Wt as FakeClock, Xt as Json, a as Config$3, g as Config$2, ht as FeaturePlugin, n as AssetsIo, pt as Config$1, tn as PlayerStateProvider, u as Manifest, v as PixiModule } from "./types-ZQLYXo5X.mjs";
|
|
2
2
|
import { o as AudioContextLike, s as Config$4 } from "./types-BM4shh8K.mjs";
|
|
3
|
-
import { ht as audioPlugin, i as screen, it as platformPlugin, ot as PlatformProvider, pt as effectsPlugin, t as createApp } from "./index-
|
|
3
|
+
import { ht as audioPlugin, i as screen, it as platformPlugin, ot as PlatformProvider, pt as effectsPlugin, t as createApp } from "./index-8TiJQjQA.mjs";
|
|
4
4
|
import { t as memory } from "./memory-DwDhfFWK.mjs";
|
|
5
5
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
6
6
|
|
|
@@ -440,12 +440,14 @@ type PageAgent<App = ScreenAppOfGame<AnyGameApp>> = (page: {
|
|
|
440
440
|
modules: readonly object[];
|
|
441
441
|
}) => void | Promise<void>;
|
|
442
442
|
/**
|
|
443
|
-
* Builds the system shell from the resolved config:
|
|
444
|
-
* `@moku-labs/game/app/system
|
|
443
|
+
* Builds the system shell from the resolved config: what `systemShellOf` of
|
|
444
|
+
* `@moku-labs/game/app/system` returns over the loaders of the page. The page reaches the shell
|
|
445
|
+
* only through this.
|
|
445
446
|
*
|
|
446
447
|
* @example
|
|
447
448
|
* ```ts
|
|
448
|
-
*
|
|
449
|
+
* const factory: SystemShellFactory = systemShellOf({ system: () => import("@moku-labs/system"), back: () => import("@moku-labs/system/back") });
|
|
450
|
+
* await startPage(game, config, { system: factory }); // the page builds the shell of config.system: ["back"]
|
|
449
451
|
* ```
|
|
450
452
|
*/
|
|
451
453
|
type SystemShellFactory = (config: ResolvedGameConfig, report: (problem: string) => void) => Promise<SystemShell>;
|
|
@@ -454,7 +456,8 @@ type SystemShellFactory = (config: ResolvedGameConfig, report: (problem: string)
|
|
|
454
456
|
*
|
|
455
457
|
* @example
|
|
456
458
|
* ```ts
|
|
457
|
-
* const
|
|
459
|
+
* const system = systemShellOf({ system: () => import("@moku-labs/system"), haptics: () => import("@moku-labs/system/haptics") });
|
|
460
|
+
* const options: PageOptions = { scenarios: { ready }, system, agents: [agent0], devModules: [devModule0] };
|
|
458
461
|
* ```
|
|
459
462
|
*/
|
|
460
463
|
type PageOptions = {
|
|
@@ -477,13 +480,52 @@ type StartedPage<Game extends AnyGameApp> = {
|
|
|
477
480
|
/** The screen app, started. */app: ScreenAppOfGame<Game>; /** The `@moku-labs/system` app, or `undefined` without a shell. Typed `unknown`: see `SystemShell.handle`. */
|
|
478
481
|
system: unknown;
|
|
479
482
|
};
|
|
483
|
+
/**
|
|
484
|
+
* The modules of `@moku-labs/system` the page loads, one loader per name of `config.ts`: the
|
|
485
|
+
* package itself always, and the entry of each plugin the game names, the store for a store save.
|
|
486
|
+
* The generated `main.ts` writes only the loaders of the names, so the page bundles only those
|
|
487
|
+
* plugins and never meets the native package of another. Typed `unknown`: a system type here would
|
|
488
|
+
* land in the `.d.mts` of every game and break the typecheck of a web-only one.
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```ts
|
|
492
|
+
* // A page of its own for a game whose config.ts names haptics, with a memory save.
|
|
493
|
+
* const modules: SystemModules = {
|
|
494
|
+
* system: () => import("@moku-labs/system"),
|
|
495
|
+
* haptics: () => import("@moku-labs/system/haptics")
|
|
496
|
+
* };
|
|
497
|
+
* await startPage(game, config, { system: systemShellOf(modules) }); // the bundle holds no store plugin
|
|
498
|
+
* ```
|
|
499
|
+
*/
|
|
500
|
+
type SystemModules = {
|
|
501
|
+
/** `@moku-labs/system` itself, for its `createApp`. Always there. */system: () => Promise<{
|
|
502
|
+
createApp: unknown;
|
|
503
|
+
}>; /** `@moku-labs/system/lifecycle`, when the game names `lifecycle`. */
|
|
504
|
+
lifecycle?: () => Promise<{
|
|
505
|
+
lifecyclePlugin: unknown;
|
|
506
|
+
}>; /** `@moku-labs/system/back`, when the game names `back`. */
|
|
507
|
+
back?: () => Promise<{
|
|
508
|
+
backPlugin: unknown;
|
|
509
|
+
}>; /** `@moku-labs/system/haptics`, when the game names `haptics`. */
|
|
510
|
+
haptics?: () => Promise<{
|
|
511
|
+
hapticsPlugin: unknown;
|
|
512
|
+
}>; /** `@moku-labs/system/keep-awake`, when the game names `keepAwake`. */
|
|
513
|
+
keepAwake?: () => Promise<{
|
|
514
|
+
keepAwakePlugin: unknown;
|
|
515
|
+
}>; /** `@moku-labs/system/store`, when the game names `store` or its save is `"store"`. */
|
|
516
|
+
store?: () => Promise<{
|
|
517
|
+
storePlugin: unknown;
|
|
518
|
+
}>;
|
|
519
|
+
};
|
|
480
520
|
/**
|
|
481
521
|
* The system shell: the `@moku-labs/system` app the config names, and what the engine takes from
|
|
482
|
-
* it. `
|
|
522
|
+
* it. The factory of `systemShellOf` builds it; the page starts it before the game and stops it
|
|
523
|
+
* after.
|
|
483
524
|
*
|
|
484
525
|
* @example
|
|
485
526
|
* ```ts
|
|
486
|
-
* const
|
|
527
|
+
* const build = systemShellOf({ system: () => import("@moku-labs/system"), store: () => import("@moku-labs/system/store") });
|
|
528
|
+
* const shell = await build(resolveConfig({ page: { title: "T" }, save: "store" }), problem => problems.push(problem));
|
|
487
529
|
* game.screen({ platform: shell.platform, provider: shell.save });
|
|
488
530
|
* ```
|
|
489
531
|
*/
|
|
@@ -541,4 +583,4 @@ type SystemShell = {
|
|
|
541
583
|
stop(): Promise<void>;
|
|
542
584
|
};
|
|
543
585
|
//#endregion
|
|
544
|
-
export {
|
|
586
|
+
export { SystemShellFactory as _, GameHandle as a, MemoryProvider as c, SaveKind as d, Scenario as f, SystemName as g, SystemModules as h, GameDefinition as i, PageAgent as l, StartedPage as m, GameApp as n, GamePluginConfigs as o, ScreenSeams as p, GameConfig as r, HeadlessSeams as s, AnyGameApp as t, PageOptions as u };
|
package/llms.txt
CHANGED
|
@@ -9,7 +9,7 @@ Facts: Bun only. ESM only. `"sideEffects": false`. `pixi.js` `^8.0.0` is a peer
|
|
|
9
9
|
- `@moku-labs/game`: everything a game imports.
|
|
10
10
|
- `@moku-labs/game/app`: `defineGameApp`, `startMoment` and the types of a game's `index.ts` and `config.ts`. No `node:` import, no system or native package. See "The game shell".
|
|
11
11
|
- `@moku-labs/game/app/page` (the browser): `startPage`, the page the generated `.moku/main.ts` calls.
|
|
12
|
-
- `@moku-labs/game/app/system` (the browser, the native shell): `
|
|
12
|
+
- `@moku-labs/game/app/system` (the browser, the native shell): `systemShellOf`, `fromSystem`, `storeSave`, `createSystemApp`, the type `SystemModules`, over the optional peer `@moku-labs/system`. The one entry that names it, in types only: the page hands it the loaders.
|
|
13
13
|
- `@moku-labs/game/cli` (node and bun only): `runCli`, the bin `moku-game`, and `preparePage`, the editor's dev page.
|
|
14
14
|
- `@moku-labs/game/testing`: headless play, repro runs, isolated feature tests (`isolate`, `stub`), fake clock, in-memory save provider. No `node:` import.
|
|
15
15
|
- `@moku-labs/game/visual` (node and bun only): the visual tests `defineVisualTest`, `runVisualTests`, `parseVisualArgv`.
|
|
@@ -300,7 +300,7 @@ The page. `moku-game dev` and `build` write a `main.ts` that calls `startPage(ga
|
|
|
300
300
|
- `?player=<name>` starts from the scenario `tests/scenarios/<name>.ts` on a fresh memory save, never on the stored one. An unknown name logs `[game] No scenario "<name>".` and starts from the starting player. A scenario is `Scenario<Player>`: `(now) => ({ player, session? })`, its default export.
|
|
301
301
|
- `?renderer=webgl` asks Pixi for WebGL.
|
|
302
302
|
- Save kinds: `"memory"` lives for the page only; `"local"` is `localStorage` under `<native.identifier>:save` or `moku-game:save`, and falls back to memory with a warning where storage is refused; `"store"` is the system store (idb on the web, the Tauri store native), needs the shell, rejects a load it cannot read instead of starting a new player.
|
|
303
|
-
- System: the generated `main.ts` imports `
|
|
303
|
+
- System: the generated `main.ts` imports `systemShellOf` of `@moku-labs/game/app/system` only when `system` is not empty or `save` is `"store"`, so a web-only page bundles no system code. It passes `system: systemShellOf({ system: () => import("@moku-labs/system"), haptics: () => import("@moku-labs/system/haptics") })`: one loader per named plugin, in the order `lifecycle`, `back`, `haptics`, `keepAwake` (entry `keep-awake`), `store` (when named or `save` is `"store"`). The engine holds no `import()` of the package, so the page bundles only the named plugins: a game with `system: ["haptics"]` and a memory save builds without `@tauri-apps/plugin-store`. A loader that rejects: `[game] config.system needs @moku-labs/system.` with `bun add @moku-labs/system@^0.3.1`. A named plugin without a loader: `[game] config.system names "<name>", but main.ts has no loader for it.`
|
|
304
304
|
|
|
305
305
|
```ts
|
|
306
306
|
// .moku/main.ts of the engine's mini game, written by moku-game dev
|
|
@@ -571,6 +571,7 @@ Cosmetic rendering extras as data, drawn by `effectsPlugin`: `plugins: [...scree
|
|
|
571
571
|
The phone as a provider, last in the array: `plugins: [...screen, effectsPlugin, audioPlugin, platformPlugin]` with `pluginConfigs: { platform: { provider, keepAwake: true } }`. `game.screen()` composes it and takes the provider as its `platform` seam. A game imports no native package: the engine page builds the provider from the `system` list of `config.ts` through `@moku-labs/game/app/system`, and turns keep-awake on when the list names `keepAwake`. The full reference is `src/plugins/platform/README.md`.
|
|
572
572
|
- `PlatformProvider` has six members: `onPause(fn)`, `onResume(fn)`, `onBack(fn)` (each returns its remover), `haptic(kind)`, `keepAwake(on)`, `exit()`. Pause and resume push and pop the `"background"` reason of `lifecycle`. A provider method that throws is logged, never thrown into the frame.
|
|
573
573
|
- Back chain, `app.platform.back(): BackResult`. First an Escape press: a popup with an `escape` button closes, `"popup"`. Then `flow.gate.answer({ intent: "back" })` when the resting node lists `back`, `"intent"`. Then `provider.exit()`, `"exit"`. Without a provider `"none"`.
|
|
574
|
+
- `app.platform.exit()`: the last step of the Back chain alone, `provider.exit()`, for a Leave button: `ctx.require(flowPlugin).fx.handle("exit", () => ctx.require(platformPlugin).exit())`. A throw is logged; without a provider it does nothing.
|
|
574
575
|
- Haptics: `await fx(haptic("success"))` in a node, or `haptic("light")` as a timeline step. The kinds are `HAPTIC_KINDS`: `light`, `medium`, `heavy`, `selection`, `success`, `warning`, `error`. A fast walk is silent.
|
|
575
576
|
- Config: `provider: undefined`, which leaves the plugin inert: a `haptic` effect resolves at once, so the same node runs on the web and headless. `keepAwake: false`.
|
|
576
577
|
- No events. Depends on `lifecycle`, `flow`, `input`.
|