@moku-labs/game 0.4.2 → 0.4.4
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/{commands-DYO22lzi.d.mts → commands-C83eQ5B9.d.mts} +8 -1
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +2 -2
- package/dist/{dev-B5p9_3fz.mjs → dev-wKLgOw7c.mjs} +8 -5
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +2 -1
- package/dist/inspect.d.mts +5 -2
- package/dist/inspect.mjs +1 -1
- package/dist/{run-C7O77UQR.mjs → run-D_R0oJ6g.mjs} +36 -1
- package/dist/{sources-CTGuY3Fe.mjs → sources-DVWJ8nfr.mjs} +26 -3
- package/dist/testing.d.mts +2 -2
- package/dist/testing.mjs +2 -2
- package/dist/{types-CVUHPvMB.d.mts → types-C-4f2jD_.d.mts} +669 -18
- package/dist/types-w646dMeA.d.mts +648 -0
- package/llms.txt +3 -3
- package/package.json +13 -11
- package/dist/types-BnWH-75b.d.mts +0 -1284
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as Ease, I as AnyComponentValue, Kt as Json, L as ComponentHandle, Nt as TypeTag, P as AnyComponent, Rt as Api, V as Entity, ct as TrackSegment, it as NumericFields, k as Api$2, m as Api$3, rt as MotionHandle, st as TrackOptions, ut as Api$1, vn as Require, z as ComponentType } from "./types-Dy1xB68L.mjs";
|
|
1
|
+
import { $ as Ease, Gt as Events$2, I as AnyComponentValue, K as Owner, Kt as Json, L as ComponentHandle, Nt as TypeTag, P as AnyComponent, Pt as Descriptor, Rt as Api, Ut as Api$5, V as Entity, ct as TrackSegment, et as LayerSort, it as NumericFields, k as Api$2, m as Api$3, o as Events$4, rt as MotionHandle, sn as Events$3, st as TrackOptions, t as Api$4, tt as LayerSpec, ut as Api$1, vn as Require, z as ComponentType } from "./types-Dy1xB68L.mjs";
|
|
2
2
|
import { D as TextApi, H as InputApi, I as I18nApi, c as UiNode, i as Finding, n as ElementChange, o as JsxState, r as ElementMotion, v as StylesState } from "./types-VErbiEXy.mjs";
|
|
3
3
|
import { Log } from "@moku-labs/common/browser";
|
|
4
4
|
import { PluginCtx } from "@moku-labs/core";
|
|
@@ -22,8 +22,8 @@ type LayoutState = {
|
|
|
22
22
|
order: number;
|
|
23
23
|
cleanups: Array<() => void>;
|
|
24
24
|
};
|
|
25
|
-
declare namespace types_d_exports$
|
|
26
|
-
export { Config$
|
|
25
|
+
declare namespace types_d_exports$3 {
|
|
26
|
+
export { Config$3 as Config, Deps$3 as Deps, ElementChange, ElementMotion, Finding, FocusRing, KernelSlice$3 as KernelSlice, State$3 as State, TextInputLook, UiApi, UiCtx, UiNode };
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* The look of the keyboard focus ring: a dashed ring with a solid halo under it, drawn around the
|
|
@@ -96,7 +96,7 @@ type TextInputLook = {
|
|
|
96
96
|
* });
|
|
97
97
|
* ```
|
|
98
98
|
*/
|
|
99
|
-
type Config$
|
|
99
|
+
type Config$3 = {
|
|
100
100
|
/** Smallest tap target `lint()` accepts, in CSS px (points). */tapTargetPt: number; /** `when` flags: `tall` when height / width is at least `tall`, `wide` the other way round. */
|
|
101
101
|
breakpoints: {
|
|
102
102
|
tall: number;
|
|
@@ -116,7 +116,7 @@ type Config$1 = {
|
|
|
116
116
|
/**
|
|
117
117
|
* ui plugin state: one branch per module.
|
|
118
118
|
*/
|
|
119
|
-
type State$
|
|
119
|
+
type State$3 = {
|
|
120
120
|
jsx: JsxState;
|
|
121
121
|
styles: StylesState;
|
|
122
122
|
layout: LayoutState;
|
|
@@ -125,7 +125,7 @@ type State$1 = {
|
|
|
125
125
|
* Resolved dependency APIs. `anim` is not here: its edge is validation only, and its work
|
|
126
126
|
* reaches `ui` through the tween driver behind every `ViewHandle`.
|
|
127
127
|
*/
|
|
128
|
-
type Deps$
|
|
128
|
+
type Deps$3 = {
|
|
129
129
|
time: Api;
|
|
130
130
|
flow: Api$1;
|
|
131
131
|
world: Api$2;
|
|
@@ -139,7 +139,7 @@ type Deps$1 = {
|
|
|
139
139
|
*
|
|
140
140
|
* `ui` owns no event, so `emit` is the kernel's and never called here.
|
|
141
141
|
*/
|
|
142
|
-
type KernelSlice$
|
|
142
|
+
type KernelSlice$3 = PluginCtx<Config$3, State$3> & {
|
|
143
143
|
readonly global: object;
|
|
144
144
|
readonly log: Log.LogApi;
|
|
145
145
|
readonly require: Require;
|
|
@@ -147,8 +147,8 @@ type KernelSlice$1 = PluginCtx<Config$1, State$1> & {
|
|
|
147
147
|
/**
|
|
148
148
|
* Domain context shared by the three modules: the kernel slice plus the resolved deps.
|
|
149
149
|
*/
|
|
150
|
-
type UiCtx = KernelSlice$
|
|
151
|
-
readonly deps: Deps$
|
|
150
|
+
type UiCtx = KernelSlice$3 & {
|
|
151
|
+
readonly deps: Deps$3;
|
|
152
152
|
};
|
|
153
153
|
/**
|
|
154
154
|
* ui plugin API, `app.ui`. The screen is one more projection, so three members read it the way a
|
|
@@ -865,8 +865,8 @@ type RunningTimeline = {
|
|
|
865
865
|
readonly resolve: () => void;
|
|
866
866
|
ended: boolean;
|
|
867
867
|
};
|
|
868
|
-
declare namespace types_d_exports {
|
|
869
|
-
export { AnimApi, AnimCtx, AnimationDefinition, AnimationSpec, AnyAnimationDefinition, BuildTools, Config, Cursor, Deps, ErasedFields, Events, ExternalPlayer, FrameLoop, FramesValue, FxStep, HapticDescriptor, HapticKind, KernelSlice, MarkListener, MotionKeyframe, PlayDescriptor, PlayHandle, Pose, RunningTimeline, SfxDescriptor, SlotRecord, SlotTags, SlotValue, SlotValues, State, Step, StepMotion, Target, TimelineRuntime, Track };
|
|
868
|
+
declare namespace types_d_exports$2 {
|
|
869
|
+
export { AnimApi, AnimCtx, AnimationDefinition, AnimationSpec, AnyAnimationDefinition, BuildTools, Config$2 as Config, Cursor, Deps$2 as Deps, ErasedFields, Events$1 as Events, ExternalPlayer, FrameLoop, FramesValue, FxStep, HapticDescriptor, HapticKind, KernelSlice$2 as KernelSlice, MarkListener, MotionKeyframe, PlayDescriptor, PlayHandle, Pose, RunningTimeline, SfxDescriptor, SlotRecord, SlotTags, SlotValue, SlotValues, State$2 as State, Step, StepMotion, Target, TimelineRuntime, Track };
|
|
870
870
|
}
|
|
871
871
|
/**
|
|
872
872
|
* What a step and a slot are pointed at: the projection key of a live view or of an element a
|
|
@@ -1034,7 +1034,7 @@ type MarkListener = (animation: string, mark: string) => void;
|
|
|
1034
1034
|
* }); // a reached mark("done") step logs { mark: "done" }
|
|
1035
1035
|
* ```
|
|
1036
1036
|
*/
|
|
1037
|
-
type Events = {
|
|
1037
|
+
type Events$1 = {
|
|
1038
1038
|
/** A `mark` step was reached, or jumped by `finish()`. */"anim:mark": {
|
|
1039
1039
|
animation: string;
|
|
1040
1040
|
mark: string;
|
|
@@ -1118,7 +1118,7 @@ type FrameLoop = {
|
|
|
1118
1118
|
* createApp({ plugins: [...screen], pluginConfigs: { anim: { maxTracks: 500, reducedMotion: true } } });
|
|
1119
1119
|
* ```
|
|
1120
1120
|
*/
|
|
1121
|
-
type Config = {
|
|
1121
|
+
type Config$2 = {
|
|
1122
1122
|
/** Dev guard: one warning each time the running track count rises past this number. */maxTracks: number;
|
|
1123
1123
|
/**
|
|
1124
1124
|
* Start value of reduced motion: every track but a loop takes 0 ms and every loop stands on
|
|
@@ -1130,7 +1130,7 @@ type Config = {
|
|
|
1130
1130
|
* anim plugin state: the one track table, the field bookkeeping of the retarget policy and the
|
|
1131
1131
|
* offsets accumulator, the running timelines and the animation registry.
|
|
1132
1132
|
*/
|
|
1133
|
-
type State = {
|
|
1133
|
+
type State$2 = {
|
|
1134
1134
|
/** The one track table. Insertion order is advance order. */tracks: Map<number, Track>; /** Ids of tracks and timelines. */
|
|
1135
1135
|
nextId: number; /** `"<entity>:<component>:<field>"` to the id of the absolute track that drives the field. */
|
|
1136
1136
|
owner: Map<string, number>; /** Per field key, the delta each additive track contributes. */
|
|
@@ -1278,7 +1278,7 @@ type AnimApi = {
|
|
|
1278
1278
|
* of `at` with the pure `rootPoseOf` of `renderer/sync/pose.ts`, and turns the target of a
|
|
1279
1279
|
* `tween` in `space: "root"` local with the pure `localPoseOf` of the same module.
|
|
1280
1280
|
*/
|
|
1281
|
-
type Deps = {
|
|
1281
|
+
type Deps$2 = {
|
|
1282
1282
|
time: Api;
|
|
1283
1283
|
flow: Api$1;
|
|
1284
1284
|
world: Api$2;
|
|
@@ -1290,7 +1290,7 @@ type Deps = {
|
|
|
1290
1290
|
* row 8), so the own events reach the context the kernel hands the factories and `emit` is the
|
|
1291
1291
|
* kernel's own, anim-typed one. No member of the context is cast.
|
|
1292
1292
|
*/
|
|
1293
|
-
type KernelSlice = PluginCtx<Config, State, Events> & {
|
|
1293
|
+
type KernelSlice$2 = PluginCtx<Config$2, State$2, Events$1> & {
|
|
1294
1294
|
readonly global: object;
|
|
1295
1295
|
readonly log: Log.LogApi;
|
|
1296
1296
|
readonly require: Require;
|
|
@@ -1298,8 +1298,659 @@ type KernelSlice = PluginCtx<Config, State, Events> & {
|
|
|
1298
1298
|
/**
|
|
1299
1299
|
* Domain context of the anim plugin: the kernel slice and the three resolved dependencies.
|
|
1300
1300
|
*/
|
|
1301
|
-
type AnimCtx = KernelSlice & {
|
|
1301
|
+
type AnimCtx = KernelSlice$2 & {
|
|
1302
|
+
readonly deps: Deps$2;
|
|
1303
|
+
};
|
|
1304
|
+
declare namespace types_d_exports$1 {
|
|
1305
|
+
export { AnySceneProjection, CheckedProjections, Config$1 as Config, DefineScene, Deps$1 as Deps, Events, KernelSlice$1 as KernelSlice, LayerMap, RunContext, SceneDefinition, SceneLayer, SceneOwner, SceneProjection, SceneSpec, ScenesApi, ScenesCtx, SortRule, State$1 as State, UiLayer };
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* How a layer orders what is drawn in it. The scene's name for the rule `world` stores.
|
|
1309
|
+
*
|
|
1310
|
+
* @example
|
|
1311
|
+
* ```ts
|
|
1312
|
+
* const sort: SortRule = "y";
|
|
1313
|
+
* ```
|
|
1314
|
+
*/
|
|
1315
|
+
type SortRule = LayerSort;
|
|
1316
|
+
/**
|
|
1317
|
+
* What a scene declares about its layers: the key is the layer name, the order of the keys is
|
|
1318
|
+
* draw order, bottom first. An omitted `sort` means `"none"`.
|
|
1319
|
+
*
|
|
1320
|
+
* @example
|
|
1321
|
+
* ```ts
|
|
1322
|
+
* const layers: LayerMap = { background: {}, cells: {}, items: { sort: "y" }, lifted: {} };
|
|
1323
|
+
* ```
|
|
1324
|
+
*/
|
|
1325
|
+
type LayerMap = Record<string, {
|
|
1326
|
+
sort?: SortRule;
|
|
1327
|
+
}>;
|
|
1328
|
+
/**
|
|
1329
|
+
* The name of the layer every scene gets on top of the layers it declared, where popups and the
|
|
1330
|
+
* HUD are mounted. A scene that declares it keeps the place it wrote it in.
|
|
1331
|
+
*
|
|
1332
|
+
* @example
|
|
1333
|
+
* ```ts
|
|
1334
|
+
* const layer: UiLayer = "ui";
|
|
1335
|
+
* ```
|
|
1336
|
+
*/
|
|
1337
|
+
type UiLayer = "ui";
|
|
1338
|
+
/**
|
|
1339
|
+
* The layer names the projections of a scene may use: the keys the scene declared and the
|
|
1340
|
+
* appended `ui`, which is there whether the scene wrote it or not.
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* ```ts
|
|
1344
|
+
* const layer: SceneLayer<{ cells: Record<never, never> }> = "ui"; // or "cells"
|
|
1345
|
+
* ```
|
|
1346
|
+
*/
|
|
1347
|
+
type SceneLayer<Layers extends LayerMap> = (keyof Layers & string) | UiLayer;
|
|
1348
|
+
/**
|
|
1349
|
+
* Any projection as a scene reads it. `projection()` widens `lift` to `string` when the author
|
|
1350
|
+
* declared none, so this is the loosest shape `defineScene` accepts.
|
|
1351
|
+
*
|
|
1352
|
+
* @example
|
|
1353
|
+
* ```ts
|
|
1354
|
+
* const spec: AnySceneProjection = { name: "board.items", layer: "items", lift: "lifted" };
|
|
1355
|
+
* ```
|
|
1356
|
+
*/
|
|
1357
|
+
type AnySceneProjection = {
|
|
1358
|
+
readonly name: string;
|
|
1359
|
+
readonly layer: string;
|
|
1360
|
+
readonly lift?: string;
|
|
1361
|
+
};
|
|
1362
|
+
/**
|
|
1363
|
+
* The three fields of a `ProjectionSpec` a scene reads, with both layers checked against the
|
|
1364
|
+
* layers the scene declares. It is what a wrong `layer` or `lift` is reported against.
|
|
1365
|
+
*
|
|
1366
|
+
* @example
|
|
1367
|
+
* ```ts
|
|
1368
|
+
* const spec: SceneProjection<"items" | "lifted"> = { name: "board.items", layer: "items" };
|
|
1369
|
+
* ```
|
|
1370
|
+
*/
|
|
1371
|
+
type SceneProjection<Layer extends string> = {
|
|
1372
|
+
readonly name: string;
|
|
1373
|
+
readonly layer: Layer;
|
|
1374
|
+
readonly lift?: Layer;
|
|
1375
|
+
};
|
|
1376
|
+
/**
|
|
1377
|
+
* Checks the `lift` of one projection. A projection built without a `lift` carries the widened
|
|
1378
|
+
* `string` of `projection()`, which is the one lift that is always accepted.
|
|
1379
|
+
*/
|
|
1380
|
+
type CheckedLift<Layer extends string, Spec> = Spec extends {
|
|
1381
|
+
readonly lift?: infer Lift;
|
|
1382
|
+
} ? string extends Exclude<Lift, undefined> ? Spec : Exclude<Lift, undefined> extends Layer ? Spec : SceneProjection<Layer> : Spec;
|
|
1383
|
+
/**
|
|
1384
|
+
* Checks one projection of a scene: first its `layer`, then its `lift`. A projection that fails
|
|
1385
|
+
* becomes `SceneProjection<Layer>`, so the compiler prints the layer names it accepts.
|
|
1386
|
+
*/
|
|
1387
|
+
type CheckedProjection<Layer extends string, Spec> = Spec extends {
|
|
1388
|
+
readonly layer: infer Declared;
|
|
1389
|
+
} ? Declared extends Layer ? CheckedLift<Layer, Spec> : SceneProjection<Layer> : SceneProjection<Layer>;
|
|
1390
|
+
/**
|
|
1391
|
+
* Checking type: validates the projections of a scene one by one against its layer names, so the
|
|
1392
|
+
* error sits on the projection that is wrong and not on the whole list.
|
|
1393
|
+
*
|
|
1394
|
+
* @example
|
|
1395
|
+
* ```ts
|
|
1396
|
+
* type Checked = CheckedProjections<"items", readonly [{ name: "board.items"; layer: "items" }]>;
|
|
1397
|
+
* ```
|
|
1398
|
+
*/
|
|
1399
|
+
type CheckedProjections<Layer extends string, List> = { readonly [Index in keyof List]: CheckedProjection<Layer, List[Index]> };
|
|
1400
|
+
/**
|
|
1401
|
+
* What the author passes to `defineScene`. The layer names come from the keys of `layers` plus
|
|
1402
|
+
* the appended `ui`; `NoInfer` keeps `projections` out of that inference, so a wrong name is
|
|
1403
|
+
* reported on the projection and never widens the layer union. `music` is an asset key of the
|
|
1404
|
+
* game, narrowed to its audio keys once the scanner splits them.
|
|
1405
|
+
*
|
|
1406
|
+
* @example
|
|
1407
|
+
* ```ts
|
|
1408
|
+
* const spec: SceneSpec<{ items: Record<never, never> }, readonly [], string, "board"> = {
|
|
1409
|
+
* bundle: "board",
|
|
1410
|
+
* layers: { items: {} },
|
|
1411
|
+
* projections: []
|
|
1412
|
+
* };
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
type SceneSpec<Layers extends LayerMap, Projections extends readonly AnySceneProjection[], Asset extends string, Bundle extends string> = {
|
|
1416
|
+
bundle: Bundle;
|
|
1417
|
+
layers: Layers;
|
|
1418
|
+
projections: Projections & CheckedProjections<NoInfer<SceneLayer<Layers>>, NoInfer<Projections>>;
|
|
1419
|
+
music?: Asset;
|
|
1420
|
+
};
|
|
1421
|
+
/**
|
|
1422
|
+
* The signature of `defineScene` bound to the asset and bundle keys of one game.
|
|
1423
|
+
* `defineGame<Types>()` returns it; the loose export accepts any string.
|
|
1424
|
+
*
|
|
1425
|
+
* @example
|
|
1426
|
+
* ```ts
|
|
1427
|
+
* const defineGameScene: DefineScene<"board.music", "board"> = defineScene;
|
|
1428
|
+
* ```
|
|
1429
|
+
*/
|
|
1430
|
+
type DefineScene<Asset extends string, Bundle extends string> = <Layers extends LayerMap, const Projections extends readonly AnySceneProjection[]>(id: string, scene: SceneSpec<Layers, Projections, Asset, Bundle>) => SceneDefinition;
|
|
1431
|
+
/**
|
|
1432
|
+
* A scene as `defineScene` returns it: plain frozen data, ready for the `scenes` key of a feature.
|
|
1433
|
+
*
|
|
1434
|
+
* @example
|
|
1435
|
+
* ```ts
|
|
1436
|
+
* // What defineScene("board", { bundle: "board", layers: { items: { sort: "y" } }, projections: [] })
|
|
1437
|
+
* // returns: { id: "board", bundle: "board", music: undefined,
|
|
1438
|
+
* // layers: [{ name: "items", sort: "y" }, { name: "ui", sort: "none" }], projections: [] }
|
|
1439
|
+
* ```
|
|
1440
|
+
*/
|
|
1441
|
+
type SceneDefinition = {
|
|
1442
|
+
readonly id: string;
|
|
1443
|
+
readonly bundle: string;
|
|
1444
|
+
readonly music: string | undefined; /** Draw order, bottom first. */
|
|
1445
|
+
readonly layers: readonly LayerSpec[]; /** Names of the projections the scene mounts. */
|
|
1446
|
+
readonly projections: readonly string[];
|
|
1447
|
+
};
|
|
1448
|
+
/**
|
|
1449
|
+
* The one owner every mount of this plugin carries. One is enough: one scene is mounted at a
|
|
1450
|
+
* time, and `unmount` is what flushes.
|
|
1451
|
+
*
|
|
1452
|
+
* @example
|
|
1453
|
+
* ```ts
|
|
1454
|
+
* const owner: SceneOwner = { kind: "plugin", name: "scenes" };
|
|
1455
|
+
* ```
|
|
1456
|
+
*/
|
|
1457
|
+
type SceneOwner = Owner & {
|
|
1458
|
+
kind: "plugin";
|
|
1459
|
+
name: "scenes";
|
|
1460
|
+
};
|
|
1461
|
+
/**
|
|
1462
|
+
* scenes plugin config: none. A scene is data in a feature, and a transition effect is V3 work
|
|
1463
|
+
* of `anim`, so a key here would have no reader.
|
|
1464
|
+
*
|
|
1465
|
+
* @example
|
|
1466
|
+
* ```ts
|
|
1467
|
+
* const config: Config = {};
|
|
1468
|
+
* ```
|
|
1469
|
+
*/
|
|
1470
|
+
type Config$1 = Record<string, never>;
|
|
1471
|
+
/**
|
|
1472
|
+
* scenes plugin state.
|
|
1473
|
+
*/
|
|
1474
|
+
type State$1 = {
|
|
1475
|
+
/** Scene id to its declaration, filled in `onStart` from `flow.features`. */scenes: Map<string, SceneDefinition>; /** Id of the scene that is mounted now. */
|
|
1476
|
+
current: string | undefined; /** Fast mode: the scene a transit node named, applied at the next rest node. */
|
|
1477
|
+
pending: string | undefined;
|
|
1478
|
+
owner: SceneOwner; /** The remover of the `onEnter` callback: set in `onStart`, run in `onStop`. */
|
|
1479
|
+
teardown: (() => void) | undefined;
|
|
1480
|
+
};
|
|
1481
|
+
/**
|
|
1482
|
+
* scenes plugin events.
|
|
1483
|
+
*
|
|
1484
|
+
* @example
|
|
1485
|
+
* ```ts
|
|
1486
|
+
* // A game plugin starts the music of the scene the graph switched to.
|
|
1487
|
+
* createPlugin("music", {
|
|
1488
|
+
* depends: [scenesPlugin],
|
|
1489
|
+
* hooks: ctx => ({ "scenes:changed": ({ music }) => ctx.log.info("scene music", { music }) })
|
|
1490
|
+
* }); // entering the board logs { music: "board.theme" }
|
|
1491
|
+
* ```
|
|
1492
|
+
*/
|
|
1493
|
+
type Events = {
|
|
1494
|
+
/** The mounted scene changed. */"scenes:changed": {
|
|
1495
|
+
from: string | undefined;
|
|
1496
|
+
to: string;
|
|
1497
|
+
music: string | undefined;
|
|
1498
|
+
};
|
|
1499
|
+
};
|
|
1500
|
+
/**
|
|
1501
|
+
* scenes plugin API, `app.scenes`. A scene is switched by the graph, never by a call, so the
|
|
1502
|
+
* plugin answers one question and takes no orders.
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```ts
|
|
1506
|
+
* // A headless test walks from the menu onto the board and asks what is mounted.
|
|
1507
|
+
* await app.flow.walk([{ at: "home", intent: "play" }]);
|
|
1508
|
+
* app.scenes.current(); // "board"
|
|
1509
|
+
* ```
|
|
1510
|
+
*/
|
|
1511
|
+
type ScenesApi = {
|
|
1512
|
+
/**
|
|
1513
|
+
* The id of the mounted scene.
|
|
1514
|
+
*
|
|
1515
|
+
* @returns The scene id, `undefined` before the first switch and after the app stopped.
|
|
1516
|
+
* @example
|
|
1517
|
+
* ```ts
|
|
1518
|
+
* // A dev overlay writes the scene next to the frame counter.
|
|
1519
|
+
* app.scenes.current(); // "board", or undefined while the first bundle still loads
|
|
1520
|
+
* ```
|
|
1521
|
+
*/
|
|
1522
|
+
current(): string | undefined;
|
|
1523
|
+
};
|
|
1524
|
+
/**
|
|
1525
|
+
* Resolved dependency APIs.
|
|
1526
|
+
*/
|
|
1527
|
+
type Deps$1 = {
|
|
1528
|
+
flow: Api$1;
|
|
1529
|
+
world: Api$2;
|
|
1530
|
+
assets: Api$4;
|
|
1531
|
+
time: Api;
|
|
1532
|
+
};
|
|
1533
|
+
/**
|
|
1534
|
+
* What the kernel context offers before the deps are attached.
|
|
1535
|
+
*
|
|
1536
|
+
* `index.ts` writes `events` with an annotated `register` (core spec `14-EVENT-REGISTRATION.md`
|
|
1537
|
+
* row 8), so the own event reaches the context the kernel hands the factories and `emit` is the
|
|
1538
|
+
* kernel's own, scenes-typed one. No member of the context is cast.
|
|
1539
|
+
*/
|
|
1540
|
+
type KernelSlice$1 = PluginCtx<Config$1, State$1, Events> & {
|
|
1541
|
+
readonly global: object;
|
|
1542
|
+
readonly log: Log.LogApi;
|
|
1543
|
+
readonly require: Require;
|
|
1544
|
+
};
|
|
1545
|
+
/**
|
|
1546
|
+
* Domain context shared by the files of the plugin.
|
|
1547
|
+
*/
|
|
1548
|
+
type ScenesCtx = KernelSlice$1 & {
|
|
1549
|
+
readonly deps: Deps$1;
|
|
1550
|
+
};
|
|
1551
|
+
/**
|
|
1552
|
+
* The mode and the abort signal `flow.onEnter` hands every callback.
|
|
1553
|
+
*
|
|
1554
|
+
* @example
|
|
1555
|
+
* ```ts
|
|
1556
|
+
* const run: RunContext = { mode: "live", signal: new AbortController().signal };
|
|
1557
|
+
* ```
|
|
1558
|
+
*/
|
|
1559
|
+
type RunContext = {
|
|
1560
|
+
mode: "live" | "fast";
|
|
1561
|
+
signal: AbortSignal;
|
|
1562
|
+
};
|
|
1563
|
+
declare namespace types_d_exports {
|
|
1564
|
+
export { AudioApi, AudioContextLike, AudioCtx, AudioSessionLike, AudioSessionType, BundleUnloaded, Bus, BusState, Config, Deps, KernelSlice, LifecycleChanged, ModelCommitted, MusicDescriptor, MusicMode, MusicOptions, MusicRequest, MusicSwitch, MusicTrack, RetiringTrack, SceneChanged, SfxRequest, SoundEntry, State, StreamTrack, Volumes };
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* The three volume buses. `master` carries the whole game, `music` the scene track, `sfx` every
|
|
1568
|
+
* sound a node or a timeline fires.
|
|
1569
|
+
*
|
|
1570
|
+
* @example
|
|
1571
|
+
* ```ts
|
|
1572
|
+
* const bus: Bus = "music";
|
|
1573
|
+
* ```
|
|
1574
|
+
*/
|
|
1575
|
+
type Bus = "master" | "music" | "sfx";
|
|
1576
|
+
/**
|
|
1577
|
+
* The part of `AudioContext` the plugin uses. A test passes its own through `config.context`, so
|
|
1578
|
+
* nothing in the unit tests touches a sound card. `state` adds Safari's `"interrupted"`, which a
|
|
1579
|
+
* phone call or the lock screen puts a context into.
|
|
1580
|
+
*
|
|
1581
|
+
* @example
|
|
1582
|
+
* ```ts
|
|
1583
|
+
* // A dev tool builds the engine's context itself and hands it to the plugin.
|
|
1584
|
+
* const context: AudioContextLike = new AudioContext();
|
|
1585
|
+
* createApp({ plugins: [...screen, audioPlugin], pluginConfigs: { audio: { context: () => context } } });
|
|
1586
|
+
* ```
|
|
1587
|
+
*/
|
|
1588
|
+
type AudioContextLike = Pick<AudioContext, "destination" | "currentTime" | "createGain" | "createBufferSource" | "decodeAudioData" | "createMediaElementSource" | "resume" | "close"> & {
|
|
1589
|
+
readonly state: AudioContext["state"] | "interrupted";
|
|
1590
|
+
};
|
|
1591
|
+
/**
|
|
1592
|
+
* What `music` accepts besides the key. An absent `fadeMs` means `config.musicFadeMs` at play time.
|
|
1593
|
+
*
|
|
1594
|
+
* @example
|
|
1595
|
+
* ```ts
|
|
1596
|
+
* const options: MusicOptions = { fadeMs: 200 };
|
|
1597
|
+
* ```
|
|
1598
|
+
*/
|
|
1599
|
+
type MusicOptions = {
|
|
1600
|
+
fadeMs?: number;
|
|
1601
|
+
};
|
|
1602
|
+
/**
|
|
1603
|
+
* `music` bound to the audio asset keys of one game. `defineGame` returns it through `audioFor`;
|
|
1604
|
+
* the loose export accepts any string.
|
|
1605
|
+
*
|
|
1606
|
+
* @example
|
|
1607
|
+
* ```ts
|
|
1608
|
+
* const gameMusic: MusicDescriptor<"board.theme"> = music;
|
|
1609
|
+
* ```
|
|
1610
|
+
*/
|
|
1611
|
+
type MusicDescriptor<Asset extends string> = (key: Asset | null, options?: MusicOptions) => Descriptor;
|
|
1612
|
+
/**
|
|
1613
|
+
* Reads the player's volume choice out of the committed player state. Every bus it names is
|
|
1614
|
+
* applied; the ones it leaves out keep the value they had.
|
|
1615
|
+
*
|
|
1616
|
+
* @example
|
|
1617
|
+
* ```ts
|
|
1618
|
+
* const volumes: Volumes = player => (player as { settings: { audio: { music: number } } }).settings.audio;
|
|
1619
|
+
* ```
|
|
1620
|
+
*/
|
|
1621
|
+
type Volumes = (player: Json) => Partial<Record<Bus, number>>;
|
|
1622
|
+
/**
|
|
1623
|
+
* How a music track is played. `"decode"`: one AudioBuffer per track, gapless, about 58 MB per
|
|
1624
|
+
* 150 s at 48 kHz. `"stream"`: an `<audio>` element on a `blob:` URL of the bytes `assets` holds,
|
|
1625
|
+
* about 12 MB, and a gap at every loop: 5 to 49 ms in Chromium, about 0.4 s in WebKit. A tight
|
|
1626
|
+
* loop keeps `"decode"`; a long track that tolerates a seam takes `"stream"`.
|
|
1627
|
+
*
|
|
1628
|
+
* @example
|
|
1629
|
+
* ```ts
|
|
1630
|
+
* const mode: MusicMode = "stream";
|
|
1631
|
+
* ```
|
|
1632
|
+
*/
|
|
1633
|
+
type MusicMode = "decode" | "stream";
|
|
1634
|
+
/**
|
|
1635
|
+
* What the page asks iOS for. `"ambient"`: mixes with other apps, the silent switch mutes it.
|
|
1636
|
+
* `"playback"`: stops other apps, plays through the switch. `"auto"`: WebKit picks.
|
|
1637
|
+
*
|
|
1638
|
+
* @example
|
|
1639
|
+
* ```ts
|
|
1640
|
+
* const session: AudioSessionType = "playback";
|
|
1641
|
+
* ```
|
|
1642
|
+
*/
|
|
1643
|
+
type AudioSessionType = "ambient" | "playback" | "auto";
|
|
1644
|
+
/**
|
|
1645
|
+
* The part of `navigator.audioSession` the plugin writes. `lib.dom` has no type for it, and only
|
|
1646
|
+
* WebKit has the object at all.
|
|
1647
|
+
*
|
|
1648
|
+
* @example
|
|
1649
|
+
* ```ts
|
|
1650
|
+
* // What Safari answers before the plugin started: no override.
|
|
1651
|
+
* const session: AudioSessionLike = { type: "auto" };
|
|
1652
|
+
* ```
|
|
1653
|
+
*/
|
|
1654
|
+
type AudioSessionLike = {
|
|
1655
|
+
type: string;
|
|
1656
|
+
};
|
|
1657
|
+
/**
|
|
1658
|
+
* One music track played by an element at `music: "stream"`: the element, its source node in the
|
|
1659
|
+
* graph, the track gain every level goes through, and the `blob:` URL the element reads.
|
|
1660
|
+
*
|
|
1661
|
+
* @example
|
|
1662
|
+
* ```ts
|
|
1663
|
+
* // `state.music.stream` once "board.theme" plays at `music: "stream"`.
|
|
1664
|
+
* const { element, url }: StreamTrack = track;
|
|
1665
|
+
* element.loop; // true
|
|
1666
|
+
* url.startsWith("blob:"); // true
|
|
1667
|
+
* ```
|
|
1668
|
+
*/
|
|
1669
|
+
type StreamTrack = {
|
|
1670
|
+
element: HTMLAudioElement;
|
|
1671
|
+
node: MediaElementAudioSourceNode;
|
|
1672
|
+
gain: GainNode;
|
|
1673
|
+
url: string;
|
|
1674
|
+
};
|
|
1675
|
+
/**
|
|
1676
|
+
* A streamed track that fades out. Its timer frees the element when the fade ends: an element has
|
|
1677
|
+
* no `stop(when)` on the context clock.
|
|
1678
|
+
*
|
|
1679
|
+
* @example
|
|
1680
|
+
* ```ts
|
|
1681
|
+
* // A switch at `musicFadeMs: 600` keeps the old track here for 600 ms.
|
|
1682
|
+
* const entry: RetiringTrack = { stream: oldTrack, timer: setTimeout(free, 600) };
|
|
1683
|
+
* ```
|
|
1684
|
+
*/
|
|
1685
|
+
type RetiringTrack = {
|
|
1686
|
+
stream: StreamTrack;
|
|
1687
|
+
timer: ReturnType<typeof setTimeout>;
|
|
1688
|
+
};
|
|
1689
|
+
/**
|
|
1690
|
+
* audio plugin config.
|
|
1691
|
+
*
|
|
1692
|
+
* @example
|
|
1693
|
+
* ```ts
|
|
1694
|
+
* createApp({
|
|
1695
|
+
* plugins: [...screen, audioPlugin],
|
|
1696
|
+
* pluginConfigs: {
|
|
1697
|
+
* audio: { musicFadeMs: 400, music: "stream", session: "playback", volumes: player => player.settings.audio }
|
|
1698
|
+
* }
|
|
1699
|
+
* });
|
|
1700
|
+
* ```
|
|
1701
|
+
*/
|
|
1702
|
+
type Config = {
|
|
1703
|
+
/** Start gain of each bus, 0..1. Overridden per commit when `volumes` is set. */buses: {
|
|
1704
|
+
master: number;
|
|
1705
|
+
music: number;
|
|
1706
|
+
sfx: number;
|
|
1707
|
+
}; /** Cross-fade of a music switch, in real milliseconds of the context clock. */
|
|
1708
|
+
musicFadeMs: number; /** Reads the player's choice from the committed player. `undefined`: the buses stay at `buses`. */
|
|
1709
|
+
volumes: Volumes | undefined; /** Context factory, the test seam. `undefined`: `new AudioContext()` when the global exists, otherwise headless. */
|
|
1710
|
+
context: (() => AudioContextLike) | undefined; /** How many started sounds `journal()` keeps, newest last. `0` turns the journal off. */
|
|
1711
|
+
journal: number; /** How music plays. `"stream"` needs MP3 or AAC: WebM Opus is silent through a media element in WebKit (bug 276813). Sounds always decode. */
|
|
1712
|
+
music: MusicMode; /** Set on `navigator.audioSession.type` in `onStart`, before the context exists. No-op where the API is missing (every Chromium, Firefox). */
|
|
1713
|
+
session: AudioSessionType;
|
|
1714
|
+
};
|
|
1715
|
+
/**
|
|
1716
|
+
* One sound that started: a play of an `sfx` or a music track that began. `at` is the elapsed
|
|
1717
|
+
* game time in milliseconds, `app.time.snapshot().elapsed` at the start.
|
|
1718
|
+
*
|
|
1719
|
+
* @example
|
|
1720
|
+
* ```ts
|
|
1721
|
+
* const entry: SoundEntry = { key: "ui.click", bus: "sfx", kind: "sfx", at: 1600 };
|
|
1722
|
+
* ```
|
|
1723
|
+
*/
|
|
1724
|
+
type SoundEntry = {
|
|
1725
|
+
readonly key: string;
|
|
1726
|
+
readonly bus: Bus;
|
|
1727
|
+
readonly kind: "sfx" | "music";
|
|
1728
|
+
readonly at: number;
|
|
1729
|
+
};
|
|
1730
|
+
/**
|
|
1731
|
+
* What the plugin keeps for one bus: its gain node while a context exists, the volume a game or
|
|
1732
|
+
* the player chose, and whether it is muted.
|
|
1733
|
+
*
|
|
1734
|
+
* @example
|
|
1735
|
+
* ```ts
|
|
1736
|
+
* const entry: BusState = { gain: undefined, volume: 0.6, muted: false };
|
|
1737
|
+
* ```
|
|
1738
|
+
*/
|
|
1739
|
+
type BusState = {
|
|
1740
|
+
gain: GainNode | undefined;
|
|
1741
|
+
volume: number;
|
|
1742
|
+
muted: boolean;
|
|
1743
|
+
};
|
|
1744
|
+
/**
|
|
1745
|
+
* The music that is playing, or the key remembered until the first touch unlocks the context.
|
|
1746
|
+
* `source` plays a decoded track, `stream` a streamed one; they are never both set. Both
|
|
1747
|
+
* `undefined`: the key is only remembered (a locked context, or a refused `play()`).
|
|
1748
|
+
*
|
|
1749
|
+
* @example
|
|
1750
|
+
* ```ts
|
|
1751
|
+
* const track: MusicTrack = { key: "board.theme", gain: undefined, source: undefined, stream: undefined };
|
|
1752
|
+
* ```
|
|
1753
|
+
*/
|
|
1754
|
+
type MusicTrack = {
|
|
1755
|
+
key: string;
|
|
1756
|
+
gain: GainNode | undefined;
|
|
1757
|
+
source: AudioBufferSourceNode | undefined;
|
|
1758
|
+
stream: StreamTrack | undefined;
|
|
1759
|
+
};
|
|
1760
|
+
/**
|
|
1761
|
+
* A music switch that waits for its buffer to decode. Its identity is the token: a later request
|
|
1762
|
+
* replaces it, and the replaced switch neither starts nor fades anything when its buffer arrives.
|
|
1763
|
+
*
|
|
1764
|
+
* @example
|
|
1765
|
+
* ```ts
|
|
1766
|
+
* const waiting: MusicSwitch = { key: "ui.theme" };
|
|
1767
|
+
* ```
|
|
1768
|
+
*/
|
|
1769
|
+
type MusicSwitch = {
|
|
1770
|
+
key: string;
|
|
1771
|
+
};
|
|
1772
|
+
/**
|
|
1773
|
+
* audio plugin state.
|
|
1774
|
+
*/
|
|
1775
|
+
type State = {
|
|
1776
|
+
/** `undefined` means headless: no graph, no sound, every member still keeps its value. */context: AudioContextLike | undefined;
|
|
1777
|
+
buses: Record<Bus, BusState>; /** A lifecycle push is in force: every bus is held at zero. */
|
|
1778
|
+
paused: boolean;
|
|
1779
|
+
unlocked: boolean; /** A gesture called `resume()` and it has not settled yet. */
|
|
1780
|
+
resuming: boolean; /** Sounds fired while `resuming`, one per key; played when the context runs, dropped when it does not. */
|
|
1781
|
+
pendingSfx: Map<string, SfxRequest>; /** Per key, evicted per key on `assets:bundle-unloaded`. */
|
|
1782
|
+
decoded: Map<string, Promise<AudioBuffer>>; /** Asset keys that already got their one warning. */
|
|
1783
|
+
warned: Set<string>; /** `config.volumes` threw once and was reported; it is not reported again this run. */
|
|
1784
|
+
warnedVolumes: boolean;
|
|
1785
|
+
music: MusicTrack | undefined; /** The latest switch still decoding; `undefined` once it started or a later request replaced it. */
|
|
1786
|
+
musicPending: MusicSwitch | undefined; /** Removes the two window listeners of the unlock. */
|
|
1787
|
+
unlock: (() => void) | undefined; /** The removers of the two fx handlers. */
|
|
1788
|
+
removers: Array<() => void>; /** The `navigator.audioSession` that took `config.session`; `stop` writes `"auto"` back to it. */
|
|
1789
|
+
session: AudioSessionLike | undefined; /** Streamed tracks that fade out, each freed by its timer. */
|
|
1790
|
+
retiring: Set<RetiringTrack>;
|
|
1791
|
+
/**
|
|
1792
|
+
* The sounds that started, oldest first, at most `config.journal` of them. Frozen: a write
|
|
1793
|
+
* replaces the whole list, so `journal()` hands it out without a copy.
|
|
1794
|
+
*/
|
|
1795
|
+
journal: readonly SoundEntry[];
|
|
1796
|
+
};
|
|
1797
|
+
/**
|
|
1798
|
+
* audio plugin API, `app.audio`. Three buses and the unlock flag: what a game changes about sound
|
|
1799
|
+
* it commits to the player state, which this plugin applies on the next commit.
|
|
1800
|
+
*
|
|
1801
|
+
* @example
|
|
1802
|
+
* ```ts
|
|
1803
|
+
* // A dev overlay pulls the music down and reads the value back.
|
|
1804
|
+
* app.audio.setVolume("music", 0.2);
|
|
1805
|
+
* app.audio.volume("music"); // 0.2
|
|
1806
|
+
* ```
|
|
1807
|
+
*/
|
|
1808
|
+
type AudioApi = {
|
|
1809
|
+
/**
|
|
1810
|
+
* Sets the volume of one bus and schedules the new gain at once. The value is clamped to 0..1
|
|
1811
|
+
* and `NaN` becomes 0. Nothing is persisted: a game stores the choice in the player state and
|
|
1812
|
+
* lets `config.volumes` apply it, so the next commit overwrites what this call set.
|
|
1813
|
+
*
|
|
1814
|
+
* @param bus - The bus to change.
|
|
1815
|
+
* @param value - The new volume, 0..1.
|
|
1816
|
+
* @throws {Error} When the bus does not exist.
|
|
1817
|
+
* @example
|
|
1818
|
+
* ```ts
|
|
1819
|
+
* // A test turns the music off before it walks the graph, so nothing rings.
|
|
1820
|
+
* app.audio.setVolume("music", 0);
|
|
1821
|
+
* app.audio.volume("music"); // 0
|
|
1822
|
+
* ```
|
|
1823
|
+
*/
|
|
1824
|
+
setVolume(bus: Bus, value: number): void;
|
|
1825
|
+
/**
|
|
1826
|
+
* The stored volume of a bus, never the live gain: a muted or paused bus still answers the
|
|
1827
|
+
* value the player chose.
|
|
1828
|
+
*
|
|
1829
|
+
* @param bus - The bus to read.
|
|
1830
|
+
* @returns The stored volume, 0..1.
|
|
1831
|
+
* @throws {Error} When the bus does not exist.
|
|
1832
|
+
* @example
|
|
1833
|
+
* ```ts
|
|
1834
|
+
* // The settings screen draws the slider of the sfx bus at its stored place.
|
|
1835
|
+
* app.audio.mute("sfx", true);
|
|
1836
|
+
* app.audio.volume("sfx"); // 1: muting does not move the slider
|
|
1837
|
+
* ```
|
|
1838
|
+
*/
|
|
1839
|
+
volume(bus: Bus): number;
|
|
1840
|
+
/**
|
|
1841
|
+
* Mutes or unmutes one bus. The flag is independent of the pause: a bus muted here stays muted
|
|
1842
|
+
* when the game comes back from the background.
|
|
1843
|
+
*
|
|
1844
|
+
* @param bus - The bus to change.
|
|
1845
|
+
* @param on - `true` mutes it, `false` lets it play again.
|
|
1846
|
+
* @throws {Error} When the bus does not exist.
|
|
1847
|
+
* @example
|
|
1848
|
+
* ```ts
|
|
1849
|
+
* // A dev overlay silences the whole game while a profiler trace runs.
|
|
1850
|
+
* app.audio.mute("master", true);
|
|
1851
|
+
* app.audio.volume("master"); // 1, and nothing is heard
|
|
1852
|
+
* ```
|
|
1853
|
+
*/
|
|
1854
|
+
mute(bus: Bus, on: boolean): void;
|
|
1855
|
+
/**
|
|
1856
|
+
* Tells whether one bus is muted: the stored flag `mute` wrote. A pause does not change it, and
|
|
1857
|
+
* a headless run answers it too.
|
|
1858
|
+
*
|
|
1859
|
+
* @param bus - The bus to read.
|
|
1860
|
+
* @returns True while the bus is muted.
|
|
1861
|
+
* @throws {Error} When the bus does not exist.
|
|
1862
|
+
* @example
|
|
1863
|
+
* ```ts
|
|
1864
|
+
* // The settings screen draws the Sound switch off after the player muted the game.
|
|
1865
|
+
* app.audio.mute("master", true);
|
|
1866
|
+
* app.audio.muted("master"); // true
|
|
1867
|
+
* ```
|
|
1868
|
+
*/
|
|
1869
|
+
muted(bus: Bus): boolean;
|
|
1870
|
+
/**
|
|
1871
|
+
* Tells whether the browser let the audio context run. It is false until the first pointer
|
|
1872
|
+
* event on the page resumed it, and false for the whole of a headless run.
|
|
1873
|
+
*
|
|
1874
|
+
* @returns True once the context is running.
|
|
1875
|
+
* @example
|
|
1876
|
+
* ```ts
|
|
1877
|
+
* // A "tap to start" screen stays up until the browser allowed sound.
|
|
1878
|
+
* app.audio.unlocked(); // false before the first touch, true after it
|
|
1879
|
+
* ```
|
|
1880
|
+
*/
|
|
1881
|
+
unlocked(): boolean;
|
|
1882
|
+
/**
|
|
1883
|
+
* The sounds that started, oldest first: every play of an `sfx` and every music track that
|
|
1884
|
+
* began, at most `config.journal` of them. A sound dropped before the unlock, a missing file
|
|
1885
|
+
* and a music switch to the track that already plays are not in it. Empty while
|
|
1886
|
+
* `config.journal` is 0, the default, and after the app stopped.
|
|
1887
|
+
*
|
|
1888
|
+
* @returns The journal, frozen; a later sound replaces the list and leaves this one as it was.
|
|
1889
|
+
* @example
|
|
1890
|
+
* ```ts
|
|
1891
|
+
* // A test composed with `pluginConfigs.audio = { journal: 200 }` taps "deliver" after the
|
|
1892
|
+
* // first touch and checks the chime was heard.
|
|
1893
|
+
* app.audio.journal();
|
|
1894
|
+
* // [{ key: "board.theme", bus: "music", kind: "music", at: 0 },
|
|
1895
|
+
* // { key: "orders.complete", bus: "sfx", kind: "sfx", at: 1600 }]
|
|
1896
|
+
* ```
|
|
1897
|
+
*/
|
|
1898
|
+
journal(): readonly SoundEntry[];
|
|
1899
|
+
};
|
|
1900
|
+
/**
|
|
1901
|
+
* Resolved dependency APIs.
|
|
1902
|
+
*/
|
|
1903
|
+
type Deps = {
|
|
1904
|
+
flow: Api$1;
|
|
1905
|
+
assets: Api$4;
|
|
1906
|
+
model: Api$5;
|
|
1907
|
+
time: Api;
|
|
1908
|
+
};
|
|
1909
|
+
/**
|
|
1910
|
+
* What the kernel context offers before the deps are attached.
|
|
1911
|
+
*
|
|
1912
|
+
* `audio` owns no event, so `emit` is the kernel's and never called here.
|
|
1913
|
+
*/
|
|
1914
|
+
type KernelSlice = PluginCtx<Config, State> & {
|
|
1915
|
+
readonly global: object;
|
|
1916
|
+
readonly log: Log.LogApi;
|
|
1917
|
+
readonly require: Require;
|
|
1918
|
+
};
|
|
1919
|
+
/**
|
|
1920
|
+
* Domain context shared by the files of the plugin: the kernel slice plus the resolved deps.
|
|
1921
|
+
*/
|
|
1922
|
+
type AudioCtx = KernelSlice & {
|
|
1302
1923
|
readonly deps: Deps;
|
|
1303
1924
|
};
|
|
1925
|
+
/**
|
|
1926
|
+
* Payload of the `model:committed` hook: the source of every volume a game sets.
|
|
1927
|
+
*/
|
|
1928
|
+
type ModelCommitted = Events$2["model:committed"];
|
|
1929
|
+
/**
|
|
1930
|
+
* Payload of the `scenes:changed` hook: `music` is the track the next scene declared.
|
|
1931
|
+
*/
|
|
1932
|
+
type SceneChanged = Events["scenes:changed"];
|
|
1933
|
+
/**
|
|
1934
|
+
* Payload of the `lifecycle:changed` hook: the pause that holds every bus at zero.
|
|
1935
|
+
*/
|
|
1936
|
+
type LifecycleChanged = Events$3["lifecycle:changed"];
|
|
1937
|
+
/**
|
|
1938
|
+
* Payload of the `assets:bundle-unloaded` hook: `keys` names every decoded sound that is gone.
|
|
1939
|
+
*/
|
|
1940
|
+
type BundleUnloaded = Events$4["assets:bundle-unloaded"];
|
|
1941
|
+
/**
|
|
1942
|
+
* What one play of a sound asks for: the key and the bus the sound goes to.
|
|
1943
|
+
*/
|
|
1944
|
+
type SfxRequest = {
|
|
1945
|
+
key: string;
|
|
1946
|
+
bus: string;
|
|
1947
|
+
};
|
|
1948
|
+
/**
|
|
1949
|
+
* What one music switch asks for: the key, or `null` to fade the current track out.
|
|
1950
|
+
*/
|
|
1951
|
+
type MusicRequest = {
|
|
1952
|
+
key: string | null;
|
|
1953
|
+
fadeMs: number;
|
|
1954
|
+
};
|
|
1304
1955
|
//#endregion
|
|
1305
|
-
export {
|
|
1956
|
+
export { haptic as A, tween as B, HapticKind as C, defineAnimation as D, HAPTIC_KINDS as E, set as F, UiApi as G, wait as H, sfx as I, types_d_exports$3 as K, spawn as L, parallel as M, play as N, external as O, sequence as P, spawned as R, types_d_exports$2 as S, Step as T, Config$3 as U, use as V, State$3 as W, Config$2 as _, SoundEntry as a, State$2 as b, AnySceneProjection as c, SceneDefinition as d, SceneSpec as f, AnimApi as g, types_d_exports$1 as h, MusicOptions as i, mark as j, frames as k, DefineScene as l, State$1 as m, Config as n, State as o, ScenesApi as p, MusicDescriptor as r, types_d_exports as s, AudioApi as t, LayerMap as u, FramesValue as v, SfxDescriptor as w, Target as x, MotionKeyframe as y, stagger as z };
|