@moku-labs/game 0.7.1 → 0.8.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/README.md +5 -4
- package/dist/assets.d.mts +1 -1
- package/dist/{capture-fpd83Mi5.mjs → capture-BX5Gfoty.mjs} +1 -384
- package/dist/{commands-mzE9PX0H.d.mts → commands-C1kIfOG5.d.mts} +6 -4
- package/dist/control.d.mts +4 -3
- package/dist/control.mjs +2 -2
- package/dist/{define-BbgXv4cy.d.mts → define-BPpZcpxW.d.mts} +4 -3
- package/dist/headless-CvamCUcR.mjs +186 -0
- package/dist/headless-q98SwADR.d.mts +181 -0
- package/dist/index.d.mts +23 -22
- package/dist/index.mjs +15 -6
- package/dist/{input-CK4nxBO1.mjs → input-z_35Jwfn.mjs} +2 -2
- package/dist/inspect.d.mts +8 -6
- 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/project.d.mts +28 -28
- package/dist/project.mjs +7 -7
- package/dist/registry-DlpRCibU.mjs +384 -0
- package/dist/{run-Bcyg32M5.mjs → run-CUPSFM85.mjs} +4 -187
- package/dist/{runtime-HTlmRb81.d.mts → runtime-CvDZZg1S.d.mts} +1 -1
- package/dist/{sources-DVWJ8nfr.mjs → sources-BBUd15vQ.mjs} +1 -1
- package/dist/testing.d.mts +3 -328
- package/dist/testing.mjs +2 -2142
- package/dist/{types-BMEn0tSC.d.mts → types-BWzCSRM2.d.mts} +12 -2974
- package/dist/{types-CYYKjvLn.d.mts → types-CDSKa0vl.d.mts} +5 -182
- package/dist/{types-ClF8say0.d.mts → types-DF5kkW-C.d.mts} +5 -4
- package/dist/{types-BaUUcIaN.d.mts → types-DgdMLZnV.d.mts} +8 -7
- package/dist/{types-CXyipKhE.d.mts → types-DlgsfOmW.d.mts} +10 -9
- package/dist/types-ERb2Y9U5.d.mts +2967 -0
- package/dist/visual.d.mts +331 -0
- package/dist/visual.mjs +2142 -0
- package/llms.txt +6 -5
- package/package.json +7 -8
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { A as Api, C as RouteStep, R as Json, X as RngState, b as FlowState, k as Answer, t as Api$1, x as JournalEntry } from "./types-ERb2Y9U5.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/flow/headless.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The part of an app the headless helpers use. Structural on purpose: any app created with the
|
|
6
|
+
* default plugins fits.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const app: HeadlessApp = createApp({ pluginConfigs: { flow: { mainFlow } } });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
type HeadlessApp = {
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
time: Api;
|
|
17
|
+
flow: Api$1;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A game played without a screen: answers go through the gate, effects resolve instantly.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // A test of the dice game: two rolls, no screen, no waiting.
|
|
25
|
+
* const game = await createHeadless(app);
|
|
26
|
+
* const state = await game.walk([{ at: "home", intent: "roll" }, { at: "home", intent: "roll" }]);
|
|
27
|
+
*
|
|
28
|
+
* state.path; // "home"
|
|
29
|
+
* await game.stop();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
type HeadlessGame = {
|
|
33
|
+
/**
|
|
34
|
+
* Walks a route through the running loop.
|
|
35
|
+
*
|
|
36
|
+
* @param route - The player's answers and substituted sub-flow results, in order.
|
|
37
|
+
* @returns The state the walk ended in.
|
|
38
|
+
* @throws {Error} When a step is never reached, or the loop failed fatally.
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* // Open the board and tap the generator twice. Every node's logic runs for real.
|
|
42
|
+
* const tap = { at: "board/awaitIntent", intent: "tap", payload: { generatorId: "sawmill" } };
|
|
43
|
+
* const state = await game.walk([{ at: "home", intent: "play" }, tap, tap]);
|
|
44
|
+
*
|
|
45
|
+
* state.path; // "board/awaitIntent"
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
walk(route: readonly RouteStep[]): Promise<FlowState>;
|
|
49
|
+
/**
|
|
50
|
+
* Gives one answer to the gate, the way a tap does.
|
|
51
|
+
*
|
|
52
|
+
* @param answer - Intent and optional payload.
|
|
53
|
+
* @returns Whether the gate took it.
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // One tap without a route. The test then waits for the loop by itself.
|
|
57
|
+
* game.answer({ intent: "play" }); // true: "home" rests and lists "play"
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
answer(answer: Answer): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Reads where the graph stands.
|
|
63
|
+
*
|
|
64
|
+
* @returns Whether it runs, the path, the stack, what it waits for and the mode.
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* // Right after createHeadless: the graph rests at its first rest node.
|
|
68
|
+
* game.state().path; // "home"
|
|
69
|
+
* game.state().pending; // { gate: ["play"] }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
state(): FlowState;
|
|
73
|
+
/**
|
|
74
|
+
* Reads the edges taken since the last checkpoint.
|
|
75
|
+
*
|
|
76
|
+
* @returns A copy of the journal.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* // After a merge onto an empty cell: the last edge says why the move was refused.
|
|
80
|
+
* const last = game.history().at(-1);
|
|
81
|
+
* // last?.path: "board/merge", last?.outcome: "rejected", last?.payload: { reason: "empty" }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
history(): readonly JournalEntry[];
|
|
85
|
+
/**
|
|
86
|
+
* Stops the app, then re-throws a fatal error of the loop.
|
|
87
|
+
*
|
|
88
|
+
* @throws {Error} When the loop failed fatally.
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* // The last line of a headless test. A fatal error of the loop fails the test here.
|
|
92
|
+
* await game.stop();
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
stop(): Promise<void>;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* A reproducible run: a starting state, an optional checkpoint and the route played from it.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const repro: Repro = { player: { coins: 0 }, checkpoint: "home", route: [{ at: "home", intent: "play" }] };
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
type Repro = {
|
|
106
|
+
player: Json;
|
|
107
|
+
session?: Json;
|
|
108
|
+
rng?: RngState;
|
|
109
|
+
checkpoint?: string;
|
|
110
|
+
route: RouteStep[];
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* What a repro run ends with: the path where the loop rests and the committed state.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const result: ReproResult = { path: ["home"], player: { coins: 3 }, session: { visits: 1 } };
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
type ReproResult = {
|
|
121
|
+
path: string[];
|
|
122
|
+
player: Json;
|
|
123
|
+
session: Json;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Starts an app headless: sets flow mode `"fast"`, awaits `app.start()`, starts `flow.run()`
|
|
127
|
+
* unless the app's own `onStart` already did, and waits until the loop rests for the first time.
|
|
128
|
+
* `game.state().path` therefore names the first rest node of the graph as soon as the call
|
|
129
|
+
* resolves. A fatal error of the loop rejects this call, and a later one is re-thrown by `walk`
|
|
130
|
+
* and by `stop`, so a headless test never loses it.
|
|
131
|
+
*
|
|
132
|
+
* @param app - An app that is not started yet.
|
|
133
|
+
* @returns The game: walk it, answer it, read it, stop it.
|
|
134
|
+
* @throws {Error} When the loop failed fatally before it reached its first rest node.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* // A test starts the merge game without a screen. The call resolves at the first rest node.
|
|
138
|
+
* const game = await createHeadless(app);
|
|
139
|
+
*
|
|
140
|
+
* game.state().path; // "home": the transit node "boot" was played out
|
|
141
|
+
* game.state().mode; // "fast"
|
|
142
|
+
* await game.stop();
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
declare function createHeadless(app: HeadlessApp): Promise<HeadlessGame>;
|
|
146
|
+
/**
|
|
147
|
+
* Plays a repro: starts the app headless, restores the bookmark built from its state and
|
|
148
|
+
* checkpoint, then walks its route. The app keeps running, so the caller can read more than the
|
|
149
|
+
* result and stops it itself.
|
|
150
|
+
*
|
|
151
|
+
* @param app - An app that is not started yet.
|
|
152
|
+
* @param repro - Starting state, optional checkpoint and the route.
|
|
153
|
+
* @returns The path the run ended at, and the committed state.
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* // A bug report on the dice game: "reset keeps my coins". Replay it from the "home" checkpoint.
|
|
157
|
+
* const reset = { at: "home", intent: "reset" };
|
|
158
|
+
* const result = await runRepro(app, { player: { coins: 7 }, checkpoint: "home", route: [reset] });
|
|
159
|
+
*
|
|
160
|
+
* result.player; // { coins: 0 }; result.path is ["home"]
|
|
161
|
+
* await app.stop(); // the app keeps running after the run
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare function runRepro(app: HeadlessApp, repro: Repro): Promise<ReproResult>;
|
|
165
|
+
/**
|
|
166
|
+
* Steps the frame loop by hand: `count` calls of `app.time.step(deltaMs)`. A headless game has no
|
|
167
|
+
* frame source, so this is the only thing that moves the frame phases.
|
|
168
|
+
*
|
|
169
|
+
* @param app - A started app.
|
|
170
|
+
* @param count - Number of frames.
|
|
171
|
+
* @param deltaMs - Milliseconds per frame.
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* // A headless game has no frame source: the test moves the six frame phases by hand.
|
|
175
|
+
* stepFrames(app, 2, 16);
|
|
176
|
+
* app.time.snapshot(); // frame: 2, delta: 16, elapsed: 32
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
declare function stepFrames(app: HeadlessApp, count: number, deltaMs: number): void;
|
|
180
|
+
//#endregion
|
|
181
|
+
export { createHeadless as a, ReproResult as i, HeadlessGame as n, runRepro as o, Repro as r, stepFrames as s, HeadlessApp as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { $ as
|
|
3
|
-
import { A as
|
|
4
|
-
import {
|
|
1
|
+
import { $ as Events, A as Api$3, B as State$4, D as GuideOptions, E as Descriptor, H as Patch, I as Config$4, J as StoreApi, K as SaveUnreadableError, M as State$5, O as Hint, P as types_d_exports$14, Q as Config$3, R as Json, V as types_d_exports$9, Y as RngApi, Z as Api$2, a as FeaturePlugin, c as State$2, ct as Config$6, d as defineFlow, et as PauseReason, f as exit, g as FeatureDescription, h as type, i as EmitterIdOf, it as Config$1, j as Config$5, l as TextStylesOf, lt as Events$1, m as to, n as BundlesOf, nt as types_d_exports$8, o as GameTypes, ot as State$1, p as slot, r as Config$2, rt as Api, st as types_d_exports$3, t as Api$1, tt as State$3, u as types_d_exports$5, ut as Require, v as DefineNode, w as SceneIdOf, z as Root } from "./types-ERb2Y9U5.mjs";
|
|
2
|
+
import { $ as Ease, A as Config$9, B as ComponentValue, G as Narrowed, J as ResourceType, L as ComponentHandle, M as State$8, N as types_d_exports$16, O as ViewportSize, Q as DescriptionNode, S as types_d_exports$11, W as Mut, X as TagType, Y as SystemDefinition, a as DefineBundles, at as ProjectionMotion, b as State$7, c as LoadReason, d as Tier, h as Config$8, i as Config$7, it as NumericFields, k as Api$6, m as Api$5, n as BundleMap, ot as ProjectionSpec, p as types_d_exports$1, q as QueryTerm, r as BundleSpec, s as LoadBundles, t as Api$4, u as State$6, z as ComponentType } from "./types-BWzCSRM2.mjs";
|
|
3
|
+
import { $ as SpriteValue, A as TextStyleInput, B as types_d_exports$6, C as Config$12, D as TextApi, E as State$11, F as Config$10, G as Display, H as InputApi, I as I18nApi, J as Parent, K as NineSlice, L as Message, M as TextValue, N as types_d_exports$13, O as TextBind, P as Argument, Q as SpriteOptions, R as State$9, S as BindOptions, T as Point, U as State$10, V as Config$11, W as types_d_exports$7, X as ShapeValue, Y as Shape, Z as Sprite, _ as Style, b as defineComponent, d as popup, et as Transform, f as defineTokens, g as ResolvedStyle, h as IsFlags, j as TextStyles, k as TextFormat, l as Box, nt as sprite, p as IntrinsicElementsFor, q as NineSliceValue, s as PopupComponent, tt as TransformValue, u as LocalWrite, w as CountdownValue, x as BindField, y as WhenFlags, z as TypedTr } from "./types-DgdMLZnV.mjs";
|
|
4
|
+
import { A as HAPTIC_KINDS, B as sfx, C as MotionKeyframe, D as HapticKind, E as types_d_exports, F as mark, G as use, H as spawned, I as parallel, K as wait, L as play, M as external, N as frames, O as SfxDescriptor, P as haptic, R as sequence, S as FramesValue, T as Target, U as stagger, V as spawn, W as tween, _ as State$15, b as AnimApi, c as AnySceneProjection, d as SceneDefinition, f as SceneSpec, g as Config$15, h as types_d_exports$12, i as MusicOptions, j as defineAnimation, k as Step, l as DefineScene, m as State$14, n as Config$14, o as State$13, p as ScenesApi, r as MusicDescriptor, s as types_d_exports$2, t as AudioApi, u as LayerMap, v as UiApi, w as State$12, x as Config$13, y as types_d_exports$15, z as set } from "./types-DlgsfOmW.mjs";
|
|
5
|
+
import { _ as NoiseValue, a as types_d_exports$4, c as EmitterValue, d as ColorMatrixValue, f as DisplacementValue, g as GlowValue, h as FilterValueOf, i as State$16, l as AlphaValue, m as FilterSpec, n as EffectsApi, o as EmitterConfig, p as FilterComponent, s as EmitterDefinition, t as Config$16, u as BlurValue, v as OutlineValue, y as UniformDeclaration } from "./types-DF5kkW-C.mjs";
|
|
5
6
|
import { Log } from "@moku-labs/common/browser";
|
|
6
7
|
import { PluginCtx } from "@moku-labs/core";
|
|
7
8
|
|
|
@@ -177,7 +178,7 @@ declare const animPlugin: import("@moku-labs/core").PluginInstance<"anim", Confi
|
|
|
177
178
|
* app.assets.usage().textureMb; // 0.188, the boot tier
|
|
178
179
|
* ```
|
|
179
180
|
*/
|
|
180
|
-
declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", Config$
|
|
181
|
+
declare const assetsPlugin: import("@moku-labs/core").PluginInstance<"assets", Config$7, State$6, Api$4, {
|
|
181
182
|
"assets:bundle-loaded": {
|
|
182
183
|
bundle: string;
|
|
183
184
|
tier: Tier;
|
|
@@ -227,7 +228,7 @@ declare const audioPlugin: import("@moku-labs/core").PluginInstance<"audio", Con
|
|
|
227
228
|
* });
|
|
228
229
|
* ```
|
|
229
230
|
*/
|
|
230
|
-
declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Config$
|
|
231
|
+
declare const clockPlugin: import("@moku-labs/core").PluginInstance<"clock", Config$1, State$1, Api, {}> & Record<never, never>;
|
|
231
232
|
//#endregion
|
|
232
233
|
//#region src/plugins/effects/index.d.ts
|
|
233
234
|
/**
|
|
@@ -261,7 +262,7 @@ declare const effectsPlugin: import("@moku-labs/core").PluginInstance<"effects",
|
|
|
261
262
|
* });
|
|
262
263
|
* ```
|
|
263
264
|
*/
|
|
264
|
-
declare const flowPlugin: import("@moku-labs/core").PluginInstance<"flow", Config$
|
|
265
|
+
declare const flowPlugin: import("@moku-labs/core").PluginInstance<"flow", Config$2, State$2, Api$1, {
|
|
265
266
|
"flow:edge": {
|
|
266
267
|
flow: string;
|
|
267
268
|
node: string;
|
|
@@ -342,7 +343,7 @@ declare const inputPlugin: import("@moku-labs/core").PluginInstance<"input", Con
|
|
|
342
343
|
* });
|
|
343
344
|
* ```
|
|
344
345
|
*/
|
|
345
|
-
declare const lifecyclePlugin: import("@moku-labs/core").PluginInstance<"lifecycle", Config$
|
|
346
|
+
declare const lifecyclePlugin: import("@moku-labs/core").PluginInstance<"lifecycle", Config$3, State$3, Api$2, {
|
|
346
347
|
"lifecycle:changed": {
|
|
347
348
|
reason: PauseReason;
|
|
348
349
|
action: "push" | "pop";
|
|
@@ -367,7 +368,7 @@ declare const lifecyclePlugin: import("@moku-labs/core").PluginInstance<"lifecyc
|
|
|
367
368
|
* });
|
|
368
369
|
* ```
|
|
369
370
|
*/
|
|
370
|
-
declare const modelPlugin: import("@moku-labs/core").PluginInstance<"model", Config$
|
|
371
|
+
declare const modelPlugin: import("@moku-labs/core").PluginInstance<"model", Config$4, State$4, {
|
|
371
372
|
store: StoreApi;
|
|
372
373
|
rng: RngApi;
|
|
373
374
|
}, {
|
|
@@ -529,7 +530,7 @@ declare const platformPlugin: import("@moku-labs/core").PluginInstance<"platform
|
|
|
529
530
|
* app.renderer.host.kind(); // "webgpu" in Chrome, "webgl" on an older device
|
|
530
531
|
* ```
|
|
531
532
|
*/
|
|
532
|
-
declare const rendererPlugin: import("@moku-labs/core").PluginInstance<"renderer", Config$
|
|
533
|
+
declare const rendererPlugin: import("@moku-labs/core").PluginInstance<"renderer", Config$8, State$7, Api$5, {
|
|
533
534
|
"renderer:device-lost": {
|
|
534
535
|
kind: "webgpu" | "webgl";
|
|
535
536
|
reason: string;
|
|
@@ -592,7 +593,7 @@ declare const textPlugin: import("@moku-labs/core").PluginInstance<"text", Confi
|
|
|
592
593
|
* });
|
|
593
594
|
* ```
|
|
594
595
|
*/
|
|
595
|
-
declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Config$
|
|
596
|
+
declare const timePlugin: import("@moku-labs/core").PluginInstance<"time", Config$5, State$5, Api$3, {}> & Record<never, never>;
|
|
596
597
|
//#endregion
|
|
597
598
|
//#region src/plugins/ui/index.d.ts
|
|
598
599
|
/**
|
|
@@ -625,7 +626,7 @@ declare const uiPlugin: import("@moku-labs/core").PluginInstance<"ui", Config$15
|
|
|
625
626
|
* app.world.projection.entityOf("board.items", "i7"); // 1048576
|
|
626
627
|
* ```
|
|
627
628
|
*/
|
|
628
|
-
declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Config$
|
|
629
|
+
declare const worldPlugin: import("@moku-labs/core").PluginInstance<"world", Config$9, State$8, Api$6, {
|
|
629
630
|
"world:reconciled": {
|
|
630
631
|
mode: "play" | "direct";
|
|
631
632
|
projections: number;
|
|
@@ -1356,7 +1357,7 @@ declare function defineEmitter(id: string, config: EmitterConfig): EmitterDefini
|
|
|
1356
1357
|
* });
|
|
1357
1358
|
* ```
|
|
1358
1359
|
*/
|
|
1359
|
-
declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$
|
|
1360
|
+
declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$6, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$5, State$5, Api$3, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$3, State$3, Api$2, {
|
|
1360
1361
|
"lifecycle:changed": {
|
|
1361
1362
|
reason: PauseReason;
|
|
1362
1363
|
action: "push" | "pop";
|
|
@@ -1364,7 +1365,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1364
1365
|
paused: boolean;
|
|
1365
1366
|
resumed: boolean;
|
|
1366
1367
|
};
|
|
1367
|
-
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"model", Config$
|
|
1368
|
+
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"model", Config$4, State$4, {
|
|
1368
1369
|
store: StoreApi;
|
|
1369
1370
|
rng: RngApi;
|
|
1370
1371
|
}, {
|
|
@@ -1372,7 +1373,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1372
1373
|
roots: readonly Root[];
|
|
1373
1374
|
cause: "edge" | "rollback" | "restore" | "load";
|
|
1374
1375
|
};
|
|
1375
|
-
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$
|
|
1376
|
+
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$1, State$1, Api, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$2, State$2, Api$1, {
|
|
1376
1377
|
"flow:edge": {
|
|
1377
1378
|
flow: string;
|
|
1378
1379
|
node: string;
|
|
@@ -1396,7 +1397,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1396
1397
|
rolledBackTo: string;
|
|
1397
1398
|
retry: boolean;
|
|
1398
1399
|
};
|
|
1399
|
-
}> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi>, import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>]>, import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi> | import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>> | undefined) => import("@moku-labs/core").App<Config$
|
|
1400
|
+
}> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi>, import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>]>, import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi> | import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>> | undefined) => import("@moku-labs/core").App<Config$6, Events$1, (import("@moku-labs/core").PluginInstance<"time", Config$5, State$5, Api$3, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"lifecycle", Config$3, State$3, Api$2, {
|
|
1400
1401
|
"lifecycle:changed": {
|
|
1401
1402
|
reason: PauseReason;
|
|
1402
1403
|
action: "push" | "pop";
|
|
@@ -1404,7 +1405,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1404
1405
|
paused: boolean;
|
|
1405
1406
|
resumed: boolean;
|
|
1406
1407
|
};
|
|
1407
|
-
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"model", Config$
|
|
1408
|
+
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"model", Config$4, State$4, {
|
|
1408
1409
|
store: StoreApi;
|
|
1409
1410
|
rng: RngApi;
|
|
1410
1411
|
}, {
|
|
@@ -1412,7 +1413,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1412
1413
|
roots: readonly Root[];
|
|
1413
1414
|
cause: "edge" | "rollback" | "restore" | "load";
|
|
1414
1415
|
};
|
|
1415
|
-
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$
|
|
1416
|
+
}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"clock", Config$1, State$1, Api, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"flow", Config$2, State$2, Api$1, {
|
|
1416
1417
|
"flow:edge": {
|
|
1417
1418
|
flow: string;
|
|
1418
1419
|
node: string;
|
|
@@ -1449,7 +1450,7 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
1449
1450
|
* });
|
|
1450
1451
|
* ```
|
|
1451
1452
|
*/
|
|
1452
|
-
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$
|
|
1453
|
+
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$6, Events$1, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common/browser").LogConfig, import("@moku-labs/common/browser").LogState, import("@moku-labs/common/browser").LogApi>, import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common/browser").EnvConfig, import("@moku-labs/common/browser").EnvState, import("@moku-labs/common/browser").EnvApi>]>>;
|
|
1453
1454
|
/**
|
|
1454
1455
|
* Binds the authoring helpers to the types of one game: "createApp for a game". Each plugin binds
|
|
1455
1456
|
* its own helpers (`flowFor`, `projectionFor`, `componentsFor`, `bundlesFor`, `scenesFor`); this
|
|
@@ -1537,7 +1538,7 @@ declare function defineGame<Types extends GameTypes>(): {
|
|
|
1537
1538
|
* createApp({ plugins: [...screen, boardFeature], pluginConfigs: { renderer: { mount: "#game" } } });
|
|
1538
1539
|
* ```
|
|
1539
1540
|
*/
|
|
1540
|
-
declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world", Config$
|
|
1541
|
+
declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world", Config$9, State$8, Api$6, {
|
|
1541
1542
|
"world:reconciled": {
|
|
1542
1543
|
mode: "play" | "direct";
|
|
1543
1544
|
projections: number;
|
|
@@ -1549,12 +1550,12 @@ declare const screen: readonly [import("@moku-labs/core").PluginInstance<"world"
|
|
|
1549
1550
|
hintsRouted: number;
|
|
1550
1551
|
hintsDropped: number;
|
|
1551
1552
|
};
|
|
1552
|
-
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"renderer", Config$
|
|
1553
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"renderer", Config$8, State$7, Api$5, {
|
|
1553
1554
|
"renderer:device-lost": {
|
|
1554
1555
|
kind: "webgpu" | "webgl";
|
|
1555
1556
|
reason: string;
|
|
1556
1557
|
};
|
|
1557
|
-
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"input", Config$11, State$10, InputApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"assets", Config$
|
|
1558
|
+
}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"input", Config$11, State$10, InputApi, {}> & Record<never, never>, import("@moku-labs/core").PluginInstance<"assets", Config$7, State$6, Api$4, {
|
|
1558
1559
|
"assets:bundle-loaded": {
|
|
1559
1560
|
bundle: string;
|
|
1560
1561
|
tier: Tier;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
2
|
import { a as enableDraftPatches, i as dropDrafts, o as finishDrafts, r as deepFreeze, s as openDrafts, t as memory } from "./memory-CvgdnsQO.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { a as graphHash, c as pushEntry, i as framePath, n as describeGraph, o as slotNames, r as findNode, s as compact, t as collectFlows } from "./registry-DlpRCibU.mjs";
|
|
4
4
|
import { A as system, C as Exiting, D as component, E as Tree, O as mut, S as sprite, T as Order, _ as Parent, a as visualOf$1, 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, m as textFor, n as fitScaleOf, o as visualRectOf, p as readStyle, r as samePose, s as Countdown, t as CONTENT, u as builtInStyles, v as Shape, w as Layer, x as componentsFor, y as Sprite } from "./visual-DUvvPPCt.mjs";
|
|
5
|
+
import { i as servePaused, n as captureFrame, r as serveCaptures, t as cancelCaptures } from "./capture-BX5Gfoty.mjs";
|
|
5
6
|
import { n as isDev } from "./dev-wKLgOw7c.mjs";
|
|
6
7
|
import { i as isComponentDefinition, n as flatten, r as defineComponent } from "./flatten-BkXuscAV.mjs";
|
|
7
8
|
import { envPlugin, logPlugin } from "@moku-labs/common/browser";
|
|
@@ -31078,6 +31079,8 @@ function createGuideHandler(ctx) {
|
|
|
31078
31079
|
const DEFAULT_TEXT_STYLE = "body";
|
|
31079
31080
|
/** The glyph an icon is sized from: one line of the text style it sits in. */
|
|
31080
31081
|
const LINE_SAMPLE = "M";
|
|
31082
|
+
/** Below this a measured length counts as whole: the tolerance Yoga's own rounding uses. */
|
|
31083
|
+
const WHOLE_EPSILON = 1e-4;
|
|
31081
31084
|
/**
|
|
31082
31085
|
* Makes an icon square on the line height of the text next to it.
|
|
31083
31086
|
*
|
|
@@ -31174,16 +31177,21 @@ function shownOf(element, source) {
|
|
|
31174
31177
|
}
|
|
31175
31178
|
/**
|
|
31176
31179
|
* The size a text or an icon takes before Yoga clamps it: an icon is square on one line of its
|
|
31177
|
-
* text style, a bound text measures the string it shows, any other text its content.
|
|
31180
|
+
* text style, a bound text measures the string it shows, any other text its content. The size is
|
|
31181
|
+
* rounded up to whole units. Yoga rounds a node with a measure function outward but sizes its
|
|
31182
|
+
* parent from the unrounded length, so a fractional size would run into the parent's padding.
|
|
31178
31183
|
*
|
|
31179
31184
|
* @param element - The text or icon element.
|
|
31180
31185
|
* @param source - What it is measured through.
|
|
31181
|
-
* @returns The width and the height.
|
|
31186
|
+
* @returns The width and the height, in whole units.
|
|
31182
31187
|
*/
|
|
31183
31188
|
function naturalSize(element, source) {
|
|
31184
31189
|
const { content, style } = contentOf$1(element);
|
|
31185
|
-
|
|
31186
|
-
return
|
|
31190
|
+
const size = element.type === "icon" ? squareOf(source.measure(LINE_SAMPLE, style)) : source.measure(shownOf(element, source) ?? content, style);
|
|
31191
|
+
return {
|
|
31192
|
+
width: Math.ceil(size.width - WHOLE_EPSILON),
|
|
31193
|
+
height: Math.ceil(size.height - WHOLE_EPSILON)
|
|
31194
|
+
};
|
|
31187
31195
|
}
|
|
31188
31196
|
/**
|
|
31189
31197
|
* Clamps one axis of a measured size to what Yoga offered on that axis.
|
|
@@ -34230,7 +34238,8 @@ function defineMotion(spec) {
|
|
|
34230
34238
|
*
|
|
34231
34239
|
* | Subpath | What |
|
|
34232
34240
|
* |---|---|
|
|
34233
|
-
* | `@moku-labs/game/testing` | headless play, repro runs, the in-memory save, the fake clock
|
|
34241
|
+
* | `@moku-labs/game/testing` | headless play, repro runs, the in-memory save, the fake clock |
|
|
34242
|
+
* | `@moku-labs/game/visual` | the visual tests, node and bun only |
|
|
34234
34243
|
* | `@moku-labs/game/assets` | the build-time asset key scanner and the production packer (`packAssets`, `--pack <dir>`), node and bun only |
|
|
34235
34244
|
* | `@moku-labs/game/inspect` | the editor's read door: `read`, `watch`, `defineSource`, the `sources` catalogue |
|
|
34236
34245
|
* | `@moku-labs/game/control` | the editor's write door, dev builds only: `run`, `defineCommand`, the `commands` catalogue |
|
|
@@ -24,7 +24,7 @@ function checkId(kind, id) {
|
|
|
24
24
|
* ```ts
|
|
25
25
|
* // A game's .dev module: the orders on the board, re-read after every edge.
|
|
26
26
|
* export const orders = defineSource({
|
|
27
|
-
* id: "
|
|
27
|
+
* id: "mini.orders",
|
|
28
28
|
* title: "Orders",
|
|
29
29
|
* input: {},
|
|
30
30
|
* changes: "edge",
|
|
@@ -49,7 +49,7 @@ function defineSource(source) {
|
|
|
49
49
|
* ```ts
|
|
50
50
|
* // A game's .dev module: open the shop from anywhere, through the graph.
|
|
51
51
|
* export const openShop = defineCommand({
|
|
52
|
-
* id: "
|
|
52
|
+
* id: "mini.openShop",
|
|
53
53
|
* title: "Open the shop",
|
|
54
54
|
* input: {},
|
|
55
55
|
* effect: "route",
|
package/dist/inspect.d.mts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { F as Api, q as Snapshot, s as Position, x as JournalEntry, y as FlowGraph } from "./types-ERb2Y9U5.mjs";
|
|
2
|
+
import { H as EntitySnapshot, R as ComponentSchema, U as FrameDiff, f as Usage, j as Explained, k as Api$1, m as Api$2, t as Api$3, w as RenderStats, x as Under } from "./types-BWzCSRM2.mjs";
|
|
3
|
+
import { t as HeadlessApp } from "./headless-q98SwADR.mjs";
|
|
4
|
+
import { a as InputOf, c as Source, i as InputArguments, l as WatchApp, o as InputSchema, t as CheatEntry, u as WatchInput } from "./types-CDSKa0vl.mjs";
|
|
5
|
+
import { c as UiNode } from "./types-DgdMLZnV.mjs";
|
|
6
|
+
import { a as SoundEntry, t as AudioApi, v as UiApi } from "./types-DlgsfOmW.mjs";
|
|
7
|
+
import { n as defineSource } from "./define-BPpZcpxW.mjs";
|
|
8
|
+
import { n as EffectsApi, r as EffectsStats } from "./types-DF5kkW-C.mjs";
|
|
7
9
|
|
|
8
10
|
//#region src/plugins/flow/doors/read.d.ts
|
|
9
11
|
/**
|
package/dist/inspect.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as defineSource } from "./input-
|
|
2
|
-
import { n as read, r as watch, t as sources } from "./sources-
|
|
1
|
+
import { c as defineSource } from "./input-z_35Jwfn.mjs";
|
|
2
|
+
import { n as read, r as watch, t as sources } from "./sources-BBUd15vQ.mjs";
|
|
3
3
|
export { defineSource, read, sources, watch };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./runtime-
|
|
1
|
+
import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./runtime-CvDZZg1S.mjs";
|
|
2
2
|
export { Fragment, type JSX, jsx, jsxDEV, jsxs };
|
package/dist/jsx-runtime.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as jsxs, n as JSX, r as jsx, t as Fragment } from "./runtime-
|
|
1
|
+
import { a as jsxs, n as JSX, r as jsx, t as Fragment } from "./runtime-CvDZZg1S.mjs";
|
|
2
2
|
export { Fragment, type JSX, jsx, jsxs };
|
package/dist/project.d.mts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* ```ts
|
|
16
|
-
* // The editor opens the
|
|
17
|
-
* const options: ProjectOptions = { root: "tests/
|
|
16
|
+
* // The editor opens the mini game with the default manifest and a slower debounce.
|
|
17
|
+
* const options: ProjectOptions = { root: "tests/fixtures/mini-game", debounceMs: 120 };
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
type ProjectOptions = {
|
|
@@ -29,7 +29,7 @@ type ProjectOptions = {
|
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
31
|
* ```ts
|
|
32
|
-
* const kind: JsxKind = "idProp"; // id="
|
|
32
|
+
* const kind: JsxKind = "idProp"; // id="infoPanel" on <Panel>
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
type JsxKind = "literal" | "template" | "idProp" | "ident";
|
|
@@ -39,8 +39,8 @@ type JsxKind = "literal" | "template" | "idProp" | "ident";
|
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```ts
|
|
42
|
-
* // node:
|
|
43
|
-
* const anchor: Anchor = { path: "nodes/
|
|
42
|
+
* // node:infoPopup/count, defined by the const `count` of nodes/count.ts.
|
|
43
|
+
* const anchor: Anchor = { path: "nodes/count.ts", binding: "count" };
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
46
|
type Anchor = {
|
|
@@ -66,8 +66,8 @@ type Anchor = {
|
|
|
66
66
|
*
|
|
67
67
|
* @example
|
|
68
68
|
* ```ts
|
|
69
|
-
* index.symbols["flow:
|
|
70
|
-
* index.files["nodes/
|
|
69
|
+
* index.symbols["flow:infoPopup"]; // { def: [{ path: "flows/info.ts", binding: "infoFlow" }] }
|
|
70
|
+
* index.files["nodes/count.ts"]?.state; // "ok"
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
type ProjectIndex = {
|
|
@@ -99,9 +99,9 @@ type ProjectIndex = {
|
|
|
99
99
|
*
|
|
100
100
|
* @example
|
|
101
101
|
* ```ts
|
|
102
|
-
* // An agent moved nodes/
|
|
103
|
-
* change.files; // ["flows/
|
|
104
|
-
* change.moved; // [{ key: "node:
|
|
102
|
+
* // An agent moved nodes/count.ts to nodes/info/count.ts and fixed the import of the info flow.
|
|
103
|
+
* change.files; // ["flows/info.ts", "nodes/count.ts", "nodes/info/count.ts"]
|
|
104
|
+
* change.moved; // [{ key: "node:infoPopup/count", from: "nodes/count.ts", to: "nodes/info/count.ts" }]
|
|
105
105
|
* change.removed; // []
|
|
106
106
|
* ```
|
|
107
107
|
*/
|
|
@@ -123,9 +123,9 @@ type ProjectChange = {
|
|
|
123
123
|
*
|
|
124
124
|
* @example
|
|
125
125
|
* ```ts
|
|
126
|
-
* // The editor opens the Home scene of the
|
|
126
|
+
* // The editor opens the Home scene of the mini game.
|
|
127
127
|
* const [found] = await project.find("scene:home");
|
|
128
|
-
* [found?.path, found?.line, found?.range]; // ["features/home/scene.ts", 8, [8, 1,
|
|
128
|
+
* [found?.path, found?.line, found?.range]; // ["features/home/scene.ts", 8, [8, 1, 12, 4]]
|
|
129
129
|
* ```
|
|
130
130
|
*/
|
|
131
131
|
type Found = Anchor & {
|
|
@@ -145,7 +145,7 @@ type ProjectApi = {
|
|
|
145
145
|
* @example
|
|
146
146
|
* ```ts
|
|
147
147
|
* // The editor checks a node file before it opens it.
|
|
148
|
-
* project.index.files["nodes/
|
|
148
|
+
* project.index.files["nodes/count.ts"]?.state; // "ok"
|
|
149
149
|
* ```
|
|
150
150
|
*/
|
|
151
151
|
readonly index: ProjectIndex;
|
|
@@ -157,14 +157,14 @@ type ProjectApi = {
|
|
|
157
157
|
* with a literal prop of the same name on their component (both the pattern and the prop come
|
|
158
158
|
* back), then `*` patterns. An unknown key answers `[]`.
|
|
159
159
|
*
|
|
160
|
-
* @param key - An engine id: `node:
|
|
160
|
+
* @param key - An engine id: `node:infoPopup/count`, `flow:main`, `textStyle:ui.counter`, `jsx:infoPanelSpark`.
|
|
161
161
|
* @returns One entry per place, in the order above; `broken` when the file does not parse now.
|
|
162
162
|
* @example
|
|
163
163
|
* ```ts
|
|
164
|
-
* // The editor jumps to the node the flow view clicked, and to the
|
|
165
|
-
* (await project.find("node:
|
|
166
|
-
* (await project.find("jsx:
|
|
167
|
-
* // ["features/
|
|
164
|
+
* // The editor jumps to the node the flow view clicked, and to the spark of the info panel.
|
|
165
|
+
* (await project.find("node:infoPopup/count"))[0]?.line; // 7, in "nodes/count.ts"
|
|
166
|
+
* (await project.find("jsx:infoPanelSpark")).map(found => `${found.path}:${found.line}`);
|
|
167
|
+
* // ["features/info/popup.tsx:65", "features/info/popup.tsx:79"]
|
|
168
168
|
* ```
|
|
169
169
|
*/
|
|
170
170
|
find(key: string): Promise<Found[]>;
|
|
@@ -198,9 +198,9 @@ type ProjectApi = {
|
|
|
198
198
|
* @throws {Error} When the path leaves the root, by `..` or by a symlink.
|
|
199
199
|
* @example
|
|
200
200
|
* ```ts
|
|
201
|
-
* // The editor saved nodes/
|
|
202
|
-
* const index = await project.changed("nodes/
|
|
203
|
-
* index.files["nodes/
|
|
201
|
+
* // The editor saved nodes/count.ts through its own file layer.
|
|
202
|
+
* const index = await project.changed("nodes/count.ts");
|
|
203
|
+
* index.files["nodes/count.ts"]?.state; // "ok"
|
|
204
204
|
* ```
|
|
205
205
|
*/
|
|
206
206
|
changed(path: string): Promise<ProjectIndex>;
|
|
@@ -247,9 +247,9 @@ type IndexUi = {
|
|
|
247
247
|
* `--check` that found a broken file or a conflict; else `0`.
|
|
248
248
|
* @example
|
|
249
249
|
* ```ts
|
|
250
|
-
* // An agent asks where a node of the
|
|
251
|
-
* await runCli(["--root", "tests/
|
|
252
|
-
* // 0, and the console printed "nodes/
|
|
250
|
+
* // An agent asks where a node of the mini game lives.
|
|
251
|
+
* await runCli(["--root", "tests/fixtures/mini-game", "where", "node:infoPopup/count"]);
|
|
252
|
+
* // 0, and the console printed "nodes/count.ts:7"
|
|
253
253
|
* ```
|
|
254
254
|
*/
|
|
255
255
|
declare function runCli(argv: readonly string[], ui?: IndexUi): Promise<number>;
|
|
@@ -266,10 +266,10 @@ declare function runCli(argv: readonly string[], ui?: IndexUi): Promise<number>;
|
|
|
266
266
|
* installed: `[game] The project index needs the "typescript" package.`
|
|
267
267
|
* @example
|
|
268
268
|
* ```ts
|
|
269
|
-
* // The editor opens the
|
|
270
|
-
* const project = await openProject({ root: "tests/
|
|
271
|
-
* Object.keys(project.index.files).length; //
|
|
272
|
-
* (await project.find("textStyle:ui.
|
|
269
|
+
* // The editor opens the mini game and answers where a node and a text style live.
|
|
270
|
+
* const project = await openProject({ root: "tests/fixtures/mini-game" });
|
|
271
|
+
* Object.keys(project.index.files).length; // 21
|
|
272
|
+
* (await project.find("textStyle:ui.counter"))[0]?.line; // 16, in "features/home/styles.ts"
|
|
273
273
|
* project.close();
|
|
274
274
|
* ```
|
|
275
275
|
*/
|