@moku-labs/game 0.0.1 → 0.0.3

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.
@@ -0,0 +1,690 @@
1
+ import { St as Api$3, f as SliceFrame, mt as NodeInfo, nn as Require, o as PixiTexture, q as Api$1, t as Api$2, vt as Descriptor } from "./types-Cjf3ywai.mjs";
2
+ import { Log } from "@moku-labs/common/browser";
3
+ import { PluginCtx } from "@moku-labs/core";
4
+
5
+ //#region src/plugins/assets/types.d.ts
6
+ declare namespace types_d_exports {
7
+ export { Api, AssetKind, AssetsCtx, AssetsIo, AtlasFrame, AtlasPage, BundleMap, BundleRecord, BundleSpec, BundleUsage, Config, CreateTextureOptions, DecodedImage, DefineBundles, Deps, Events, FetchResponse, FlowRest, FontAsset, FontPage, Inflight, KernelSlice, LoadBundles, LoadReason, LoadResult, LoadedAssets, LoadedFont, Manifest, ManifestBundle, ManifestFile, NineBorders, NineSlice, PreloadQueue, State, Texture, Tier, Usage };
8
+ }
9
+ /**
10
+ * When a bundle is loaded. `boot` and `core` stay for the whole session, `scene` and `feature`
11
+ * come and go with the graph, `lazy` is never preloaded.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const tier: Tier = "scene";
16
+ * ```
17
+ */
18
+ type Tier = "boot" | "core" | "scene" | "feature" | "lazy";
19
+ /**
20
+ * What one file of a bundle is. A `.fnt` with its `.png` pages is one `font`, an `.mp3` is
21
+ * `audio`, everything else is a `texture`. A file of an older manifest that names no kind is a
22
+ * texture.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const kind: AssetKind = "font";
27
+ * ```
28
+ */
29
+ type AssetKind = "texture" | "font" | "audio";
30
+ /**
31
+ * A GPU texture. `assets` owns its lifetime and never imports Pixi: `renderer` makes and destroys
32
+ * it, this plugin only says when.
33
+ */
34
+ type Texture = PixiTexture;
35
+ /**
36
+ * A decoded image, ready for the upload. `createImageBitmap` produces the first shape.
37
+ */
38
+ type DecodedImage = ImageBitmap | HTMLImageElement;
39
+ /**
40
+ * Nine-slice borders in pixels, in the order left, top, right, bottom.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const borders: NineBorders = [48, 48, 48, 48];
45
+ * ```
46
+ */
47
+ type NineBorders = readonly [number, number, number, number];
48
+ /**
49
+ * Options of `io.createTexture`. Same shape as `renderer.sync.textures.create`.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const options: CreateTextureOptions = { nine: [48, 48, 48, 48] };
54
+ * ```
55
+ */
56
+ type CreateTextureOptions = {
57
+ nine?: NineBorders;
58
+ };
59
+ /**
60
+ * The part of a fetch response the plugin reads: the manifest is `json`, a texture is a `blob`,
61
+ * a font file is `text` and an audio file stays the raw `arrayBuffer`. The global `Response`
62
+ * fits it.
63
+ */
64
+ type FetchResponse = {
65
+ ok: boolean;
66
+ status: number;
67
+ json(): Promise<unknown>;
68
+ blob(): Promise<Blob>;
69
+ text(): Promise<string>;
70
+ arrayBuffer(): Promise<ArrayBuffer>;
71
+ };
72
+ /**
73
+ * The I/O seam: everything that leaves the plugin. `undefined` in the config means the browser
74
+ * pair plus `renderer.sync.textures`; a test passes a fake and nothing touches the network or a GPU.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * // A unit test serves two files from memory and counts the textures it handed out.
79
+ * const io: AssetsIo = {
80
+ * fetch: async () => ({
81
+ * ok: true,
82
+ * status: 200,
83
+ * json: async () => ({}),
84
+ * blob: async () => blob,
85
+ * text: async () => 'info face="body"',
86
+ * arrayBuffer: async () => new ArrayBuffer(8)
87
+ * }),
88
+ * decode: async () => bitmap,
89
+ * createTexture: () => ({ id: "t1" }) as unknown as Texture,
90
+ * sliceTexture: (page, frame) => ({ id: "s1", page, frame }) as unknown as Texture,
91
+ * destroyTexture: texture => destroyed.push(texture)
92
+ * };
93
+ *
94
+ * createApp({ plugins: [...screen], pluginConfigs: { assets: { io, manifest } } });
95
+ * ```
96
+ */
97
+ type AssetsIo = {
98
+ /**
99
+ * Fetches one URL: the manifest, or a file of a bundle.
100
+ *
101
+ * @param url - Absolute or root-relative URL.
102
+ * @param init - Carries the abort signal of the running load.
103
+ * @param init.signal - Aborts the request when the load is cancelled.
104
+ * @returns The response.
105
+ */
106
+ fetch(url: string, init: {
107
+ signal: AbortSignal;
108
+ }): Promise<FetchResponse>;
109
+ /**
110
+ * Decodes one image file.
111
+ *
112
+ * @param blob - The bytes of the file.
113
+ * @returns The decoded image.
114
+ */
115
+ decode(blob: Blob): Promise<DecodedImage>;
116
+ /**
117
+ * Uploads one decoded image to the GPU.
118
+ *
119
+ * @param image - The decoded image.
120
+ * @param options - `nine` becomes the default nine-slice borders of the texture.
121
+ * @returns The new texture.
122
+ */
123
+ createTexture(image: DecodedImage, options?: CreateTextureOptions): Texture;
124
+ /**
125
+ * Cuts the texture of one packed file out of its atlas page. The slice shares the page's
126
+ * source: no pixel is copied. Same shape as `renderer.sync.textures.slice`; the manifest's
127
+ * `atlas` frame is passed as it is.
128
+ *
129
+ * @param page - The page texture, made by `createTexture`.
130
+ * @param frame - Where the file lies on the page, in page pixels.
131
+ * @param options - `nine` becomes the default nine-slice borders of the slice.
132
+ * @returns The new texture over the page's source.
133
+ */
134
+ sliceTexture(page: Texture, frame: SliceFrame, options?: CreateTextureOptions): Texture;
135
+ /**
136
+ * Frees one texture. A page frees its source too; a slice frees only itself, so the slices of
137
+ * a bundle go first and its pages after them.
138
+ *
139
+ * @param texture - The texture to free.
140
+ */
141
+ destroyTexture(texture: Texture): void;
142
+ };
143
+ /**
144
+ * Nine-slice metadata of one file, as the scanner writes it. Always four numbers: the tags
145
+ * `{nine=N}`, `{nine=H,V}` and `{nine=L,T,R,B}` all land here.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const nine: NineSlice = { left: 48, top: 48, right: 48, bottom: 48 };
150
+ * ```
151
+ */
152
+ type NineSlice = {
153
+ left: number;
154
+ top: number;
155
+ right: number;
156
+ bottom: number;
157
+ };
158
+ /**
159
+ * Where a packed file lies: `page` is the id of a page of the same bundle, never a file name, and
160
+ * the frame is in page pixels. `width` and `height` equal the file's own, so its `nine` stays
161
+ * valid as it is. The packer writes it; the loader cuts the file out of the page.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * const frame: AtlasFrame = { page: "ui/main-0", x: 583, y: 595, width: 256, height: 128 };
166
+ * ```
167
+ */
168
+ type AtlasFrame = {
169
+ page: string;
170
+ x: number;
171
+ y: number;
172
+ width: number;
173
+ height: number;
174
+ };
175
+ /**
176
+ * One atlas page of a packed bundle. `id` is `<bundle>/<group>-<index>`, the name an `atlas`
177
+ * frame uses; `path` is the hashed WebP file, read like the `path` of a file. `mb` is
178
+ * `width × height × 4 / 1 048 576`: the page carries the cost of every file packed on it.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * const page: AtlasPage = {
183
+ * id: "ui/main-0",
184
+ * path: "ui/main-0-3b1d55a0c9.webp",
185
+ * width: 966,
186
+ * height: 1365,
187
+ * mb: 5.03
188
+ * };
189
+ * ```
190
+ */
191
+ type AtlasPage = {
192
+ id: string;
193
+ path: string;
194
+ width: number;
195
+ height: number;
196
+ mb: number;
197
+ };
198
+ /**
199
+ * One page image of a font. A page has no key of its own: it belongs to the `.fnt` file that
200
+ * names it, and is loaded and freed with it.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * const page: FontPage = {
205
+ * path: "features/ui/assets/body_0.png",
206
+ * width: 256,
207
+ * height: 128,
208
+ * mb: 0.125
209
+ * };
210
+ * ```
211
+ */
212
+ type FontPage = {
213
+ path: string;
214
+ width: number;
215
+ height: number;
216
+ mb: number;
217
+ };
218
+ /**
219
+ * One file of a bundle. `mb` is what it costs: `width × height × 4` bytes for a texture, the sum
220
+ * of the pages for a font, the size of the file for audio, and `0` for a texture packed in an
221
+ * atlas, whose page carries the cost. `kind` is absent for a texture, which is what every
222
+ * manifest written before fonts and audio carries. A loose file has `path`; a packed texture has
223
+ * `atlas` and no `path`.
224
+ *
225
+ * @example
226
+ * ```ts
227
+ * // The dev manifest of the scanner: a loose file.
228
+ * const loose: ManifestFile = {
229
+ * key: "ui.panel",
230
+ * path: "features/ui/assets/panel{nine=48}.png",
231
+ * width: 256,
232
+ * height: 128,
233
+ * mb: 0.125,
234
+ * nine: { left: 48, top: 48, right: 48, bottom: 48 }
235
+ * };
236
+ *
237
+ * // The packed manifest: the same key, cut out of the page "ui/main-0".
238
+ * const packed: ManifestFile = {
239
+ * key: "ui.panel",
240
+ * width: 256,
241
+ * height: 128,
242
+ * mb: 0,
243
+ * nine: { left: 48, top: 48, right: 48, bottom: 48 },
244
+ * atlas: { page: "ui/main-0", x: 583, y: 595, width: 256, height: 128 }
245
+ * };
246
+ * ```
247
+ */
248
+ type ManifestFile = {
249
+ key: string;
250
+ path?: string;
251
+ kind?: AssetKind;
252
+ width: number;
253
+ height: number;
254
+ mb: number;
255
+ pages?: readonly FontPage[];
256
+ nine?: NineSlice;
257
+ atlas?: AtlasFrame;
258
+ };
259
+ /**
260
+ * One bundle of the manifest: which feature owns it, when it loads and what it costs. `pages` is
261
+ * written by the packer only, sorted by id; `mb` is then its pages, its loose textures, its font
262
+ * pages and its audio bytes together.
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * const bundle: ManifestBundle = { feature: "ui", tier: "core", mb: 0.125, files: [] };
267
+ * ```
268
+ */
269
+ type ManifestBundle = {
270
+ feature: string;
271
+ tier: Tier;
272
+ mb: number;
273
+ pages?: readonly AtlasPage[];
274
+ files: readonly ManifestFile[];
275
+ };
276
+ /**
277
+ * The manifest: the contract between the scanner, the packer, this plugin and the editor. Version
278
+ * `1` is the dev manifest of `bun run assets:keys`, version `2` the packed one of
279
+ * `bun run assets:pack`; the plugin reads both. Bundles are sorted by name, pages by id and files
280
+ * by key, so two runs on the same tree give the same bytes.
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * // A dev build: loose files, straight from the features.
285
+ * const manifest: Manifest = {
286
+ * version: 1,
287
+ * bundles: { ui: { feature: "ui", tier: "core", mb: 0, files: [] } }
288
+ * };
289
+ *
290
+ * createApp({ plugins: [...screen], pluginConfigs: { assets: { manifest } } });
291
+ *
292
+ * // The packed manifest of the same game: the panel is cut out of the page "ui/main-0".
293
+ * const page = { id: "ui/main-0", path: "ui/main-0-3b1d55a0c9.webp", width: 966, height: 1365, mb: 5.03 };
294
+ * const atlas = { page: "ui/main-0", x: 583, y: 595, width: 256, height: 128 };
295
+ * const panel = { key: "ui.panel", width: 256, height: 128, mb: 0, atlas };
296
+ * const packed: Manifest = {
297
+ * version: 2,
298
+ * bundles: { ui: { feature: "ui", tier: "core", mb: 5.03, pages: [page], files: [panel] } }
299
+ * };
300
+ * ```
301
+ */
302
+ type Manifest = {
303
+ version: 1 | 2;
304
+ bundles: Readonly<Record<string, ManifestBundle>>;
305
+ };
306
+ /**
307
+ * What a feature declares about one of its bundles. `files` are globs relative to the feature's
308
+ * `assets/`; a bundle with `files` takes those files out of the feature's default bundle.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * const spec: BundleSpec = { tier: "lazy", files: ["chains/*.png"] };
313
+ * ```
314
+ */
315
+ type BundleSpec = {
316
+ tier: Tier;
317
+ files?: readonly string[];
318
+ };
319
+ /**
320
+ * What `defineBundles` returns: plain data the scanner and the plugin both read.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * const bundles: BundleMap = {
325
+ * kind: "bundles",
326
+ * map: { board: { tier: "scene" }, "board.chains": { tier: "lazy", files: ["chains/*.png"] } }
327
+ * };
328
+ * ```
329
+ */
330
+ type BundleMap<Key extends string = string> = {
331
+ kind: "bundles";
332
+ map: Partial<Record<Key, BundleSpec>>;
333
+ };
334
+ /**
335
+ * `defineBundles` bound to the bundle keys of one game. `defineGame` returns it, so a key that is
336
+ * not in `BundleKey` does not compile.
337
+ *
338
+ * @example
339
+ * ```ts
340
+ * const defineGameBundles: DefineBundles<"board" | "board.chains"> = defineBundles;
341
+ * ```
342
+ */
343
+ type DefineBundles<Key extends string> = (map: Partial<Record<Key, BundleSpec>>) => BundleMap<Key>;
344
+ /**
345
+ * The `load` descriptor helper bound to the bundle keys of one game.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * const loadGameBundle: LoadBundles<"board" | "board.chains"> = load;
350
+ * ```
351
+ */
352
+ type LoadBundles<Key extends string> = (bundle: Key | readonly Key[]) => Descriptor;
353
+ /**
354
+ * What the `load` effect resolves with, so a loading node can write its own progress.
355
+ *
356
+ * @example
357
+ * ```ts
358
+ * const result: LoadResult = { loaded: ["board.chains"], mb: 1.25 };
359
+ * ```
360
+ */
361
+ type LoadResult = {
362
+ loaded: string[];
363
+ mb: number;
364
+ };
365
+ /**
366
+ * Why a bundle was loaded. It is the reason of the caller that started the load; a later waiter
367
+ * changes nothing.
368
+ *
369
+ * @example
370
+ * ```ts
371
+ * const reason: LoadReason = "enter";
372
+ * ```
373
+ */
374
+ type LoadReason = "boot" | "enter" | "request" | "preload";
375
+ /**
376
+ * The running load of one bundle. Every caller is a waiter; the last one to leave aborts it.
377
+ * `promise` never rejects: what broke waits in `error`, so a load nobody joined any more cannot
378
+ * become an unhandled rejection.
379
+ */
380
+ type Inflight = {
381
+ promise: Promise<void>;
382
+ controller: AbortController;
383
+ waiters: number;
384
+ error: unknown;
385
+ };
386
+ /**
387
+ * A loaded font: the `.fnt` file as text and the page textures it names. `text` installs the
388
+ * first page in the renderer; every page is destroyed with the bundle.
389
+ *
390
+ * @example
391
+ * ```ts
392
+ * const font: FontAsset = { fnt: 'info face="body" size=32', texture };
393
+ * ```
394
+ */
395
+ type FontAsset = {
396
+ fnt: string;
397
+ texture: Texture;
398
+ };
399
+ /**
400
+ * What the plugin keeps for a loaded font: the public pair plus every page, because a font of
401
+ * two pages owns two textures.
402
+ */
403
+ type LoadedFont = FontAsset & {
404
+ pages: readonly Texture[];
405
+ };
406
+ /**
407
+ * What one bundle brought: textures by asset key (a packed file's is a slice of its page), fonts
408
+ * with their pages, the undecoded bytes of the audio files, and the atlas pages by page id. A
409
+ * running load fills the same four maps before they are published.
410
+ */
411
+ type LoadedAssets = {
412
+ textures: Map<string, Texture>;
413
+ fonts: Map<string, LoadedFont>;
414
+ audio: Map<string, ArrayBuffer>;
415
+ pages: Map<string, Texture>;
416
+ };
417
+ /**
418
+ * What the plugin knows about one bundle. `lastUsed` is the value of `useCounter` at the last
419
+ * touch: a counter, never a clock.
420
+ */
421
+ type BundleRecord = LoadedAssets & {
422
+ status: "idle" | "loading" | "loaded";
423
+ inflight: Inflight | undefined;
424
+ lastUsed: number;
425
+ };
426
+ /**
427
+ * The background preload. A new rest node replaces it and aborts the old controller.
428
+ */
429
+ type PreloadQueue = {
430
+ bundles: string[];
431
+ controller: AbortController;
432
+ };
433
+ /**
434
+ * assets plugin config.
435
+ *
436
+ * @example
437
+ * ```ts
438
+ * createApp({
439
+ * plugins: [...screen, boardFeature],
440
+ * pluginConfigs: { assets: { manifest: "/assets/manifest.json", textureBudgetMb: 192 } }
441
+ * });
442
+ * ```
443
+ */
444
+ type Config = {
445
+ /** URL of `manifest.json`, or the parsed manifest itself (tests, headless). `undefined`: an empty manifest. */manifest: string | Manifest | undefined; /** Texture memory budget in MB. */
446
+ textureBudgetMb: number; /** How many edges from a rest node the background preload looks ahead. `0` turns preload off. */
447
+ preloadDepth: number; /** Prefix of every file URL. The CDN seam. `undefined`: the folder of the manifest URL, or `"/"`. */
448
+ baseUrl: string | undefined; /** I/O seam. `undefined`: the browser pair plus `renderer.sync.textures`, or headless. */
449
+ io: AssetsIo | undefined;
450
+ };
451
+ /**
452
+ * assets plugin state.
453
+ */
454
+ type State = {
455
+ /** `undefined` means headless: manifest only, no fetches, no textures. */io: AssetsIo | undefined; /** Empty until `onStart` read it. */
456
+ manifest: Manifest; /** Asset key to the bundle that carries it. */
457
+ bundleOfKey: Map<string, string>; /** Scene id to its bundle, read from the `scenes` key of `flow.features`. */
458
+ bundleOfScene: Map<string, string>; /** Flow id to the feature that owns it, read from the `flows` key of `flow.features`. */
459
+ featureOfFlow: Map<string, string>;
460
+ records: Map<string, BundleRecord>; /** Bundles of the node entered last. They are never unloaded. */
461
+ pinned: Set<string>; /** The bundle of the scene entered last. A node without `scene` keeps it. */
462
+ sceneBundle: string | undefined;
463
+ queue: PreloadQueue | undefined;
464
+ current: NodeInfo | undefined;
465
+ useCounter: number; /** Keys already reported missing, so one key warns and starts its background load once. */
466
+ warned: Set<string>; /** `onEnter`, the `load` handler and the texture provider. */
467
+ removers: Array<() => void>;
468
+ };
469
+ /**
470
+ * What `usage()` reports about one loaded bundle.
471
+ *
472
+ * @example
473
+ * ```ts
474
+ * const entry: BundleUsage = { name: "board", tier: "scene", mb: 3.5, lastUsed: 12 };
475
+ * ```
476
+ */
477
+ type BundleUsage = {
478
+ name: string;
479
+ tier: Tier;
480
+ mb: number;
481
+ lastUsed: number;
482
+ };
483
+ /**
484
+ * What `usage()` reports: the numbers a dev overlay and the tests read.
485
+ *
486
+ * @example
487
+ * ```ts
488
+ * const report: Usage = { textureMb: 3.5, budgetMb: 192, bundles: [] };
489
+ * ```
490
+ */
491
+ type Usage = {
492
+ textureMb: number;
493
+ budgetMb: number;
494
+ bundles: readonly BundleUsage[];
495
+ };
496
+ /**
497
+ * assets plugin events.
498
+ *
499
+ * @example
500
+ * ```ts
501
+ * // A game reports every loaded bundle to its analytics.
502
+ * createPlugin("loadReport", {
503
+ * depends: [assetsPlugin],
504
+ * hooks: ctx => ({ "assets:bundle-loaded": ({ bundle, mb }) => ctx.log.info("loaded", { bundle, mb }) })
505
+ * }); // the board bundle logs { bundle: "board", mb: 3.5 }
506
+ *
507
+ * // A splash screen fills its loading bar file by file.
508
+ * createPlugin("loadingBar", {
509
+ * depends: [assetsPlugin],
510
+ * createState: () => ({ share: 0 }),
511
+ * hooks: ctx => ({
512
+ * "assets:bundle-progress": ({ loaded, total }) => {
513
+ * ctx.state.share = loaded / total;
514
+ * }
515
+ * })
516
+ * }); // a board bundle of four files sets share to 0.25, 0.5, 0.75 and 1; bundle-loaded follows
517
+ * ```
518
+ */
519
+ type Events = {
520
+ /** Every file of a bundle is a texture now. */"assets:bundle-loaded": {
521
+ bundle: string;
522
+ tier: Tier;
523
+ mb: number;
524
+ reason: LoadReason;
525
+ };
526
+ /**
527
+ * One more file of a running load settled. `loaded` counts the settled files (a font once, with
528
+ * its pages), `total` is the file count of the bundle; the last one of a load has
529
+ * `loaded === total` and comes before `assets:bundle-loaded`. An aborted load sends none.
530
+ */
531
+ "assets:bundle-progress": {
532
+ bundle: string;
533
+ loaded: number;
534
+ total: number;
535
+ }; /** The textures of a bundle were destroyed. `keys` names every asset that went with it. */
536
+ "assets:bundle-unloaded": {
537
+ bundle: string;
538
+ tier: Tier;
539
+ mb: number;
540
+ reason: "budget" | "request";
541
+ keys: readonly string[];
542
+ };
543
+ };
544
+ /**
545
+ * assets plugin API, `app.assets`. Bundles of textures by key: the graph decides when they arrive,
546
+ * the budget decides when they leave.
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * // A loading node asks for a bundle and a game system asks for one texture of it.
551
+ * await app.assets.load("board");
552
+ * app.assets.texture("board.cell"); // the Pixi texture, once the bundle is there
553
+ * ```
554
+ */
555
+ type Api = {
556
+ /**
557
+ * Loads every file of a bundle. An already loaded bundle resolves at once, a loading one joins
558
+ * the running load. Headless it resolves at once and touches nothing.
559
+ *
560
+ * @param bundle - Name of a bundle of the manifest.
561
+ * @returns A promise that resolves when every texture of the bundle exists.
562
+ * @throws {Error} When the manifest has no such bundle, and when a file fails to load.
563
+ * @example
564
+ * ```ts
565
+ * // A game plugin warms the bundle of a timed event before its popup can open.
566
+ * await app.assets.load("event.halloween");
567
+ * app.assets.isLoaded("event.halloween"); // true
568
+ * ```
569
+ */
570
+ load(bundle: string): Promise<void>;
571
+ /**
572
+ * Destroys the textures of a bundle and tells `renderer` that its keys are gone. A pinned
573
+ * bundle and the tiers `boot` and `core` are refused with a warning. A running load is aborted.
574
+ *
575
+ * @param bundle - Name of a loaded bundle.
576
+ * @example
577
+ * ```ts
578
+ * // The timed event ended: its textures go back to the GPU.
579
+ * app.assets.unload("event.halloween");
580
+ * app.assets.isLoaded("event.halloween"); // false
581
+ * ```
582
+ */
583
+ unload(bundle: string): void;
584
+ /**
585
+ * Tells whether every texture of a bundle exists. Headless every bundle of the manifest counts
586
+ * as loaded, so a headless game never waits for a loading screen.
587
+ *
588
+ * @param bundle - Name of a bundle of the manifest.
589
+ * @returns True when the bundle is loaded.
590
+ * @example
591
+ * ```ts
592
+ * // `scenes` skips its loading path when the bundle of the next scene is already there.
593
+ * if (!app.assets.isLoaded("board")) await app.assets.load("board");
594
+ * ```
595
+ */
596
+ isLoaded(bundle: string): boolean;
597
+ /**
598
+ * The texture of a loaded asset key. It touches the use counter of the bundle, which is what
599
+ * the LRU reads. A key of a bundle that is not loaded warns once, starts a background load and
600
+ * answers `undefined`; the sprites waiting for it are textured when that load lands. A key packed
601
+ * in an atlas answers its slice of the page, so a game never sees the difference.
602
+ *
603
+ * @param key - Asset key, as `generated/assets.ts` types it.
604
+ * @returns The texture, or `undefined` while the bundle is not loaded.
605
+ * @example
606
+ * ```ts
607
+ * // A game system builds one Pixi object by hand instead of using the Sprite component.
608
+ * const texture = app.assets.texture("board.cell"); // undefined until the board bundle lands
609
+ * ```
610
+ */
611
+ texture(key: string): Texture | undefined;
612
+ /**
613
+ * The font of a loaded asset key: the `.fnt` file as text and the texture of its first page.
614
+ * It touches the use counter of the bundle. A font of a bundle that is not loaded, a key of
615
+ * another kind and every headless run answer `undefined`.
616
+ *
617
+ * @param key - Asset key of a `.fnt` file, as `generated/assets.ts` types it in `FontKey`.
618
+ * @returns The font, or `undefined` while its bundle is not loaded.
619
+ * @example
620
+ * ```ts
621
+ * // `text` installs the font in the renderer when the bundle that carries it arrived.
622
+ * const font = app.assets.font("ui.body"); // { fnt: 'info face="body" size=32', texture }
623
+ *
624
+ * if (font !== undefined) app.renderer.sync.fonts.install("ui.body", font.fnt, font.texture);
625
+ * ```
626
+ */
627
+ font(key: string): FontAsset | undefined;
628
+ /**
629
+ * The bytes of a loaded audio file, exactly as they were fetched: this plugin never decodes
630
+ * them. It touches the use counter of the bundle. A bundle that is not loaded, a key of
631
+ * another kind and every headless run answer `undefined`.
632
+ *
633
+ * @param key - Asset key of an `.mp3` file, as `generated/assets.ts` types it in `AudioKey`.
634
+ * @returns The undecoded bytes, or `undefined` while its bundle is not loaded.
635
+ * @example
636
+ * ```ts
637
+ * // `audio` decodes a sound once and keeps it until the bundle is unloaded.
638
+ * const bytes = app.assets.audio("ui.click"); // the ArrayBuffer of click.mp3
639
+ * const buffer = bytes === undefined ? undefined : await context.decodeAudioData(bytes);
640
+ * ```
641
+ */
642
+ audio(key: string): ArrayBuffer | undefined;
643
+ /**
644
+ * What the loaded bundles cost, sorted by name. `lastUsed` is the use counter, not a clock.
645
+ *
646
+ * @returns The used and allowed megabytes and one entry per loaded bundle.
647
+ * @example
648
+ * ```ts
649
+ * // A dev overlay draws the memory bar of the game.
650
+ * const { textureMb, budgetMb, bundles } = app.assets.usage();
651
+ * // textureMb: 3.5, budgetMb: 192, bundles: [{ name: "board", tier: "scene", mb: 3.5, lastUsed: 12 }]
652
+ * ```
653
+ */
654
+ usage(): Usage;
655
+ };
656
+ /**
657
+ * Resolved dependency APIs.
658
+ */
659
+ type Deps = {
660
+ flow: Api$1;
661
+ renderer: Api$2;
662
+ time: Api$3;
663
+ };
664
+ /**
665
+ * What the kernel context offers before the deps are attached.
666
+ *
667
+ * `index.ts` writes `events` with an annotated `register` (core spec `14-EVENT-REGISTRATION.md`
668
+ * row 8), so the two own events reach the context the kernel hands the factories and `emit` is the
669
+ * kernel's own, assets-typed one. No member of the context is cast.
670
+ */
671
+ type KernelSlice = PluginCtx<Config, State, Events> & {
672
+ readonly global: object;
673
+ readonly log: Log.LogApi;
674
+ readonly require: Require;
675
+ };
676
+ /**
677
+ * Domain context shared by the files of the plugin.
678
+ */
679
+ type AssetsCtx = KernelSlice & {
680
+ readonly deps: Deps;
681
+ };
682
+ /**
683
+ * Payload of the one event assets listens to.
684
+ */
685
+ type FlowRest = {
686
+ path: string;
687
+ checkpoint: boolean;
688
+ };
689
+ //#endregion
690
+ export { DefineBundles as a, LoadReason as c, Tier as d, Usage as f, Config as i, Manifest as l, BundleMap as n, Events as o, types_d_exports as p, BundleSpec as r, LoadBundles as s, Api as t, State as u };