@moku-labs/game 0.15.29 → 0.15.30
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 +1 -1
- package/dist/app/page.mjs +1 -1
- package/dist/app/system.d.mts +2 -2
- package/dist/app.d.mts +1 -1
- package/dist/app.mjs +1 -1
- package/dist/{commands-BOxMqhVe.d.mts → commands-BUfZJUx6.d.mts} +26 -26
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +2 -2
- package/dist/{index-Cl5zwodk.d.mts → index-B2GejbLf.d.mts} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/inspect.d.mts +10 -10
- package/dist/inspect.mjs +2 -2
- package/dist/{run-DRcc2SKF.mjs → run-DyL8rl2P.mjs} +15 -43
- package/dist/{session-CeKgO2hy.mjs → session-DuZfGZWk.mjs} +20 -1
- package/dist/{sources-ncFMQIus.mjs → sources-DM5Zcl4o.mjs} +8 -17
- package/dist/{src-wyJYr12n.mjs → src-B4JjsuEy.mjs} +1 -1
- package/dist/testing.d.mts +2 -2
- package/dist/testing.mjs +1 -1
- package/dist/{types-Cyu_jKop.d.mts → types-BWRJcZ3n.d.mts} +1 -1
- package/dist/{visual-DhNLNtl8.d.mts → visual-f6mtELhG.d.mts} +1 -1
- package/dist/visual.d.mts +1 -1
- package/dist/visual.mjs +2 -2
- package/llms.txt +12 -11
- package/package.json +1 -1
package/dist/app/page.d.mts
CHANGED
package/dist/app/page.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as systemSource, t as memory } from "../memory-CWlqhS7l.mjs";
|
|
2
2
|
import { t as applyTo } from "../drafts-BawpSaVp.mjs";
|
|
3
3
|
import { i as isControl } from "../dev-BNndV-hU.mjs";
|
|
4
|
-
import { n as read, r as watch, t as sources } from "../sources-
|
|
4
|
+
import { n as read, r as watch, t as sources } from "../sources-DM5Zcl4o.mjs";
|
|
5
5
|
import { t as resolveConfig } from "../config-B87aFTW-.mjs";
|
|
6
6
|
//#region src/app/save.ts
|
|
7
7
|
/**
|
package/dist/app/system.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Mr as PlayerStateProvider } from "../types-D27I4Q7b.mjs";
|
|
2
|
-
import { ht as PlatformProvider } from "../index-
|
|
3
|
-
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-
|
|
2
|
+
import { ht as PlatformProvider } from "../index-B2GejbLf.mjs";
|
|
3
|
+
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-BWRJcZ3n.mjs";
|
|
4
4
|
import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
5
5
|
|
|
6
6
|
//#region src/app/system.d.ts
|
package/dist/app.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Dr as Json } from "./types-D27I4Q7b.mjs";
|
|
2
2
|
import { U as StringTable } from "./types-BAp9HdR4.mjs";
|
|
3
|
-
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, v as WithGameState } from "./types-
|
|
3
|
+
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, v as WithGameState } from "./types-BWRJcZ3n.mjs";
|
|
4
4
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
5
5
|
|
|
6
6
|
//#region src/app/define.d.ts
|
package/dist/app.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ft as audioPlugin, H as platformPlugin, i as screen, m as flattenFeatures, t as createApp, wt as effectsPlugin } from "./src-
|
|
1
|
+
import { Ft as audioPlugin, H as platformPlugin, i as screen, m as flattenFeatures, t as createApp, wt as effectsPlugin } from "./src-B4JjsuEy.mjs";
|
|
2
2
|
import { t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { n as isFakeClock, t as fakeClock } from "./fake-6mazmHK3.mjs";
|
|
4
4
|
//#region src/app/define.ts
|
|
@@ -19,8 +19,8 @@ import { n as Command, r as ControlApp } from "./types-CgE5L_7f.mjs";
|
|
|
19
19
|
*/
|
|
20
20
|
declare const commands: Readonly<{
|
|
21
21
|
answer: Command<{
|
|
22
|
-
intent: "string";
|
|
23
|
-
payload: "json?";
|
|
22
|
+
readonly intent: "string";
|
|
23
|
+
readonly payload: "json?";
|
|
24
24
|
}, boolean, ControlApp>;
|
|
25
25
|
tap: Command<{
|
|
26
26
|
key: "string?";
|
|
@@ -32,23 +32,23 @@ declare const commands: Readonly<{
|
|
|
32
32
|
readonly ui: Pick<UiApi, "find">;
|
|
33
33
|
}>;
|
|
34
34
|
drag: Command<{
|
|
35
|
-
from: "json";
|
|
36
|
-
to: "json";
|
|
35
|
+
readonly from: "json";
|
|
36
|
+
readonly to: "json";
|
|
37
37
|
}, boolean, HeadlessApp & {
|
|
38
38
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
39
39
|
} & {
|
|
40
40
|
readonly input: InputApi;
|
|
41
41
|
}>;
|
|
42
42
|
key: Command<{
|
|
43
|
-
key: "string";
|
|
44
|
-
shift: "boolean?";
|
|
43
|
+
readonly key: "string";
|
|
44
|
+
readonly shift: "boolean?";
|
|
45
45
|
}, boolean, HeadlessApp & {
|
|
46
46
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
47
47
|
} & {
|
|
48
48
|
readonly input: InputApi;
|
|
49
49
|
}>;
|
|
50
50
|
walk: Command<{
|
|
51
|
-
route: "json";
|
|
51
|
+
readonly route: "json";
|
|
52
52
|
}, FlowState, ControlApp>;
|
|
53
53
|
bookmark: Command<{}, Bookmark, HeadlessApp & {
|
|
54
54
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
@@ -56,8 +56,8 @@ declare const commands: Readonly<{
|
|
|
56
56
|
readonly scenes?: ScenesApi;
|
|
57
57
|
}>;
|
|
58
58
|
restore: Command<{
|
|
59
|
-
bookmark: "json?";
|
|
60
|
-
repro: "json?";
|
|
59
|
+
readonly bookmark: "json?";
|
|
60
|
+
readonly repro: "json?";
|
|
61
61
|
}, FlowState, HeadlessApp & {
|
|
62
62
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
63
63
|
} & {
|
|
@@ -73,7 +73,7 @@ declare const commands: Readonly<{
|
|
|
73
73
|
};
|
|
74
74
|
}>;
|
|
75
75
|
saveImport: Command<{
|
|
76
|
-
save: "json";
|
|
76
|
+
readonly save: "json";
|
|
77
77
|
}, {
|
|
78
78
|
restored: boolean;
|
|
79
79
|
}, HeadlessApp & {
|
|
@@ -86,8 +86,8 @@ declare const commands: Readonly<{
|
|
|
86
86
|
};
|
|
87
87
|
}>;
|
|
88
88
|
step: Command<{
|
|
89
|
-
frames: "number";
|
|
90
|
-
deltaMs: "number?";
|
|
89
|
+
readonly frames: "number";
|
|
90
|
+
readonly deltaMs: "number?";
|
|
91
91
|
}, Readonly<Time>, ControlApp>;
|
|
92
92
|
pause: Command<{}, boolean, HeadlessApp & {
|
|
93
93
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
@@ -100,10 +100,10 @@ declare const commands: Readonly<{
|
|
|
100
100
|
readonly lifecycle: Api;
|
|
101
101
|
}>;
|
|
102
102
|
capture: Command<{
|
|
103
|
-
legend: "boolean?";
|
|
104
|
-
layers: "json?";
|
|
105
|
-
sheet: "json?";
|
|
106
|
-
diff: "json?";
|
|
103
|
+
readonly legend: "boolean?";
|
|
104
|
+
readonly layers: "json?";
|
|
105
|
+
readonly sheet: "json?";
|
|
106
|
+
readonly diff: "json?";
|
|
107
107
|
}, Captured | undefined, HeadlessApp & {
|
|
108
108
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
109
109
|
} & {
|
|
@@ -112,10 +112,10 @@ declare const commands: Readonly<{
|
|
|
112
112
|
readonly world: Api$2;
|
|
113
113
|
}>;
|
|
114
114
|
debug: Command<{
|
|
115
|
-
nineSlice: "boolean?";
|
|
116
|
-
verifyFrames: "boolean?";
|
|
117
|
-
kept: "boolean?";
|
|
118
|
-
overdraw: "boolean?";
|
|
115
|
+
readonly nineSlice: "boolean?";
|
|
116
|
+
readonly verifyFrames: "boolean?";
|
|
117
|
+
readonly kept: "boolean?";
|
|
118
|
+
readonly overdraw: "boolean?";
|
|
119
119
|
}, DebugSwitches, HeadlessApp & {
|
|
120
120
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
121
121
|
} & {
|
|
@@ -145,28 +145,28 @@ declare const commands: Readonly<{
|
|
|
145
145
|
readonly ui: Pick<UiApi, "scroll">;
|
|
146
146
|
}>;
|
|
147
147
|
timeScale: Command<{
|
|
148
|
-
scale: "number";
|
|
148
|
+
readonly scale: "number";
|
|
149
149
|
}, Readonly<Time>, ControlApp>;
|
|
150
150
|
frameRate: Command<{
|
|
151
|
-
fps: "number?";
|
|
151
|
+
readonly fps: "number?";
|
|
152
152
|
}, Readonly<FrameRate>, ControlApp>;
|
|
153
153
|
mute: Command<{
|
|
154
|
-
muted: "boolean";
|
|
154
|
+
readonly muted: "boolean";
|
|
155
155
|
}, boolean, HeadlessApp & {
|
|
156
156
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
157
157
|
} & {
|
|
158
158
|
readonly audio?: AudioApi;
|
|
159
159
|
}>;
|
|
160
160
|
trace: Command<{
|
|
161
|
-
path: "json";
|
|
161
|
+
readonly path: "json";
|
|
162
162
|
}, boolean, HeadlessApp & {
|
|
163
163
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
164
164
|
} & {
|
|
165
165
|
readonly input: InputApi;
|
|
166
166
|
}>;
|
|
167
167
|
filter: Command<{
|
|
168
|
-
kind: "string";
|
|
169
|
-
on: "boolean";
|
|
168
|
+
readonly kind: "string";
|
|
169
|
+
readonly on: "boolean";
|
|
170
170
|
}, readonly string[], HeadlessApp & {
|
|
171
171
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
172
172
|
} & {
|
package/dist/control.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as HeadlessApp } from "./headless-f31cEZ7f.mjs";
|
|
2
2
|
import { i as InputArguments, n as Command, o as InputSchema, s as Ran } from "./types-CgE5L_7f.mjs";
|
|
3
|
-
import { t as commands } from "./commands-
|
|
3
|
+
import { t as commands } from "./commands-BUfZJUx6.mjs";
|
|
4
4
|
import { t as defineCommand } from "./define-CE1uxbe9.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/plugins/flow/doors/dev.d.ts
|
package/dist/control.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { n as controlRefused, t as controlReadOnly } from "./dev-BNndV-hU.mjs";
|
|
2
|
-
import { s as defineCommand } from "./session-
|
|
3
|
-
import { n as commands, t as run } from "./run-
|
|
2
|
+
import { s as defineCommand } from "./session-DuZfGZWk.mjs";
|
|
3
|
+
import { n as commands, t as run } from "./run-DyL8rl2P.mjs";
|
|
4
4
|
export { commands, controlReadOnly, controlRefused, defineCommand, run };
|
|
@@ -1863,7 +1863,7 @@ declare function defineGame<Types extends GameTypes>(): {
|
|
|
1863
1863
|
readonly textures: readonly Types["assets"][];
|
|
1864
1864
|
}) => EmitterDefinition;
|
|
1865
1865
|
Emitter: Narrowed<EmitterValue, {
|
|
1866
|
-
effect?: EmitterIdOf<Types>;
|
|
1866
|
+
effect?: "" | EmitterIdOf<Types>;
|
|
1867
1867
|
active?: boolean;
|
|
1868
1868
|
}>;
|
|
1869
1869
|
Displacement: Narrowed<DisplacementValue, Partial<Omit<DisplacementValue, "map">> & {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $t as ShaderWhat, Ar as types_d_exports$10, At as PerfChange, Bt as PerfLongFrameLine, Cr as types_d_exports$3, Ct as PERF_CAUSES, Dt as PassKind, E as types_d_exports$13, Et as PROBLEM_RULES, Fr as SaveUnreadableError, Ft as PerfEventLine, G as Transform, Gt as PerfStartupLine, H as SpriteBlend, Ht as PerfMeasured, I as Overlay, It as PerfEventName, J as AdaptiveScale, Jn as exit, Jt as PoolTrimDetail, Kn as types_d_exports$6, Kr as types_d_exports$9, Kt as PerfTelemetryLine, L as OverlayValue, Lt as PerfGapLine, M as HudPart, Mt as PerfCollectorLine, N as HudPartValue, Nt as PerfCounts, Ot as PassRecord, P as NineSlice, Pt as PerfDisplay, Qt as ShaderEventDetail, R as Parent, Rt as PerfHeaderLine, St as OverlayWhat, Tn as DescriptionNode, Tt as PERF_LOG_VERSION, Ut as PerfSampleLine, V as Sprite, Vt as PerfMarkLine, Wt as PerfSpikeLine, Xn as to, Xt as ProblemRule, Yn as slot, Yt as ProblemEventDetail, Z as MonitorConfig, Zn as type, Zt as SHADER_WHATS, _t as FrameRing, at as types_d_exports$12, bt as MonitorSections, ei as types_d_exports$15, en as WarmDetail, g as types_d_exports$1, gt as FrameRecord, ht as FrameReadout, j as Display, jt as PerfChangeEntry, kt as PerfCause, mt as FrameReadResult, nt as PoolTrim, on as types_d_exports$17, pt as FrameColumns, q as sprite, qt as PerfThermalLine, st as MonitorCounts, tn as DEMAND_REASONS, vt as LongFrameEntry, wt as PERF_GAP_BUCKETS, xt as OverlayEventDetail, yt as MONITOR_SECTIONS, z as Shape, zt as PerfLogLine } from "./types-D27I4Q7b.mjs";
|
|
2
2
|
import { $ as sequence, E as FilterArea, G as HAPTIC_KINDS, H as HapticKind, J as frames, K as defineAnimation, Q as play, V as types_d_exports, X as mark, Y as haptic, Z as parallel, at as stopSfx, ct as wait, et as set, i as types_d_exports$16, it as stagger, nt as spawn, ot as tween, p as types_d_exports$2, q as external, rt as spawned, st as use, tt as sfx, ut as types_d_exports$4, v as types_d_exports$5 } from "./types-DjQkfbfZ.mjs";
|
|
3
3
|
import { A as types_d_exports$14, E as TextFormat, F as types_d_exports$8, K as types_d_exports$7, d as DebugTrigger, f as LocalWrite, h as defineTokens, j as defineComponent, m as popup, p as ScrollState, u as Box, x as CountdownValue, y as BindOptions } from "./types-BAp9HdR4.mjs";
|
|
4
|
-
import { $ as system, A as Draggable, At as Text, B as Touchable, C as AnimPlayer, Ct as debugPlugin, D as defineBundles, Dt as animPlugin, E as defineScene, Et as assetsPlugin, F as PointerOver, G as Exiting, H as Traced, I as Pressable, J as Order, K as Layer, L as Pressed, M as Held, Mt as defineTextStyles, N as Hovered, Nt as label, O as load, Ot as projection, P as Pointer, Q as resource, R as Swipeable, S as defineMotion, St as effectsPlugin, T as Frames, Tt as audioPlugin, U as PASS_KINDS, V as Traceable, W as frameAt, X as component, Y as Tree, Z as mut, _ as defineStyle, _t as modelPlugin, a as defineEmitter, at as defineFeature, b as messageDuration, bt as i18nPlugin, c as Alpha, ct as uiPlugin, d as Displacement, dt as scenesPlugin, et as tag, f as Glow, ft as rendererPlugin, g as resolve, gt as types_d_exports$11, h as music, ht as PlatformProvider, i as screen, it as schedule, j as DropTarget, jt as bind, k as ready, kt as Countdown, l as Blur, lt as timePlugin, m as Outline, mt as BackResult, n as createPlugin, nt as guide, o as Emitter, ot as flattenFeatures, p as Noise, pt as platformPlugin, q as Now, r as defineGame, rt as hint, s as defineFilter, st as worldPlugin, t as createApp, tt as defineEffect, u as ColorMatrix, ut as textPlugin, v as tr, vt as lifecyclePlugin, w as Animation, wt as clockPlugin, x as cubicBezier, xt as flowPlugin, y as messageArgument, yt as inputPlugin, z as Tappable } from "./index-
|
|
4
|
+
import { $ as system, A as Draggable, At as Text, B as Touchable, C as AnimPlayer, Ct as debugPlugin, D as defineBundles, Dt as animPlugin, E as defineScene, Et as assetsPlugin, F as PointerOver, G as Exiting, H as Traced, I as Pressable, J as Order, K as Layer, L as Pressed, M as Held, Mt as defineTextStyles, N as Hovered, Nt as label, O as load, Ot as projection, P as Pointer, Q as resource, R as Swipeable, S as defineMotion, St as effectsPlugin, T as Frames, Tt as audioPlugin, U as PASS_KINDS, V as Traceable, W as frameAt, X as component, Y as Tree, Z as mut, _ as defineStyle, _t as modelPlugin, a as defineEmitter, at as defineFeature, b as messageDuration, bt as i18nPlugin, c as Alpha, ct as uiPlugin, d as Displacement, dt as scenesPlugin, et as tag, f as Glow, ft as rendererPlugin, g as resolve, gt as types_d_exports$11, h as music, ht as PlatformProvider, i as screen, it as schedule, j as DropTarget, jt as bind, k as ready, kt as Countdown, l as Blur, lt as timePlugin, m as Outline, mt as BackResult, n as createPlugin, nt as guide, o as Emitter, ot as flattenFeatures, p as Noise, pt as platformPlugin, q as Now, r as defineGame, rt as hint, s as defineFilter, st as worldPlugin, t as createApp, tt as defineEffect, u as ColorMatrix, ut as textPlugin, v as tr, vt as lifecyclePlugin, w as Animation, wt as clockPlugin, x as cubicBezier, xt as flowPlugin, y as messageArgument, yt as inputPlugin, z as Tappable } from "./index-B2GejbLf.mjs";
|
|
5
5
|
export { type AdaptiveScale, 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, DEMAND_REASONS, types_d_exports$4 as Debug, DebugTrigger, type DescriptionNode, Displacement, Display, Draggable, DropTarget, types_d_exports$5 as Effects, Emitter, Exiting, type FilterArea, types_d_exports$6 as Flow, type FrameColumns, type FrameReadResult, type FrameReadout, type FrameRecord, type FrameRing, Frames, Glow, HAPTIC_KINDS, type HapticKind, Held, Hovered, HudPart, type HudPartValue, types_d_exports$7 as I18n, types_d_exports$8 as Input, Layer, types_d_exports$9 as Lifecycle, LocalWrite, type LongFrameEntry, MONITOR_SECTIONS, types_d_exports$10 as Model, type MonitorConfig, type MonitorCounts, type MonitorSections, NineSlice, Noise, Now, Order, Outline, Overlay, type OverlayEventDetail, type OverlayValue, type OverlayWhat, PASS_KINDS, PERF_CAUSES, PERF_GAP_BUCKETS, PERF_LOG_VERSION, PROBLEM_RULES, Parent, type PassKind, type PassRecord, type PerfCause, type PerfChange, type PerfChangeEntry, type PerfCollectorLine, type PerfCounts, type PerfDisplay, type PerfEventLine, type PerfEventName, type PerfGapLine, type PerfHeaderLine, type PerfLogLine, type PerfLongFrameLine, type PerfMarkLine, type PerfMeasured, type PerfSampleLine, type PerfSpikeLine, type PerfStartupLine, type PerfTelemetryLine, type PerfThermalLine, types_d_exports$11 as Platform, type PlatformProvider, Pointer, PointerOver, type PoolTrim, type PoolTrimDetail, Pressable, Pressed, type ProblemEventDetail, type ProblemRule, types_d_exports$12 as Renderer, SHADER_WHATS, SaveUnreadableError, types_d_exports$13 as Scenes, ScrollState, type ShaderEventDetail, type ShaderWhat, Shape, Sprite, type SpriteBlend, Swipeable, Tappable, Text, type TextFormat, types_d_exports$14 as TextTypes, types_d_exports$15 as Time, Touchable, Traceable, Traced, Transform, Tree, types_d_exports$16 as Ui, type WarmDetail, types_d_exports$17 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, cubicBezier, debugPlugin, defineAnimation, defineBundles, defineComponent, defineEffect, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flattenFeatures, flowPlugin, frameAt, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, messageArgument, messageDuration, modelPlugin, music, mut, parallel, platformPlugin, play, popup, projection, ready, rendererPlugin, resolve, resource, scenesPlugin, schedule, screen, sequence, set, sfx, slot, spawn, spawned, sprite, stagger, stopSfx, 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, $t as flowPlugin, A as types_exports$7, At as Glow, B as defineMotion, Bt as Animation, C as types_exports$14, Ct as messageDuration, D as types_exports$10, Dt as Blur, E as types_exports$11, Et as Alpha, F as types_exports$2, Ft as audioPlugin, G as external, Gt as MONITOR_SECTIONS, H as platformPlugin, Ht as rendererPlugin, I as types_exports$1, It as scenesPlugin, J as mark, Jt as PERF_LOG_VERSION, K as frames, Kt as PERF_CAUSES, L as types_exports, Lt as assetsPlugin, M as types_exports$5, Mt as Outline, N as types_exports$4, Nt as defineFilter, O as types_exports$9, Ot as ColorMatrix, P as types_exports$3, Pt as debugPlugin, Q as set, Qt as worldPlugin, R as uiPlugin, Rt as animPlugin, S as types_exports$15, St as messageArgument, T as types_exports$12, Tt as Emitter, U as HAPTIC_KINDS, Ut as PASS_KINDS, V as textPlugin, Vt as Frames, W as defineAnimation, Wt as frameAt, X as play, Xt as SHADER_WHATS, Y as parallel, Yt as PROBLEM_RULES, Z as sequence, Zt as DEMAND_REASONS, _ as defineBundles, _t as Tappable, a as cubicBezier, an as modelPlugin, at as use, b as types_exports$17, bt as Traced, c as hint, cn as timePlugin, ct as Draggable, d as defineScene, dt as Hovered, et as spawn, f as tr, ft as Pointer, g as music, gt as Swipeable, h as defineEmitter, ht as Pressed, i as screen, in as type, it as tween, j as types_exports$6, jt as Noise, k as types_exports$8, kt as Displacement, l as schedule, ln as clockPlugin, lt as DropTarget, m as flattenFeatures, mt as Pressable, n as createPlugin, nn as slot, nt as stagger, o as defineEffect, on as SaveUnreadableError, ot as wait, p as defineFeature, pt as PointerOver, q as haptic, qt as PERF_GAP_BUCKETS, r as defineGame, rn as to, rt as stopSfx, s as guide, sn as lifecyclePlugin, st as inputPlugin, t as createApp, tn as exit, tt as spawned, u as projection, ut as Held, v as load, vt as Touchable, w as types_exports$13, wt as effectsPlugin, x as types_exports$16, xt as i18nPlugin, y as ready, yt as Traceable, z as resolve, zt as AnimPlayer } from "./src-
|
|
1
|
+
import { $ as sfx, $t as flowPlugin, A as types_exports$7, At as Glow, B as defineMotion, Bt as Animation, C as types_exports$14, Ct as messageDuration, D as types_exports$10, Dt as Blur, E as types_exports$11, Et as Alpha, F as types_exports$2, Ft as audioPlugin, G as external, Gt as MONITOR_SECTIONS, H as platformPlugin, Ht as rendererPlugin, I as types_exports$1, It as scenesPlugin, J as mark, Jt as PERF_LOG_VERSION, K as frames, Kt as PERF_CAUSES, L as types_exports, Lt as assetsPlugin, M as types_exports$5, Mt as Outline, N as types_exports$4, Nt as defineFilter, O as types_exports$9, Ot as ColorMatrix, P as types_exports$3, Pt as debugPlugin, Q as set, Qt as worldPlugin, R as uiPlugin, Rt as animPlugin, S as types_exports$15, St as messageArgument, T as types_exports$12, Tt as Emitter, U as HAPTIC_KINDS, Ut as PASS_KINDS, V as textPlugin, Vt as Frames, W as defineAnimation, Wt as frameAt, X as play, Xt as SHADER_WHATS, Y as parallel, Yt as PROBLEM_RULES, Z as sequence, Zt as DEMAND_REASONS, _ as defineBundles, _t as Tappable, a as cubicBezier, an as modelPlugin, at as use, b as types_exports$17, bt as Traced, c as hint, cn as timePlugin, ct as Draggable, d as defineScene, dt as Hovered, et as spawn, f as tr, ft as Pointer, g as music, gt as Swipeable, h as defineEmitter, ht as Pressed, i as screen, in as type, it as tween, j as types_exports$6, jt as Noise, k as types_exports$8, kt as Displacement, l as schedule, ln as clockPlugin, lt as DropTarget, m as flattenFeatures, mt as Pressable, n as createPlugin, nn as slot, nt as stagger, o as defineEffect, on as SaveUnreadableError, ot as wait, p as defineFeature, pt as PointerOver, q as haptic, qt as PERF_GAP_BUCKETS, r as defineGame, rn as to, rt as stopSfx, s as guide, sn as lifecyclePlugin, st as inputPlugin, t as createApp, tn as exit, tt as spawned, u as projection, ut as Held, v as load, vt as Touchable, w as types_exports$13, wt as effectsPlugin, x as types_exports$16, xt as i18nPlugin, y as ready, yt as Traceable, z as resolve, zt as AnimPlayer } from "./src-B4JjsuEy.mjs";
|
|
2
2
|
import { $ as component, H as Shape, I as Display, J as Exiting, L as HudPart, Q as Tree, R as NineSlice, S as bind, T as label, U as Sprite, V as Parent, W as Transform, X as Now, Y as Layer, Z as Order, b as Countdown, d as LocalWrite, et as mut, g as popup, it as tag, l as DebugTrigger, nt as system, p as ScrollState, q as sprite, s as Box, tt as resource, v as defineTokens, w as defineTextStyles, x as Text, y as defineStyle, z as Overlay } from "./visual-ClVRMUAi.mjs";
|
|
3
3
|
import { t as defineComponent } from "./component-DGg5DqKK.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, DEMAND_REASONS, types_exports$4 as Debug, DebugTrigger, Displacement, Display, Draggable, DropTarget, types_exports$5 as Effects, Emitter, Exiting, types_exports$6 as Flow, Frames, Glow, HAPTIC_KINDS, Held, Hovered, HudPart, types_exports$7 as I18n, types_exports$8 as Input, Layer, types_exports$9 as Lifecycle, LocalWrite, MONITOR_SECTIONS, types_exports$10 as Model, NineSlice, Noise, Now, Order, Outline, Overlay, PASS_KINDS, PERF_CAUSES, PERF_GAP_BUCKETS, PERF_LOG_VERSION, PROBLEM_RULES, Parent, types_exports$11 as Platform, Pointer, PointerOver, Pressable, Pressed, types_exports$12 as Renderer, SHADER_WHATS, SaveUnreadableError, types_exports$13 as Scenes, ScrollState, Shape, Sprite, Swipeable, Tappable, Text, types_exports$14 as TextTypes, types_exports$15 as Time, Touchable, Traceable, Traced, Transform, Tree, types_exports$16 as Ui, types_exports$17 as World, animPlugin, assetsPlugin, audioPlugin, bind, clockPlugin, component, createApp, createPlugin, cubicBezier, debugPlugin, defineAnimation, defineBundles, defineComponent, defineEffect, defineEmitter, defineFeature, defineFilter, defineGame, defineMotion, defineScene, defineStyle, defineTextStyles, defineTokens, effectsPlugin, exit, external, flattenFeatures, flowPlugin, frameAt, frames, guide, haptic, hint, i18nPlugin, inputPlugin, label, lifecyclePlugin, load, mark, messageArgument, messageDuration, modelPlugin, music, mut, parallel, platformPlugin, play, popup, projection, ready, rendererPlugin, resolve, resource, scenesPlugin, schedule, screen, sequence, set, sfx, slot, spawn, spawned, sprite, stagger, stopSfx, system, tag, textPlugin, timePlugin, to, tr, tween, type, uiPlugin, use, wait, worldPlugin };
|
package/dist/inspect.d.mts
CHANGED
|
@@ -56,7 +56,7 @@ declare const sources: Readonly<{
|
|
|
56
56
|
graph: Source<{}, FlowGraph, HeadlessApp>;
|
|
57
57
|
position: Source<{}, Position, HeadlessApp>;
|
|
58
58
|
history: Source<{
|
|
59
|
-
last: "number?";
|
|
59
|
+
readonly last: "number?";
|
|
60
60
|
}, readonly JournalEntry[], HeadlessApp>;
|
|
61
61
|
tainted: Source<{}, boolean, HeadlessApp>;
|
|
62
62
|
cheats: Source<{}, readonly CheatEntry[], HeadlessApp>;
|
|
@@ -64,8 +64,8 @@ declare const sources: Readonly<{
|
|
|
64
64
|
readonly model: Api;
|
|
65
65
|
}>;
|
|
66
66
|
entities: Source<{
|
|
67
|
-
owner: "string?";
|
|
68
|
-
component: "string?";
|
|
67
|
+
readonly owner: "string?";
|
|
68
|
+
readonly component: "string?";
|
|
69
69
|
}, EntitySnapshot[], HeadlessApp & {
|
|
70
70
|
readonly world: Api$1;
|
|
71
71
|
}>;
|
|
@@ -92,7 +92,7 @@ declare const sources: Readonly<{
|
|
|
92
92
|
readonly renderer: Api$2;
|
|
93
93
|
}>;
|
|
94
94
|
sounds: Source<{
|
|
95
|
-
last: "number?";
|
|
95
|
+
readonly last: "number?";
|
|
96
96
|
}, readonly SoundEntry[], HeadlessApp & {
|
|
97
97
|
readonly audio?: AudioApi;
|
|
98
98
|
}>;
|
|
@@ -112,18 +112,18 @@ declare const sources: Readonly<{
|
|
|
112
112
|
readonly assets: Api$3;
|
|
113
113
|
}>;
|
|
114
114
|
log: Source<{
|
|
115
|
-
level: "string?";
|
|
115
|
+
readonly level: "string?";
|
|
116
116
|
}, readonly import("@moku-labs/common/browser").LogEntry[], HeadlessApp & {
|
|
117
117
|
readonly log: import("@moku-labs/common/browser").LogApi;
|
|
118
118
|
}>;
|
|
119
119
|
explain: Source<{
|
|
120
|
-
entity: "number";
|
|
120
|
+
readonly entity: "number";
|
|
121
121
|
}, Explained | undefined, HeadlessApp & {
|
|
122
122
|
readonly world: Api$1;
|
|
123
123
|
}>;
|
|
124
124
|
diff: Source<{
|
|
125
|
-
from: "number";
|
|
126
|
-
to: "number";
|
|
125
|
+
readonly from: "number";
|
|
126
|
+
readonly to: "number";
|
|
127
127
|
}, FrameDiff, HeadlessApp & {
|
|
128
128
|
readonly world: Api$1;
|
|
129
129
|
}>;
|
|
@@ -131,8 +131,8 @@ declare const sources: Readonly<{
|
|
|
131
131
|
readonly world: Api$1;
|
|
132
132
|
}>;
|
|
133
133
|
at: Source<{
|
|
134
|
-
x: "number";
|
|
135
|
-
y: "number";
|
|
134
|
+
readonly x: "number";
|
|
135
|
+
readonly y: "number";
|
|
136
136
|
}, readonly Under[], HeadlessApp & {
|
|
137
137
|
readonly renderer: Api$2;
|
|
138
138
|
readonly world: Api$1;
|
package/dist/inspect.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as defineSource } from "./session-
|
|
2
|
-
import { n as read, r as watch, t as sources } from "./sources-
|
|
1
|
+
import { c as defineSource } from "./session-DuZfGZWk.mjs";
|
|
2
|
+
import { n as read, r as watch, t as sources } from "./sources-DM5Zcl4o.mjs";
|
|
3
3
|
import "./inspect-la_KkjCS.mjs";
|
|
4
4
|
export { defineSource, read, sources, watch };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as sheetAlone, p as graphHash } from "./capture-PTJXDpxK.mjs";
|
|
2
2
|
import { a as isDev, i as isControl, n as controlRefused, o as notInstalled, r as isAgent, t as controlReadOnly } from "./dev-BNndV-hU.mjs";
|
|
3
3
|
import { n as reproBookmark } from "./headless-Bxxl_mQX.mjs";
|
|
4
|
-
import { a as readTarget, i as isProjectionTarget, n as isTainted, o as inputOrEmpty, r as recordCheat, s as defineCommand } from "./session-
|
|
4
|
+
import { a as readTarget, i as isProjectionTarget, l as inputSchema, n as isTainted, o as inputOrEmpty, r as recordCheat, s as defineCommand } from "./session-DuZfGZWk.mjs";
|
|
5
5
|
//#region src/plugins/anim/control.ts
|
|
6
6
|
/**
|
|
7
7
|
* @file anim plugin — the anim command of the `/control` door: switch reduced motion. Dev and
|
|
@@ -54,7 +54,7 @@ const reducedMotionCommand = defineCommand({
|
|
|
54
54
|
const muteCommand = defineCommand({
|
|
55
55
|
id: "game.mute",
|
|
56
56
|
title: "Mute",
|
|
57
|
-
input:
|
|
57
|
+
input: inputSchema(["muted", "boolean"]),
|
|
58
58
|
effect: "cosmetic",
|
|
59
59
|
run: (app, { muted }) => {
|
|
60
60
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -91,10 +91,7 @@ const muteCommand = defineCommand({
|
|
|
91
91
|
const filterCommand = defineCommand({
|
|
92
92
|
id: "game.filter",
|
|
93
93
|
title: "Filter kind on or off",
|
|
94
|
-
input:
|
|
95
|
-
kind: "string",
|
|
96
|
-
on: "boolean"
|
|
97
|
-
},
|
|
94
|
+
input: inputSchema(["kind", "string"], ["on", "boolean"]),
|
|
98
95
|
effect: "cosmetic",
|
|
99
96
|
run: (app, { kind, on }) => {
|
|
100
97
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -148,10 +145,7 @@ function readPath(value) {
|
|
|
148
145
|
const dragCommand = defineCommand({
|
|
149
146
|
id: "game.drag",
|
|
150
147
|
title: "Drag",
|
|
151
|
-
input:
|
|
152
|
-
from: "json",
|
|
153
|
-
to: "json"
|
|
154
|
-
},
|
|
148
|
+
input: inputSchema(["from", "json"], ["to", "json"]),
|
|
155
149
|
effect: "route",
|
|
156
150
|
run: (app, { from, to }) => {
|
|
157
151
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -173,7 +167,7 @@ const dragCommand = defineCommand({
|
|
|
173
167
|
const traceCommand = defineCommand({
|
|
174
168
|
id: "game.trace",
|
|
175
169
|
title: "Trace",
|
|
176
|
-
input:
|
|
170
|
+
input: inputSchema(["path", "json"]),
|
|
177
171
|
effect: "route",
|
|
178
172
|
run: (app, { path }) => {
|
|
179
173
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -195,10 +189,7 @@ const traceCommand = defineCommand({
|
|
|
195
189
|
const keyCommand = defineCommand({
|
|
196
190
|
id: "game.key",
|
|
197
191
|
title: "Press a key",
|
|
198
|
-
input:
|
|
199
|
-
key: "string",
|
|
200
|
-
shift: "boolean?"
|
|
201
|
-
},
|
|
192
|
+
input: inputSchema(["key", "string"], ["shift", "boolean?"]),
|
|
202
193
|
effect: "route",
|
|
203
194
|
run: (app, { key, shift = false }) => {
|
|
204
195
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -789,12 +780,7 @@ async function captureDiff(app, options, diff, raw) {
|
|
|
789
780
|
const captureCommand = defineCommand({
|
|
790
781
|
id: "game.capture",
|
|
791
782
|
title: "Capture",
|
|
792
|
-
input:
|
|
793
|
-
legend: "boolean?",
|
|
794
|
-
layers: "json?",
|
|
795
|
-
sheet: "json?",
|
|
796
|
-
diff: "json?"
|
|
797
|
-
},
|
|
783
|
+
input: inputSchema(["legend", "boolean?"], ["layers", "json?"], ["sheet", "json?"], ["diff", "json?"]),
|
|
798
784
|
effect: "read",
|
|
799
785
|
run: (app, input) => {
|
|
800
786
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -834,12 +820,7 @@ const captureCommand = defineCommand({
|
|
|
834
820
|
const debugCommand = defineCommand({
|
|
835
821
|
id: "game.debug",
|
|
836
822
|
title: "Debug drawing",
|
|
837
|
-
input:
|
|
838
|
-
nineSlice: "boolean?",
|
|
839
|
-
verifyFrames: "boolean?",
|
|
840
|
-
kept: "boolean?",
|
|
841
|
-
overdraw: "boolean?"
|
|
842
|
-
},
|
|
823
|
+
input: inputSchema(["nineSlice", "boolean?"], ["verifyFrames", "boolean?"], ["kept", "boolean?"], ["overdraw", "boolean?"]),
|
|
843
824
|
effect: "cosmetic",
|
|
844
825
|
run: (app, { nineSlice, verifyFrames, kept, overdraw }) => {
|
|
845
826
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -901,10 +882,7 @@ function checkScale(scale) {
|
|
|
901
882
|
const stepCommand = defineCommand({
|
|
902
883
|
id: "game.step",
|
|
903
884
|
title: "Step frames",
|
|
904
|
-
input:
|
|
905
|
-
frames: "number",
|
|
906
|
-
deltaMs: "number?"
|
|
907
|
-
},
|
|
885
|
+
input: inputSchema(["frames", "number"], ["deltaMs", "number?"]),
|
|
908
886
|
effect: "cosmetic",
|
|
909
887
|
run: (app, { frames, deltaMs = FRAME_MS }) => {
|
|
910
888
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -930,7 +908,7 @@ const stepCommand = defineCommand({
|
|
|
930
908
|
const timeScaleCommand = defineCommand({
|
|
931
909
|
id: "game.timeScale",
|
|
932
910
|
title: "Time scale",
|
|
933
|
-
input:
|
|
911
|
+
input: inputSchema(["scale", "number"]),
|
|
934
912
|
effect: "cosmetic",
|
|
935
913
|
run: (app, { scale }) => {
|
|
936
914
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -960,7 +938,7 @@ const timeScaleCommand = defineCommand({
|
|
|
960
938
|
const frameRateCommand = defineCommand({
|
|
961
939
|
id: "game.frameRate",
|
|
962
940
|
title: "Frame rate",
|
|
963
|
-
input:
|
|
941
|
+
input: inputSchema(["fps", "number?"]),
|
|
964
942
|
effect: "cosmetic",
|
|
965
943
|
run: (app, { fps }) => {
|
|
966
944
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_AGENT__ === "undefined" || !__MOKU_GAME_AGENT__)) throw controlRefused();
|
|
@@ -1189,10 +1167,7 @@ function startBookmark(app, save) {
|
|
|
1189
1167
|
const answerCommand = defineCommand({
|
|
1190
1168
|
id: "game.answer",
|
|
1191
1169
|
title: "Answer",
|
|
1192
|
-
input:
|
|
1193
|
-
intent: "string",
|
|
1194
|
-
payload: "json?"
|
|
1195
|
-
},
|
|
1170
|
+
input: inputSchema(["intent", "string"], ["payload", "json?"]),
|
|
1196
1171
|
effect: "route",
|
|
1197
1172
|
run: (app, { intent, payload }) => {
|
|
1198
1173
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -1219,7 +1194,7 @@ const answerCommand = defineCommand({
|
|
|
1219
1194
|
const walkCommand = defineCommand({
|
|
1220
1195
|
id: "game.walk",
|
|
1221
1196
|
title: "Walk a route",
|
|
1222
|
-
input:
|
|
1197
|
+
input: inputSchema(["route", "json"]),
|
|
1223
1198
|
effect: "route",
|
|
1224
1199
|
run: (app, { route }) => {
|
|
1225
1200
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -1285,10 +1260,7 @@ const bookmarkCommand = defineCommand({
|
|
|
1285
1260
|
const restoreCommand = defineCommand({
|
|
1286
1261
|
id: "game.restore",
|
|
1287
1262
|
title: "Restore",
|
|
1288
|
-
input:
|
|
1289
|
-
bookmark: "json?",
|
|
1290
|
-
repro: "json?"
|
|
1291
|
-
},
|
|
1263
|
+
input: inputSchema(["bookmark", "json?"], ["repro", "json?"]),
|
|
1292
1264
|
effect: "raw",
|
|
1293
1265
|
run: (app, input) => {
|
|
1294
1266
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -1344,7 +1316,7 @@ const saveExportCommand = defineCommand({
|
|
|
1344
1316
|
const saveImportCommand = defineCommand({
|
|
1345
1317
|
id: "game.saveImport",
|
|
1346
1318
|
title: "Import a save",
|
|
1347
|
-
input:
|
|
1319
|
+
input: inputSchema(["save", "json"]),
|
|
1348
1320
|
effect: "raw",
|
|
1349
1321
|
run: async (app, { save }) => {
|
|
1350
1322
|
if ((typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) && (typeof __MOKU_GAME_CONTROL__ === "undefined" || !__MOKU_GAME_CONTROL__)) throw controlRefused();
|
|
@@ -13,6 +13,25 @@ function checkId(kind, id) {
|
|
|
13
13
|
throw new Error(`[game] The ${kind} id "${id}" is not a dotted name.\n Name it like "game.position": camelCase words joined by dots.`);
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
+
* Builds the input schema of a door without an object literal (F77). A literal such as
|
|
17
|
+
* `{ x: "number", y: "number" }` shares V8's hidden shape with the game's points and stores
|
|
18
|
+
* strings where they store numbers: V8 turns the fields of that shape tagged, and every fractional
|
|
19
|
+
* write into any `{ x, y }` then boxes a heap number. An object without a prototype is a
|
|
20
|
+
* dictionary and shares no shape with anything.
|
|
21
|
+
*
|
|
22
|
+
* @param entries - The fields, each `[name, kind]`.
|
|
23
|
+
* @returns The schema, an object without a prototype.
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* inputSchema(["x", "number"], ["y", "number"]); // { x: "number", y: "number" }, no prototype
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
function inputSchema(...entries) {
|
|
30
|
+
const schema = Object.create(null);
|
|
31
|
+
for (const [name, kind] of entries) schema[name] = kind;
|
|
32
|
+
return schema;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
16
35
|
* Declares a source: a read-only view the editor lists, reads and watches. The types flow from
|
|
17
36
|
* the object: the input from `input`, the app from the `read` parameter, the output from its
|
|
18
37
|
* result.
|
|
@@ -199,4 +218,4 @@ function recordCheat(app, id, input, frame) {
|
|
|
199
218
|
sessions.set(app, session);
|
|
200
219
|
}
|
|
201
220
|
//#endregion
|
|
202
|
-
export { readTarget as a, defineSource as c, isProjectionTarget as i, isTainted as n, inputOrEmpty as o, recordCheat as r, defineCommand as s, cheatsOf as t };
|
|
221
|
+
export { readTarget as a, defineSource as c, isProjectionTarget as i, inputSchema as l, isTainted as n, inputOrEmpty as o, recordCheat as r, defineCommand as s, cheatsOf as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as rootPoseOf, H as Shape, R as NineSlice, Y as Layer, j as parentOf, n as drawnRect, s as Box } from "./visual-ClVRMUAi.mjs";
|
|
2
2
|
import { o as notInstalled } from "./dev-BNndV-hU.mjs";
|
|
3
|
-
import { a as readTarget, c as defineSource, n as isTainted, o as inputOrEmpty, t as cheatsOf } from "./session-
|
|
3
|
+
import { a as readTarget, c as defineSource, l as inputSchema, n as isTainted, o as inputOrEmpty, t as cheatsOf } from "./session-DuZfGZWk.mjs";
|
|
4
4
|
//#region src/plugins/flow/doors/read.ts
|
|
5
5
|
/**
|
|
6
6
|
* @file flow/doors — `read` and `watch`, the `/inspect` side. Neither changes the game.
|
|
@@ -117,7 +117,7 @@ const assetsSource = defineSource({
|
|
|
117
117
|
const soundsSource = defineSource({
|
|
118
118
|
id: "game.sounds",
|
|
119
119
|
title: "Sounds",
|
|
120
|
-
input:
|
|
120
|
+
input: inputSchema(["last", "number?"]),
|
|
121
121
|
changes: "frame",
|
|
122
122
|
read: (app, { last }) => {
|
|
123
123
|
if (app.audio === void 0) throw notInstalled("game.sounds", "audioPlugin");
|
|
@@ -283,10 +283,7 @@ const renderSource = defineSource({
|
|
|
283
283
|
const atSource = defineSource({
|
|
284
284
|
id: "game.at",
|
|
285
285
|
title: "Under a point",
|
|
286
|
-
input:
|
|
287
|
-
x: "number",
|
|
288
|
-
y: "number"
|
|
289
|
-
},
|
|
286
|
+
input: inputSchema(["x", "number"], ["y", "number"]),
|
|
290
287
|
changes: "frame",
|
|
291
288
|
read: (app, { x, y }) => {
|
|
292
289
|
const point = app.renderer.viewport.toReference(x, y);
|
|
@@ -516,10 +513,7 @@ function carries(entity, component) {
|
|
|
516
513
|
const entitiesSource = defineSource({
|
|
517
514
|
id: "game.entities",
|
|
518
515
|
title: "Entities",
|
|
519
|
-
input:
|
|
520
|
-
owner: "string?",
|
|
521
|
-
component: "string?"
|
|
522
|
-
},
|
|
516
|
+
input: inputSchema(["owner", "string?"], ["component", "string?"]),
|
|
523
517
|
changes: "frame",
|
|
524
518
|
read: (app, { owner, component }) => app.world.ecs.snapshot().entities.filter((entity) => (owner === void 0 || entity.owner.name === owner) && (component === void 0 || carries(entity, component)))
|
|
525
519
|
});
|
|
@@ -569,7 +563,7 @@ const projectionsSource = defineSource({
|
|
|
569
563
|
const explainSource = defineSource({
|
|
570
564
|
id: "game.explain",
|
|
571
565
|
title: "Entity",
|
|
572
|
-
input:
|
|
566
|
+
input: inputSchema(["entity", "number"]),
|
|
573
567
|
changes: "frame",
|
|
574
568
|
read: (app, { entity }) => {
|
|
575
569
|
const row = app.world.ecs.snapshot().entities.find((candidate) => candidate.id === entity);
|
|
@@ -602,10 +596,7 @@ const explainSource = defineSource({
|
|
|
602
596
|
const diffSource = defineSource({
|
|
603
597
|
id: "game.diff",
|
|
604
598
|
title: "Frame diff",
|
|
605
|
-
input:
|
|
606
|
-
from: "number",
|
|
607
|
-
to: "number"
|
|
608
|
-
},
|
|
599
|
+
input: inputSchema(["from", "number"], ["to", "number"]),
|
|
609
600
|
changes: "frame",
|
|
610
601
|
read: (app, { from, to }) => app.world.ecs.diff(from, to)
|
|
611
602
|
});
|
|
@@ -719,7 +710,7 @@ const positionSource = defineSource({
|
|
|
719
710
|
const historySource = defineSource({
|
|
720
711
|
id: "game.history",
|
|
721
712
|
title: "History",
|
|
722
|
-
input:
|
|
713
|
+
input: inputSchema(["last", "number?"]),
|
|
723
714
|
changes: "edge",
|
|
724
715
|
read: (app, { last }) => {
|
|
725
716
|
const entries = app.flow.history();
|
|
@@ -771,7 +762,7 @@ const cheatsSource = defineSource({
|
|
|
771
762
|
const logSource = defineSource({
|
|
772
763
|
id: "game.log",
|
|
773
764
|
title: "Log",
|
|
774
|
-
input:
|
|
765
|
+
input: inputSchema(["level", "string?"]),
|
|
775
766
|
changes: "frame",
|
|
776
767
|
read: (app, { level }) => {
|
|
777
768
|
const entries = app.log.trace();
|
|
@@ -8878,7 +8878,7 @@ function schemaOfType(type) {
|
|
|
8878
8878
|
defaults: notJson,
|
|
8879
8879
|
owned
|
|
8880
8880
|
};
|
|
8881
|
-
const fields =
|
|
8881
|
+
const fields = Object.create(null);
|
|
8882
8882
|
for (const [field, value] of Object.entries(defaults)) fields[field] = fieldKind(value);
|
|
8883
8883
|
return {
|
|
8884
8884
|
name,
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $n as FeaturePlugin, Dr as Json, dr as Descriptor, gr as NodeFx, hr as Hint, sr as NodeTable, tr as AnyFlow, xr as FakeClock, yr as ClockSource } from "./types-D27I4Q7b.mjs";
|
|
2
|
-
import { t as createApp } from "./index-
|
|
3
|
-
import { b as saveOf, v as WithGameState, y as memory } from "./types-
|
|
2
|
+
import { t as createApp } from "./index-B2GejbLf.mjs";
|
|
3
|
+
import { b as saveOf, v as WithGameState, y as memory } from "./types-BWRJcZ3n.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-f31cEZ7f.mjs";
|
|
5
5
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
6
6
|
|
package/dist/testing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { en as refuseStart, in as type, m as flattenFeatures, t as createApp, tn as exit } from "./src-
|
|
1
|
+
import { en as refuseStart, in as type, m as flattenFeatures, t as createApp, tn as exit } from "./src-B4JjsuEy.mjs";
|
|
2
2
|
import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-6mazmHK3.mjs";
|
|
4
4
|
import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-Bxxl_mQX.mjs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $ as PixiModule, $n as FeaturePlugin, Dr as Json, Lr as SnapshotOf, Mr as PlayerStateProvider, Nr as ProviderCall, Pr as SaveDoc, Tr as Config, X as Config$2, a as Config$3, d as Manifest, lt as Orientation, n as AssetsIo, tr as AnyFlow, ur as TypeTag, xr as FakeClock, yr as ClockSource, zn as Config$1 } from "./types-D27I4Q7b.mjs";
|
|
2
2
|
import { o as AudioContextLike, s as Config$4 } from "./types-DjQkfbfZ.mjs";
|
|
3
3
|
import { R as I18nApi, U as StringTable, W as TextKey } from "./types-BAp9HdR4.mjs";
|
|
4
|
-
import { St as effectsPlugin, Tt as audioPlugin, ht as PlatformProvider, i as screen, pt as platformPlugin, t as createApp } from "./index-
|
|
4
|
+
import { St as effectsPlugin, Tt as audioPlugin, ht as PlatformProvider, i as screen, pt as platformPlugin, t as createApp } from "./index-B2GejbLf.mjs";
|
|
5
5
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
6
6
|
|
|
7
7
|
//#region src/plugins/model/store/providers/memory.d.ts
|
|
@@ -3,7 +3,7 @@ import { P as AnimApi, r as UiApi } from "./types-DjQkfbfZ.mjs";
|
|
|
3
3
|
import { N as InputApi } from "./types-BAp9HdR4.mjs";
|
|
4
4
|
import { r as Repro } from "./headless-f31cEZ7f.mjs";
|
|
5
5
|
import { a as InputOf, r as ControlApp } from "./types-CgE5L_7f.mjs";
|
|
6
|
-
import { t as commands } from "./commands-
|
|
6
|
+
import { t as commands } from "./commands-BUfZJUx6.mjs";
|
|
7
7
|
|
|
8
8
|
//#region src/visual/types.d.ts
|
|
9
9
|
/** The base commands of the `/control` door, keyed by their short names. */
|
package/dist/visual.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as VisualApp, c as VisualRenderer, d as VisualStart, f as VisualStep, h as VisualTolerance, i as CheckpointResult, l as VisualReport, m as VisualTestResult, n as runVisualTests, o as VisualOptions, p as VisualTest, r as defineVisualTest, s as VisualPage, t as parseVisualArgv, u as VisualSetup } from "./visual-
|
|
1
|
+
import { a as VisualApp, c as VisualRenderer, d as VisualStart, f as VisualStep, h as VisualTolerance, i as CheckpointResult, l as VisualReport, m as VisualTestResult, n as runVisualTests, o as VisualOptions, p as VisualTest, r as defineVisualTest, s as VisualPage, t as parseVisualArgv, u as VisualSetup } from "./visual-f6mtELhG.mjs";
|
|
2
2
|
export { type CheckpointResult, type VisualApp, type VisualOptions, type VisualPage, type VisualRenderer, type VisualReport, type VisualSetup, type VisualStart, type VisualStep, type VisualTest, type VisualTestResult, type VisualTolerance, defineVisualTest, parseVisualArgv, runVisualTests };
|
package/dist/visual.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as read, t as sources } from "./sources-
|
|
2
|
-
import { n as commands, t as run } from "./run-
|
|
1
|
+
import { n as read, t as sources } from "./sources-DM5Zcl4o.mjs";
|
|
2
|
+
import { n as commands, t as run } from "./run-DyL8rl2P.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createBrandConsole } from "@moku-labs/common/cli";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
package/llms.txt
CHANGED
|
@@ -27,7 +27,7 @@ Root exports:
|
|
|
27
27
|
- Class: `SaveUnreadableError`.
|
|
28
28
|
- Plugin instances: `timePlugin`, `lifecyclePlugin`, `modelPlugin`, `clockPlugin`, `flowPlugin`, `worldPlugin`, `rendererPlugin`, `inputPlugin`, `assetsPlugin`, `scenesPlugin`, `animPlugin`, `i18nPlugin`, `textPlugin`, `uiPlugin`, `audioPlugin`, `effectsPlugin`, `platformPlugin`; the list `screen` = `world`, `renderer`, `input`, `assets`, `scenes`, `anim`, `i18n`, `text`, `ui`. `effects`, `audio` and `platform` are opt-in: `plugins: [...screen, effectsPlugin, audioPlugin, platformPlugin]`, `platform` last.
|
|
29
29
|
- Screen helpers from the root: `component`, `tag`, `resource`, `mut`, `system`, `projection`, `Layer`, `Order`, `Exiting`, `Tree`, `Now`, `Transform`, `Sprite`, `NineSlice`, `Shape`, `Parent`, `Display`, `Overlay`, `HudPart`, `sprite`, `Tappable`, `Pressable`, `Draggable`, `DropTarget`, `Swipeable`, `Traceable`, `Touchable`, `Held`, `Hovered`, `PointerOver`, `Pressed`, `Pointer`, `Traced`, `defineBundles`, `load`, `defineScene`.
|
|
30
|
-
- Interface helpers from the root (V3): `defineAnimation`, `sequence`, `parallel`, `stagger`, `tween`, `set`, `wait`, `mark`, `frames`, `sfx`, `haptic`, `use`, `spawn`, `spawned`, `play`, `external`, `defineMotion`, `Animation`, `Frames`, the resource `AnimPlayer`; `tr`, `messageArgument`, `messageDuration`; `Text`, `label`, `defineTextStyles`, `bind`, `Countdown` and the types `BindOptions`, `CountdownValue`, `TextFormat`; `defineComponent`, `popup`, `defineStyle`, `defineTokens`, `resolve`, `Box`, `LocalWrite`, `DebugTrigger`, `ScrollState`; `music`.
|
|
30
|
+
- Interface helpers from the root (V3): `defineAnimation`, `sequence`, `parallel`, `stagger`, `tween`, `set`, `wait`, `mark`, `frames`, `sfx`, `haptic`, `use`, `spawn`, `spawned`, `play`, `external`, `defineMotion`, `Animation`, `Frames`, the resource `AnimPlayer`; `tr`, `messageArgument`, `messageDuration`; `Text`, `label`, `defineTextStyles`, `bind`, `Countdown` and the types `BindOptions`, `CountdownValue`, `TextFormat`; `defineComponent`, `popup`, `defineStyle`, `defineTokens`, `resolve`, `Box`, `LocalWrite`, `DebugTrigger`, `ScrollState`; `music`. Also `stopSfx(id, { fadeMs? })` (ends a named sound, see audio) and `cubicBezier(x1, y1, x2, y2)` (a CSS-style easing curve for `tween`'s `ease`).
|
|
31
31
|
- Effects helpers from the root (V5): `defineEmitter`, `Emitter`, `defineFilter`, `Glow`, `Outline`, `Blur`, `ColorMatrix`, `Noise`, `Displacement`, `Alpha`.
|
|
32
32
|
- Platform from the root (V6): the types `PlatformProvider`, `BackResult`, `HapticKind` and the frozen list `HAPTIC_KINDS`.
|
|
33
33
|
- `defineGame<Types>()` returns, typed by the game's `player`, `session`, `assets`, `bundles`, `scenes`, `strings` and `textStyles`: `defineNode`, `defineFlow`, `defineFeature`, `projection`, `sprite`, `Sprite`, `NineSlice`, `defineBundles`, `load`, `defineScene`, `defineAnimation`, `frames`, `sfx`, `play`, `tr`, `label`, `defineTextStyles`, `defineComponent`, `defineStyle`, `defineTokens`, `popup`, `music`, `Frames`, `defineEmitter`, `Emitter`, `Displacement`, and `system` (its `ctx.snapshot` typed by `player` and `session`), `volumes` (the `audio` config's reader of the typed player), `key` (string keys from data, below). `Types` is `{ player; session; assets: string; bundles?: string; scenes?: string; strings: Record<string, unknown>; textStyles?: string; emitters?: string }`.
|
|
@@ -457,7 +457,7 @@ Registered in this order: `time`, `lifecycle`, `model`, `clock`, `flow`; then th
|
|
|
457
457
|
|
|
458
458
|
The single `requestAnimationFrame` loop. Six phases in this order: `input`, `animate`, `layout`, `sync`, `signals`, `render`.
|
|
459
459
|
- API: `onFrame(phase, callback): () => void`, `snapshot(): Readonly<Time>`, `setScale(scale)`, `pause()`, `resume()`, `isPaused()`, `isRunning()`, `step(deltaMs)`, `wake()`, and for an agent build (dev pages and `--debug` builds) `measure(listener): () => void` (every frame's `FrameMeasure`: gap, skipped ticks, the six phase durations, work, `rateMs`), `agentClock()` (the page clock, `undefined` without the flag) and `chargeAgent(ms)` (for engine plugins: the editor's own work left out of a frame). Every build: `rate(): Readonly<Time.FrameRate>` (`{ fps, mode, reason, displayHz, ladder, thermal }`, one frozen object until it changes), `setRate(choice: "auto" | 30 | 60 | 120)` (a number forces the cap, never above `maxFps`; `"auto"` gives it back; answers `rate()`), and for engine plugins `frameDrawn()` and `frameProbed()` (the renderer reports a drawn frame and a warm-up frame).
|
|
460
|
-
- Adaptive frame rate: `time: { maxFps: 120, adaptive: { floor: 60 } }` runs at the highest divisor of the display rate at or below `maxFps` (120 on a 120 Hz panel, 60 on a 60 Hz one, 72 on 144 Hz), drops one step when at least `max(8, 10 %)` of the last second's drawn intervals came late, returns one step after the dwell (5 s, doubling up to 120 s after a failed return) with 90 steady drawn frames in 3 s, never below `floor`; thermal `moderate` drops a step, `severe` to the floor. Only drawn frames count. Every change emits `time:rate` (`Time.RateChange`: `from`, `to`, `reason`, `mode`, `displayHz`, `thermal`, `window`, `dwellMs`) and logs `time: frame rate`. Off by default, in a headless app and on a fake clock.
|
|
460
|
+
- Adaptive frame rate: `time: { maxFps: 120, adaptive: { floor: 60 } }` runs at the highest divisor of the display rate at or below `maxFps` (120 on a 120 Hz panel, 60 on a 60 Hz one, 72 on 144 Hz), drops one step when at least `max(8, 10 %)` of the last second's drawn intervals came late, returns one step after the dwell (5 s, doubling up to 120 s after a failed return) with 90 steady drawn frames in 3 s, never below `floor`; thermal `moderate` drops a step, `severe` to the floor. Only drawn frames count. Every change emits `time:rate` (`Time.RateChange`: `from`, `to`, `reason`, `mode`, `displayHz`, `thermal`, `window`, `dwellMs`) and logs `time: frame rate`. Off by default, in a headless app and on a fake clock. The render scale it may lower first is `pluginConfigs.renderer.adaptiveScale`, of type `AdaptiveScale` (`{ floor: 0.75, devices: "phone" }`).
|
|
461
461
|
- Native frame rate: on a page with `__MOKU_NATIVE__` of version 1, `time` asks the panel for the loop's rate at start and on every change, and hands it back at stop, every build; with `adaptive` the answer's `maxHz` is the display rate. In an agent build or with `adaptive` its one `moku-native:thermal` listener emits `time:thermal` with `Time.ThermalReading` (`{ status, headroom, at, android }`).
|
|
462
462
|
- `Time` is `{ delta, elapsed, scale, frame, idle }` in scaled milliseconds.
|
|
463
463
|
- Idle cap: after `idleAfterMs` unscaled milliseconds without a `wake()` the loop runs at `idleFps` and `snapshot().idle` is true. `wake()` lifts it at once; `input`, `anim`, `flow`, `assets`, `scenes`, `text` and `ui` call it. `step(deltaMs)` is never capped.
|
|
@@ -495,7 +495,7 @@ Trusted time as an input. Monotonic `now()` and one `elapsed` signal at the next
|
|
|
495
495
|
### debug (Micro, no dependencies, no events)
|
|
496
496
|
|
|
497
497
|
The editor's overlay from the game, in every app. The plugin name `debug` is reserved.
|
|
498
|
-
- API: `app.debug.overlay.open({ mode?: "pill" | "card" })` (the card by default), `close()`, `toggle()` (hidden and the last visible mode), `isOpen()`. Each reads `globalThis.__MOKU_GAME_OVERLAY__` (set by the editor's page agent) at call time, else the 0.10 `editor.overlay`, and answers `true` when an overlay took the call; without the agent flag (a release build, a test) every member is a no-op answering `false`. A throwing channel logs `debug:overlay-failed`.
|
|
498
|
+
- API: `app.debug.overlay.open({ mode?: "pill" | "card" })` (the card by default), `close()`, `toggle()` (hidden and the last visible mode), `isOpen()`. Each reads `globalThis.__MOKU_GAME_OVERLAY__` (set by the editor's page agent) at call time, else the 0.10 `editor.overlay`, and answers `true` when an overlay took the call; without the agent flag (a release build, a test) every member is a no-op answering `false`. A throwing channel logs `debug:overlay-failed`. The plugin instance is `debugPlugin`; it is always registered, a game never lists it.
|
|
499
499
|
|
|
500
500
|
### flow (Very Complex, depends on time, lifecycle, model, clock)
|
|
501
501
|
|
|
@@ -510,7 +510,7 @@ The graph. Modules `runner`, `gate`, `inbox`, `fx`, `features`. Runner methods s
|
|
|
510
510
|
- After a rollback (a node failed) a view of a projection that the node moved and that still stands off its rest pose is settled, also when its item did not change. Ui elements are not settled by a rollback, and a timeline the failed node started without `await` runs on.
|
|
511
511
|
- A loop adds its sway on top of the value under it. The world compares that value with the rest pose, so a looping view that stands at home is never settled, and one a node moved is brought home while its loop runs on. A custom tween driver may report what its additive tracks add with the optional `offsetsOf(entity, component)`; without it the stored value is compared as it stands.
|
|
512
512
|
- The `loop` hook of a view runs while the world is live and `anim` is installed: a view that entered on a load, a mount or a restore gets its loop from the next live frame. `anim.finishAll()` ends it; the next flush of the world (a load, a restore, a commit in a paused or fast world) owes it again.
|
|
513
|
-
- For a JSX screen ui compares the description prop by prop, by value: inline styles are fine, an equal description costs nothing (no style pass, no layout, no write), hooks stay built once (a function compares by identity). A style object changed in place is not seen: build a new one.
|
|
513
|
+
- For a JSX screen ui compares the description prop by prop, by value: inline styles are fine, an equal description costs nothing (no style pass, no layout, no write), hooks stay built once (a function compares by identity). A style object changed in place is not seen: build a new one. One node of a description, as the JSX runtime builds it, is a `DescriptionNode`.
|
|
514
514
|
- A projection may build a new item object on every commit. A view whose components did not change keeps its running motions; only a real component change cancels them. No frozen item tables are needed.
|
|
515
515
|
- After a `restore` or a load the picture is the one of the restored state, whatever played before: every view of a mounted projection stands on its rest pose, its `loop` starts again on the next live frame and no other motion runs, and every ui root is built again through the mount path, so `enter` hooks run and a loop starts as after a fresh mount. Scroll offsets, local state, hover and focus start anew. Look an element up again with `ui.find(key)` after a restore. A rest node names the scene it is shown on (`scene: "splash"`): a restore into a node without `scene` keeps the mounted scene.
|
|
516
516
|
- `restore` of a rest node resolves when the node is entered. `restore` of a transit node runs it again from its start, so its effects before the gate play again, and resolves once its gate is open. The open gate is not the draw: the popup shows on the next frame. `restore` also resolves when the loop ends before the bookmark was entered, after a stop or a fatal error, and nothing is entered then.
|
|
@@ -520,9 +520,9 @@ The graph. Modules `runner`, `gate`, `inbox`, `fx`, `features`. Runner methods s
|
|
|
520
520
|
### Screen plugins (V2, built)
|
|
521
521
|
|
|
522
522
|
`world`, `renderer`, `input`, `assets`, `scenes`. Each has a README at `src/plugins/<name>/README.md`; the root README lists their APIs, events and config. Rendering: WebGPU preferred, with Pixi's WebGL fallback.
|
|
523
|
-
- `app.scenes`: `current()` the mounted scene id, `expect(id)` the scene the next node without its own `scene` mounts, a rest node or a transit node in live mode (the restore door calls it; an unknown id throws). An `over` node takes it the same way, also over another mounted scene.
|
|
523
|
+
- `app.scenes`: `current()` the mounted scene id, `expect(id)` the scene the next node without its own `scene` mounts, a rest node or a transit node in live mode (the restore door calls it; an unknown id throws). An `over` node takes it the same way, also over another mounted scene. A live switch, before it builds the scene, warms the bundles the scene names (`assets.warm`): their textures go to the GPU `renderer.uploads` a drawn frame while the old scene is still up, so the first frame of the new scene uploads none of them; textures already there are not waited for, and a fast walk or a headless app never waits. A bundle the scene does not name (a `core` bundle of portraits the board shows) is not warmed: name it in the scene's `bundles` or call `app.assets.warm`. Then, with a drawing renderer, the next scene is built aside: its logic runs in one block, the renderer makes its Pixi views over the next frames off the stage in a budget per frame, config `scenes.buildMs: number | "auto"` (default `"auto"`, half the frame interval: 8.33 ms at 60 Hz, 4.17 ms at 120 Hz; `0` throws), and it is swapped in one frame. Until the swap `current()` answers the old scene, nothing of the new one is drawn, hit or found by `ui.find`, its `enter` motions wait and the gate stays closed, so the first tap lands on a complete scene; `scenes:changed` is emitted at the swap. A fast walk, a world that is not live and a headless app mount in one block as before.
|
|
524
524
|
- `Shape({ kind, w, h, fill, fillAlpha, alpha, radius, stroke, strokeWidth, dash, clip, sweep?, cap? })` (`kind: "rect"`; `sweep` and `cap` are optional, `1` and `"round"` when left out; only an arc reads them; a rectangle or a triangle ignores them, also when an earlier arc left them on the `Shape`): a rounded rectangle, `kind: "triangle"` (fills its box pointing right) or `kind: "arc"`: a stroke on the circle inscribed in the box (`min(w, h) − strokeWidth` across, centred) from 12 o'clock clockwise over `sweep` (0..1, clamped; 0 draws nothing, 1 a closed ring), ended by `cap` (`"round" | "butt"`); an arc draws no fill and ignores `radius` and `dash`. The path is built again only when a field changes: a still arc costs nothing a frame. `Shape({ kind: "arc", w: 28, h: 28, stroke: 0xc8a15a, strokeWidth: 2.2, sweep: 0.42 })` is a slot timer's ring with 42 % left.
|
|
525
|
-
- Overlays: `Overlay({ dim, dimColor, cover, hud, fade, hold })` on the root of an overlay (in `components`) keeps everything drawn before it as one picture, retaken in the frame anything in it changes, and with `cover: "opaque"` draws none of it once landed at alpha 1; `hold: true` (default `false`) holds the endless loops under it while it stands, as under a cover or a blurred picture (their phase follows time), so a dimmed sheet over a sharp scene draws no frame at rest; the engine draws the dim (`dim × level`, right under the root); the level follows the root's own enter and exit motion, `fade` (250 ms) only when it has none; level and landing are read through `app.renderer.sync.debug.overlays()`. A `backdrop: true` filter inside the kept range runs no pass while the picture stands (its look is in the picture) and is drawn again in the frame the overlay is gone.
|
|
525
|
+
- Overlays: `Overlay({ dim, dimColor, cover, hud, fade, hold })` on the root of an overlay (in `components`) keeps everything drawn before it as one picture, retaken in the frame anything in it changes, and with `cover: "opaque"` draws none of it once landed at alpha 1; `hold: true` (default `false`) holds the endless loops under it while it stands, as under a cover or a blurred picture (their phase follows time), so a dimmed sheet over a sharp scene draws no frame at rest; the engine draws the dim (`dim × level`, right under the root); the level follows the root's own enter and exit motion, `fade` (250 ms) only when it has none; level and landing are read through `app.renderer.sync.debug.overlays()`. A `backdrop: true` filter inside the kept range runs no pass while the picture stands (its look is in the picture) and is drawn again in the frame the overlay is gone. Types: `OverlayValue` (the component's value) and `HudPartValue` (a part of the HUD an overlay keeps shown or lets fade).
|
|
526
526
|
- HUD: a scene layer `{ above: "overlays" }` is the HUD layer, drawn above every overlay and never in a picture; a scene with a HUD layer and no `ui` gets `ui` right under it. Its roots never take the keyboard: Escape and the Back press reach the top sheet under it. `HudPart({ key })` tags a HUD view; an overlay's `hud` (`"all"`, `"none"` or keys) names the parts that stay shown, the others fade with its level and take no tap. Keys are typed by `defineGame<{ …, hud: "energy" | "gems" }>()`.
|
|
527
527
|
- Endless loops of views under an opaque or blurred overlay write nothing (`renderer.sync.loopsHeld(entity)`, the seam anim asks before an endless loop writes); their phase follows time.
|
|
528
528
|
- A scene names bundles on top of its `bundle` from the committed state: `defineScene("ward", { bundle: "episodes-kit", bundles: ({ session }) => [session.episode], layers: {}, projections: [wardRoom] })`. `bundles` is read each time a node enters the scene, and every way in (a live entry, a restore, the `safeNode` recovery) waits for all of them before the scene is mounted and the node's gate opens. The keys are `BundleKey`s of `generated/assets.ts`.
|
|
@@ -536,13 +536,14 @@ The graph. Modules `runner`, `gate`, `inbox`, `fx`, `features`. Runner methods s
|
|
|
536
536
|
- `Draggable({ payload, carry?, aim? })`: `aim: { x, y }`, a point of the view in its own units, moves the hover and the drop lookup from the finger to that point of the view in the hand; `null` (default) is the finger.
|
|
537
537
|
- `pluginConfigs.renderer.onDemand: true` draws a frame only when something visible changed (a written view, a filter value, a resize, a wake, a capture); `app.renderer.stats().drawn` is the frames drawn per second (`fps` without it); a game that writes into its own `Display` object calls `app.renderer.invalidate(entity)` before the write; `renderer.sync.debug.verifyFrames(true)` (dev/debug) checks skipped frames by pixels and logs `renderer:missed-frame`; a dev build warns `renderer:missed-mark` for a write without the call.
|
|
538
538
|
- `app.renderer.stats()` adds `textureMbSplit: { art, targets, kept }` (MiB). `app.renderer.host.resolution()` is the resolution drawn at: `override ?? min(devicePixelRatio, maxResolution)`; `maxResolution` is a number (default 2), a change of `devicePixelRatio` is followed from the next frame, and `app.renderer.monitor.setResolution(n | undefined)` overrides it in every build, the way to apply a player's graphics setting from an effect (0.5 to 4, else a `RangeError`).
|
|
539
|
-
- `app.renderer.monitor` (agent builds; nothing otherwise): `stream(listener)` the performance log, one frozen JSON line at a time (`PerfLogLine`, `v` = `PERF_LOG_VERSION` = 1, `t` page epoch ms, `build`): `header`, `startup`, a `sample` a second, `spike` (a frame over its budget, with its passes, GPU time, systems, compiles, filters per kind, long frames), `longFrame`, `event`, `mark`, `thermal`; `frames()` the frame ring (typed-array columns, `read(into, cursor)` copies without allocating; `frameAt(ring, age)` gives one record); `mark(label)`; `event(name, detail?)`; `beginAgent()`/`endAgent()` for engine plugins. Config `renderer.monitor: { budgetMs: "rate", frames: 1024 }`: `"rate"` makes the spike budget one frame of the frame's rate (8.33 ms at 120 fps, 16.7 at 60). The engine sends nothing anywhere.
|
|
539
|
+
- `app.renderer.monitor` (agent builds; nothing otherwise): `stream(listener)` the performance log, one frozen JSON line at a time (`PerfLogLine`, `v` = `PERF_LOG_VERSION` = 1, `t` page epoch ms, `build`): `header`, `startup`, a `sample` a second, `spike` (a frame over its budget, with its passes, GPU time, systems, compiles, filters per kind, long frames), `longFrame`, `event`, `mark`, `thermal`; `frames()` the frame ring (typed-array columns, `read(into, cursor)` copies without allocating; `frameAt(ring, age)` gives one record); `mark(label)`; `event(name, detail?)`; `beginAgent()`/`endAgent()` for engine plugins. Config `renderer.monitor: { budgetMs: "rate", frames: 1024 }`: `"rate"` makes the spike budget one frame of the frame's rate (8.33 ms at 120 fps, 16.7 at 60). The engine sends nothing anywhere. The types of the log and of its ring are exported from the root for tools that read it: `PerfLogLine` and its lines `PerfHeaderLine`, `PerfStartupLine`, `PerfSampleLine`, `PerfSpikeLine`, `PerfLongFrameLine`, `PerfEventLine`, `PerfMarkLine`, `PerfThermalLine`, `PerfCollectorLine`, with `PerfEventName`, `PerfChange`, `PerfChangeEntry`, `PerfCause`, `PerfDisplay`, `PerfMeasured`, `LongFrameEntry`, `PassKind`, `PassRecord`, `ProblemRule`, `ShaderWhat`, `OverlayWhat`, `OverlayEventDetail`, `PoolTrimDetail`, `WarmDetail`; the ring `FrameRing`, `FrameRecord`, `FrameColumns`, `FrameReadout`, `FrameReadResult`; the sections `MonitorSections`, `MonitorCounts`, `MonitorConfig`; and the constant lists `PERF_CAUSES` (bit order of the `causes` column), `PERF_GAP_BUCKETS`, `MONITOR_SECTIONS` and `DEMAND_REASONS` (the `reason` column's index into it).
|
|
540
540
|
- The telemetry of a debug build (0.15, PerfLog still `v: 1`, every field additive): the header carries `app: { id }` (`__MOKU_GAME_APP__`, `"com.mokulabs.timber.debug"` in a native debug build, else `null`) and `debug: { overdraw }`. The pass ring (`frames().passes`) gains `owner` (the entity whose filter drew the pass, 0 none), `kind2` (the filter kind, 1-based: `frames().kindNames[kind2 - 1]`, 0 none), `drawsAt` (the frame's draws when the pass began; WebGPU), `format` and `resolution` of its target; `frames().systemNames` names `sysIdx` (a new array when a system registers). A spike's `passes[]` add `owner`, `view` (the owner's view label), `filter`, `draws`, `format`, `resolution`, `kept`. Root exports `PASS_KINDS` (`passes.kind` by index), `SHADER_WHATS`, `PROBLEM_RULES`, types `ShaderEventDetail`, `ProblemEventDetail`, `PerfCounts`. Event `shader` `{ what: "compile" | "module", label, ms, frame, boot, during: { pass, filter, owner, view } }`, one per pipeline or shader module, written at the flush, boot compiles included (`boot: true`); the old `compile { frame, count }` stays. Event `problem` once per crossing, judged once a second: `filter-still` (a filtered view the kept cache does not keep stood still `stillFrames` drawn frames, filtered in every one over `stillMpx`; `reason: "budget" | "not-eligible"`), `target-churn` (render targets made and dropped `churnPerSecond` a second for `churnSeconds`, or made while idle, or within `churnAfterTrimMs` after a pool trim; `reason: "rate" | "idle" | "after-trim"`), `retakes` (a kept view taken again 3 times in 2 s; `value` per second); `{ rule, cleared: true, owner, view }` when it stops. Thresholds are flat keys of `renderer.monitor`: `stillFrames: 60, stillMpx: 0.25, churnPerSecond: 4, churnSeconds: 3, churnAfterTrimMs: 1000`. A `sample` adds `counts: { entities, views, timers, frameListeners, clockListeners, …registered }` (`timers` = `clock.pending()`; input registers `inputListeners`) and `targets: { created, destroyed }` (WebGPU, else `null`); `stats().counts` reads the same. `monitor.counts.register(name, read)` adds a count (agent builds; at most 16, the 17th throws `[game] Monitor count table is full (16).`; the renderer's `onStop` drops them). Event `debug { overdraw }` marks the overdraw switch. The editor's collector writes `telemetry` and `gap` lines into its copy of a log (`PerfTelemetryLine`, `PerfGapLine`); the engine never does.
|
|
541
541
|
- Overdraw heat map (dev and debug builds): `app.renderer.sync.debug.overdraw(true)` (or `game.debug { overdraw: true }`) draws every frame so a pixel's brightness counts the layers drawn there: 1/16 white a layer, white at sixteen. While on, every frame is drawn (also with `onDemand`), kept pictures draw live and filters are off; only the stage pass changes, the tree between frames stays the game's, and off draws the game again from the next frame. Texels a texture leaves transparent count nothing.
|
|
542
542
|
- `app.renderer.viewport.size()` answers one frozen object, replaced only when the frame changes (a resize, a rotation, new insets, a new scale): compare frames with `===`; a write into it throws a `TypeError`.
|
|
543
543
|
- `pluginConfigs.renderer.warm` (default `1`, 0 to 16) is the pipeline warm-up: while a game loads, each drawn frame first draws that many invisible probes (sprites, graphics, text, particles, every filter kind and stage `effects` registers, on the canvas and on a texture, with and without a clip), wiped by the stage pass, so no screen creates a GPU pipeline in the frame it opens in; `0` turns it off. `app.renderer.sync.filters.warm(filter)` warms a game's own filter (answers `true` once drawn). An agent build writes a `warm` event `{ draws }` when the queue empties.
|
|
544
|
-
- `defineFilter(id, { area: value => [x, y, width, height] })` declares the box, in the entity's own units, outside of which the filter draws nothing: Pixi renders and fills only that box (a lens over a full-screen cover fills its disc, not the screen). The view gets the union of its enabled filters' areas, none when an enabled filter declares none (`renderer.sync.filters.area(entity, area)`). The area also clips the view's own children: Pixi draws nothing of the view outside it, so a shadow or a badge that overhangs the box is cut; make the box hold them. The full-screen filter budget and the kept-picture budget count a view with an area by that area, not by its box. Distance-field text uses device pixels for its edge: sharper at a resolution above 1.
|
|
545
|
-
- `pluginConfigs.renderer.poolTrim` (default `{ restMs: 1000, aboveMb: 16 }`) gives back the idle render targets Pixi's texture pool keeps, strictly between frames: after `restMs` of a still screen (`onDemand`), `restMs` after a scene change (each when the targets grew by `aboveMb` MiB), and on a pause (whatever grew); `false` keeps them. `stats().textureMbSplit.targets` shows the drop; an agent build writes a `pool-trim` event `{ reason, freedMb }`.
|
|
544
|
+
- `defineFilter(id, { area: value => [x, y, width, height] })` declares the box, in the entity's own units, outside of which the filter draws nothing: Pixi renders and fills only that box (a lens over a full-screen cover fills its disc, not the screen). The view gets the union of its enabled filters' areas, none when an enabled filter declares none (`renderer.sync.filters.area(entity, area)`). The area also clips the view's own children: Pixi draws nothing of the view outside it, so a shadow or a badge that overhangs the box is cut; make the box hold them. The full-screen filter budget and the kept-picture budget count a view with an area by that area, not by its box. Distance-field text uses device pixels for its edge: sharper at a resolution above 1. The type of that box is `FilterArea`.
|
|
545
|
+
- `pluginConfigs.renderer.poolTrim` (default `{ restMs: 1000, aboveMb: 16 }`) gives back the idle render targets Pixi's texture pool keeps, strictly between frames: after `restMs` of a still screen (`onDemand`), `restMs` after a scene change (each when the targets grew by `aboveMb` MiB), and on a pause (whatever grew); `false` keeps them. `stats().textureMbSplit.targets` shows the drop; an agent build writes a `pool-trim` event `{ reason, freedMb }`. Its type is `PoolTrim`.
|
|
546
|
+
- `blend` on `Sprite` and `NineSlice` (optional, absent by default, type `SpriteBlend`): `"screen"` lightens what is under the view (CSS `mix-blend-mode: screen` on a dark background), `"add"` adds its colours (brighter), `"normal"` covers by alpha as without the field. Any other string draws normally and warns `renderer:blend-unknown` once. It goes on the view itself, so a glow's children draw normally; both are Pixi's native batch blends, no filter and no pass, and each switch between blends in draw order costs one draw call. In `ui`, `style.blend` on an `image`, an `icon` or a nine-slice style writes it (`style={{ blend: "screen" }}` for a soft glow, `"add"` for a spark); an element that never blended carries no `blend` field, so describe and saves stay as they were.
|
|
546
547
|
- `app.renderer.viewport.size().safeArea` is read from four CSS custom properties on the page, `--moku-safe-top`, `--moku-safe-right`, `--moku-safe-bottom`, `--moku-safe-left`, each falling back to `env(safe-area-inset-*, 0px)`. Any CSS length works (`max()`, `calc()`, `env()`); a negative one counts as 0. A change of a property or of the page's insets, and the window event `moku-native:insets`, is laid out at the next frame. There is no `setInsets`: set the properties, e.g. `:root { --moku-safe-top: max(env(safe-area-inset-top, 0px), 24px); }`.
|
|
547
548
|
|
|
548
549
|
### Interface plugins (V3, built)
|
|
@@ -556,7 +557,7 @@ A screen is a projection whose `view` returns JSX. The game's `tsconfig.json` se
|
|
|
556
557
|
- Keys that come from data: `I18n.TextKey<Strings>` is the keys of the generated `Strings` without parameters (nothing new is generated). A data table types its keys `TextKey` or builds them with the kit's `key("board.hint.red")`; the kit's `tr` never takes a plain `string`. A key read back from a save is checked where the app is (an effect handler, app or page code, loading a save) with one `isKey(value)`: `defineGameApp({ ..., strings: type<Strings>() })` types the game's `app.i18n`, so a true `app.i18n.isKey(value)` narrows the value to `TextKey`; `ctx.require(i18nPlugin).isKey(value)` in a plugin narrows to `string`. `app.i18n.isKey(value)` answers true for a key of the loaded tables of the current locale or the fallback, and for the `<feature>.` prefix of a sub-feature whose strings are not loaded yet; a key that takes parameters answers true too.
|
|
557
558
|
- Text: `Text` component, `label({ text, style, at, anchor? })` for board text in a projection view, `defineTextStyles({ "hud.digits": { font, size, fill, bold?, italic?, stroke?, strokeWidth?, letterSpacing?, align?, wrap? (a width, "none" or "box": wrap at the laid-out width of its ui element), digits? } })` under the feature's `textStyles` key. Tags inside a string: `<b>`, `<i>`, `<color=#rrggbb>`, `<icon=key>`, `\<`, `\n`. Built-in styles `body` and `digits` from config `fonts: { body: "ui.font-body", digits: "ui.font-digits" }`. `app.text.measure(content, style, width?)` gives the same numbers in a browser and in Bun. `app.text.replaceStyles(styles)` is the dev hot swap of a saved `defineTextStyles` value.
|
|
558
559
|
- Animation is data: `defineAnimation(id, { slots: { name: type<Anim.Target>() }, build: (slots, { at }) => Step })`. Steps: `sequence(...)`, `parallel(...)`, `stagger(items, ms, item => Step)`, `tween(target, Component, to, { ms, ease?, delayMs?, additive?, space?, reduced? })`, `set(target, Component, patch)`, `wait(ms)`, `mark(name)`, `frames(target, { keys, fps, loop? })`, `sfx(key, { bus? })`, `haptic(kind)`, `use(animation, slots, tools?)`, `spawn` (a temporary entity, flying coins, that the timeline despawns when it ends; see the anim README). `Frames({ keys, fps, loop, playing })` is a component that walks a sprite through its textures for the entity's whole life. A target is `{ projection, key }` or an entity. A timeline resolves each `{ projection, key }` target once, when it starts: every step writes the view that held the key then, also after a commit removed it and while its exit plays, until it despawns; a view spawned again under the same key is not followed, and a key nothing held at the start is looked up at its step. `reduced: "keep"` (on a `tween` step, `transition` and `loop` of `defineMotion`, `TweenOptions`, `RestOptions`) plays a track as written under reduced motion, a fade for one; the default `"cut"` lands it at once or holds a loop on its first key. A node plays it with `await fx(play(animation, slots))`; in fast mode it finishes at once. `defineMotion({ states, transition?, on: { enter?, exit?, change? }, when? })` builds the enter, exit and change hooks for a projection or the `motion` prop of a tag; `when: "change"` plays enter and exit only for a commit, so an element that comes or goes with its screen stands at rest and leaves without a motion (default `"always"`). Events `anim:mark` `{ animation, mark }` and `anim:finished` `{ animation }`. `app.anim.replace(definition)` is the dev hot swap: the next `play` builds the new tree. A system cannot `require` a plugin, so it plays through the resource `AnimPlayer`: `res(AnimPlayer).play(animation, slots)` returns the same handle as `app.anim.play`, and the registered animation of `animation.id` wins, so a hot swap reaches the system. Play on a change, never every frame; from phase `input` the tree moves in `animate` of the same frame. Before `anim` starts it throws `[game] AnimPlayer is not ready: anim has not started.` Config `maxTracks: 2000`.
|
|
559
|
-
- Audio is opt-in: `plugins: [...screen, audioPlugin]`. `fx(sfx("orders.complete"))` resolves when the sound started. `await fx(music("board.theme"))` cross-fades; `music(null)` fades out; a scene's `music` key switches the track on `scenes:changed`. Buses `master`, `music`, `sfx`. Volumes come from the committed player: config `volumes: player => (player as Player).settings.audio`, applied on every `model:committed`. `app.audio`: `setVolume(bus, value)`, `volume(bus)`, `mute(bus, on)`, `muted(bus)`, `unlocked()`, `journal()` (the last started sounds, empty unless config `journal` is above 0). Config: `buses: { master: 1, music: 0.6, sfx: 1 }`, `musicFadeMs: 600`, `volumes`, `context`, `journal: 0`, `music: "decode" | "stream"` default `"decode"` (gapless buffer; `"stream"` is an `<audio>` element, less memory, a gap at every loop), `session: "ambient" | "playback" | "auto"` default `"ambient"` (iOS only: ambient mixes with other apps and obeys the silent switch). The context is asked to run at start: where the shell lets audio play (a native webview with the gesture requirement off) `unlocked()` is true with no touch; a browser that wants a gesture unlocks on the first `pointerdown` or `touchend`. Without `audio` every `sfx` and `music` effect resolves `undefined` at once, so the same node runs in a game with no sound.
|
|
560
|
+
- Audio is opt-in: `plugins: [...screen, audioPlugin]`. `fx(sfx("orders.complete"))` resolves when the sound started. `await fx(music("board.theme"))` cross-fades; `music(null)` fades out; a scene's `music` key switches the track on `scenes:changed`. Buses `master`, `music`, `sfx`. Volumes come from the committed player: config `volumes: player => (player as Player).settings.audio`, applied on every `model:committed`. `app.audio`: `setVolume(bus, value)`, `volume(bus)`, `mute(bus, on)`, `muted(bus)`, `unlocked()`, `journal()` (the last started sounds, empty unless config `journal` is above 0). Config: `buses: { master: 1, music: 0.6, sfx: 1 }`, `musicFadeMs: 600`, `volumes`, `context`, `journal: 0`, `music: "decode" | "stream"` default `"decode"` (gapless buffer; `"stream"` is an `<audio>` element, less memory, a gap at every loop), `session: "ambient" | "playback" | "auto"` default `"ambient"` (iOS only: ambient mixes with other apps and obeys the silent switch). The context is asked to run at start: where the shell lets audio play (a native webview with the gesture requirement off) `unlocked()` is true with no touch; a browser that wants a gesture unlocks on the first `pointerdown` or `touchend`. Without `audio` every `sfx` and `music` effect resolves `undefined` at once, so the same node runs in a game with no sound. Named sounds: `sfx(key, { bus?, id?, fadeMs? })` with an `id` plays through its own gain, and the next sound with the same `id` fades the old one out over `fadeMs`, else config `sfxFadeMs` (default `120`, real milliseconds); `fx.start(stopSfx(id, { fadeMs? }))` and `app.audio.stop(id, { fadeMs? })` fade it out and end it (`fadeMs: 0` cuts it); an `id` nothing plays under changes nothing, and a sound of that `id` still decoding never starts. Without `id` an `sfx` plays to its end as before.
|
|
560
561
|
- `app.ui`: `tree()` the live screen as plain data (a text node carries `content`, the words it draws after `tr()` and `bind`; a text field carries `value`), `find(key)` the entity of a keyed element, `fill(key, value)` types into the text field with that `key`, `scroll(key, to)` puts the `scroll` with that `key` at `to` from its start at once, inside `0..max`, its fling or glide stopped (`false` and `ui:scroll-without-scroll` for no live `scroll`, `false` and `ui:scroll-before-solve` for a `scroll` its first solve has not placed yet), `lint()` tap targets under `tapTargetPt` (default `44`), text that overflows in some locale, absolute elements without `reason`. Config: `tapTargetPt: 44`, `breakpoints: { tall: 2, wide: 1.5 }`. `ui` emits only the dev global event `ui:hot-swap`, see "Hot swap".
|
|
561
562
|
|
|
562
563
|
```tsx
|
|
@@ -623,7 +624,7 @@ export const deliver = defineNode({
|
|
|
623
624
|
|
|
624
625
|
Cosmetic rendering extras as data, drawn by `effectsPlugin`: `plugins: [...screen, effectsPlugin]`. Nothing here enters `model`, the journal or a save. Headless it draws nothing. The full reference is `src/plugins/effects/README.md`.
|
|
625
626
|
- Particles: `defineEmitter(id, config)` returns frozen data a feature lists under `emitters`. Required: `textures` (1 to 16 asset keys of one atlas page) and exactly one of `burst` (an integer, emitted once) and `rate` (particles per second while `active`). Optional with defaults: `lifeMs`, `speed`, `angle`, `gravity`, `drag`, `spin`, `shape` (`point`, `circle`, `rect`, `ring`), `scale`, `alpha`, `tint` (each `{ from, to }`), `space` (`"world"` or `"local"`), `prewarmMs`, `maxParticles` (`256`), `blend` (`"normal"` or `"add"`). A mistake throws at definition.
|
|
626
|
-
- The `Emitter({ effect, active })` component on an entity runs an emitter: `generator: item => [Sprite({ texture: "board.generator" }), Emitter({ effect: "fx.steam" })]`. `effect: ""` draws nothing. Particles step in the `animate` phase, so they freeze while paused and a fast walk emits nothing. Their random source is seeded, never `Math.random` and never the model's rng.
|
|
627
|
+
- The `Emitter({ effect, active })` component on an entity runs an emitter: `generator: item => [Sprite({ texture: "board.generator" }), Emitter({ effect: "fx.steam" })]`. `effect: ""` draws nothing. Particles step in the `animate` phase, so they freeze while paused and a fast walk emits nothing. Their random source is seeded, never `Math.random` and never the model's rng. In `defineGame<Types>()`'s `Emitter`, `effect` takes the game's emitter ids and `""`; `defineEmitter` never takes `""`.
|
|
627
628
|
- Filters: `defineFilter(id, { wgsl, glsl, uniforms?, passes?, padding?, inputs?, fallback? })` returns a component type a feature lists under `filters`. Both bodies are required: `wgsl` is the WGSL `fn mainFragment` and reads a uniform as `fu.amount`; `glsl` is GLSL ES 3.0 `void main()` that sets `finalColor` and reads a uniform as `amount`. A uniform is a number (tweenable), `{ color: 0xffd700 }` or an array of 2 to 4 numbers. Every filter component also has `enabled: true` and `order: 0`. A filter covers the entity's subtree; on a ui element it goes in the `components` prop.
|
|
628
629
|
- Kept pictures: a still filtered view is drawn as one quad from an engine-owned picture, also while it moves (`renderer.keptMb`, default 64; `0` turns it off; `renderer.sync.debug.kept(false)` draws everything live). `defineFilter(id, { cache?: "local" | "placed" | false })`, default `"local"`; a body that reads `uOutputFrame.xy`, `uGlobalFrame`, `gl_FragCoord`, `@builtin(position)` or `uOutputTexture` and declares nothing is drawn live (dev warns `effects:filter-reads-screen`); write `canvasPixel(uv)` for the pixel's canvas position (in WGSL and GLSL) and it is kept; `cache: false` draws it live always. `app.renderer.stats()` measures `renderPasses` on the GPU path in every build and adds `renderPassesMax` (the most of one frame in the last second) and `kept: { pictures, mb, retakes }`.
|
|
629
630
|
- Filter inputs: `inputs: { blur: { stages: [FrostBox4, FrostGauss], chain: (value, { resolution }) => [{ stage, scale, uniforms? }] } }` gives the body `sampleBlur(uv)` in both languages: the last texture of a chain of stages (each a `defineFilter`, drawing alone) drawn from the view's input into pooled textures at `resolution × scale`. The chain runs only when a uniform or the resolution changed; a step naming a stage not in `stages` breaks the filter. The engine counts the passes (leave `passes` out). `fallback: OtherFilter` (a subset of the uniforms) draws when the filter is broken.
|