melonjs 20.12.0 → 20.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/README.md +66 -22
  2. package/build/application/application.d.ts +6 -1
  3. package/build/application/application.d.ts.map +1 -1
  4. package/build/application/header.d.ts.map +1 -1
  5. package/build/application/resize.d.ts.map +1 -1
  6. package/build/application/settings.d.ts +13 -8
  7. package/build/application/settings.d.ts.map +1 -1
  8. package/build/audio/audio.d.ts +8 -4
  9. package/build/audio/audio.d.ts.map +1 -1
  10. package/build/audio/backend/engine.d.ts.map +1 -1
  11. package/build/audio/playback.d.ts +2 -2
  12. package/build/audio/playback.d.ts.map +1 -1
  13. package/build/audio/spatial.d.ts.map +1 -1
  14. package/build/audio/types.d.ts +15 -5
  15. package/build/audio/types.d.ts.map +1 -1
  16. package/build/camera/camera2d.d.ts +12 -9
  17. package/build/camera/camera2d.d.ts.map +1 -1
  18. package/build/camera/camera3d.d.ts +11 -8
  19. package/build/camera/camera3d.d.ts.map +1 -1
  20. package/build/camera/effects/fade_effect.d.ts.map +1 -1
  21. package/build/geometries/ellipse.d.ts +3 -0
  22. package/build/geometries/ellipse.d.ts.map +1 -1
  23. package/build/geometries/line.d.ts.map +1 -1
  24. package/build/geometries/path2d.d.ts +9 -8
  25. package/build/geometries/path2d.d.ts.map +1 -1
  26. package/build/geometries/polygon.d.ts +2 -1
  27. package/build/geometries/polygon.d.ts.map +1 -1
  28. package/build/index.d.ts +14 -3
  29. package/build/index.d.ts.map +1 -1
  30. package/build/index.js +50215 -45051
  31. package/build/index.js.map +4 -4
  32. package/build/input/gamepad.d.ts.map +1 -1
  33. package/build/input/keyboard.d.ts.map +1 -1
  34. package/build/input/pointerevent.d.ts.map +1 -1
  35. package/build/level/gltf/GLTFModel.d.ts.map +1 -1
  36. package/build/level/level.d.ts.map +1 -1
  37. package/build/level/tiled/TMXLayer.d.ts +50 -15
  38. package/build/level/tiled/TMXLayer.d.ts.map +1 -1
  39. package/build/level/tiled/TMXTileMap.d.ts +14 -4
  40. package/build/level/tiled/TMXTileMap.d.ts.map +1 -1
  41. package/build/level/tiled/TMXTileset.d.ts.map +1 -1
  42. package/build/level/tiled/TMXUtils.d.ts.map +1 -1
  43. package/build/level/tiled/renderer/TMXHexagonalRenderer.d.ts.map +1 -1
  44. package/build/level/tiled/renderer/TMXIsometricRenderer.d.ts.map +1 -1
  45. package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts +1 -0
  46. package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts.map +1 -1
  47. package/build/level/tiled/renderer/TMXOrthogonalRenderer.d.ts.map +1 -1
  48. package/build/level/tiled/renderer/TMXRenderer.d.ts +7 -3
  49. package/build/level/tiled/renderer/TMXRenderer.d.ts.map +1 -1
  50. package/build/level/tiled/renderer/TMXStaggeredRenderer.d.ts.map +1 -1
  51. package/build/lighting/light3d.d.ts +55 -0
  52. package/build/lighting/light3d.d.ts.map +1 -1
  53. package/build/loader/cache.d.ts +146 -97
  54. package/build/loader/cache.d.ts.map +1 -1
  55. package/build/loader/internal-types.d.ts +69 -0
  56. package/build/loader/internal-types.d.ts.map +1 -0
  57. package/build/loader/loader.d.ts +589 -253
  58. package/build/loader/loader.d.ts.map +1 -1
  59. package/build/loader/parsers/audio.d.ts.map +1 -1
  60. package/build/loader/parsers/fontface.d.ts.map +1 -1
  61. package/build/loader/parsers/gltf.d.ts.map +1 -1
  62. package/build/loader/parsers/tmx.d.ts.map +1 -1
  63. package/build/math/color.d.ts +4 -0
  64. package/build/math/color.d.ts.map +1 -1
  65. package/build/math/math.d.ts +6 -1
  66. package/build/math/math.d.ts.map +1 -1
  67. package/build/math/noise.d.ts +16 -16
  68. package/build/math/noise.d.ts.map +1 -1
  69. package/build/math/observableVector2d.d.ts +6 -6
  70. package/build/math/observableVector2d.d.ts.map +1 -1
  71. package/build/math/observableVector3d.d.ts +8 -8
  72. package/build/math/observableVector3d.d.ts.map +1 -1
  73. package/build/particles/emitter.d.ts +15 -3
  74. package/build/particles/emitter.d.ts.map +1 -1
  75. package/build/particles/particle.d.ts +6 -0
  76. package/build/particles/particle.d.ts.map +1 -1
  77. package/build/particles/settings.d.ts +22 -5
  78. package/build/particles/settings.d.ts.map +1 -1
  79. package/build/physics/adapter.d.ts +64 -25
  80. package/build/physics/adapter.d.ts.map +1 -1
  81. package/build/physics/builtin/body.d.ts +23 -4
  82. package/build/physics/builtin/body.d.ts.map +1 -1
  83. package/build/physics/builtin/builtin-adapter.d.ts +25 -3
  84. package/build/physics/builtin/builtin-adapter.d.ts.map +1 -1
  85. package/build/physics/builtin/detector.d.ts.map +1 -1
  86. package/build/physics/builtin/raycast.d.ts.map +1 -1
  87. package/build/physics/world.d.ts +40 -10
  88. package/build/physics/world.d.ts.map +1 -1
  89. package/build/renderable/container.d.ts +41 -6
  90. package/build/renderable/container.d.ts.map +1 -1
  91. package/build/renderable/draggable.d.ts.map +1 -1
  92. package/build/renderable/frameAnimation.d.ts.map +1 -1
  93. package/build/renderable/instanced_mesh.d.ts +16 -14
  94. package/build/renderable/instanced_mesh.d.ts.map +1 -1
  95. package/build/renderable/mesh.d.ts +62 -5
  96. package/build/renderable/mesh.d.ts.map +1 -1
  97. package/build/renderable/renderable.d.ts.map +1 -1
  98. package/build/renderable/sprite.d.ts +4 -2
  99. package/build/renderable/sprite.d.ts.map +1 -1
  100. package/build/renderable/text/bitmaptext.d.ts +12 -3
  101. package/build/renderable/text/bitmaptext.d.ts.map +1 -1
  102. package/build/renderable/text/text.d.ts +147 -4
  103. package/build/renderable/text/text.d.ts.map +1 -1
  104. package/build/renderable/text/textmetrics.d.ts +10 -2
  105. package/build/renderable/text/textmetrics.d.ts.map +1 -1
  106. package/build/renderable/text/textstyle.d.ts.map +1 -1
  107. package/build/renderable/trigger.d.ts +5 -0
  108. package/build/renderable/trigger.d.ts.map +1 -1
  109. package/build/renderable/ui/panelpaint.d.ts +5 -1
  110. package/build/renderable/ui/panelpaint.d.ts.map +1 -1
  111. package/build/renderable/ui/progressbar.d.ts +267 -95
  112. package/build/renderable/ui/progressbar.d.ts.map +1 -1
  113. package/build/renderable/ui/uibaseelement.d.ts +443 -50
  114. package/build/renderable/ui/uibaseelement.d.ts.map +1 -1
  115. package/build/renderable/ui/uicheckbox.d.ts +383 -0
  116. package/build/renderable/ui/uicheckbox.d.ts.map +1 -0
  117. package/build/renderable/ui/uifocus.d.ts +6 -0
  118. package/build/renderable/ui/uifocus.d.ts.map +1 -0
  119. package/build/renderable/ui/uilabel.d.ts +31 -0
  120. package/build/renderable/ui/uilabel.d.ts.map +1 -0
  121. package/build/renderable/ui/uipanel.d.ts +589 -116
  122. package/build/renderable/ui/uipanel.d.ts.map +1 -1
  123. package/build/renderable/ui/uiskin.d.ts +25 -0
  124. package/build/renderable/ui/uiskin.d.ts.map +1 -0
  125. package/build/renderable/ui/uislider.d.ts +518 -0
  126. package/build/renderable/ui/uislider.d.ts.map +1 -0
  127. package/build/renderable/ui/uispriteelement.d.ts +161 -85
  128. package/build/renderable/ui/uispriteelement.d.ts.map +1 -1
  129. package/build/renderable/ui/uitextbutton.d.ts +369 -63
  130. package/build/renderable/ui/uitextbutton.d.ts.map +1 -1
  131. package/build/state/stage.d.ts.map +1 -1
  132. package/build/system/device.d.ts +11 -2
  133. package/build/system/device.d.ts.map +1 -1
  134. package/build/system/fullscreen.d.ts.map +1 -1
  135. package/build/system/pool.d.ts.map +1 -1
  136. package/build/system/save.d.ts +2 -1
  137. package/build/system/save.d.ts.map +1 -1
  138. package/build/tweens/tween.d.ts +5 -2
  139. package/build/tweens/tween.d.ts.map +1 -1
  140. package/build/utils/fetchdata.d.ts.map +1 -1
  141. package/build/utils/utils.d.ts.map +1 -1
  142. package/build/video/canvas/canvas_renderer.d.ts +16 -19
  143. package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
  144. package/build/video/canvas_factory.d.ts.map +1 -1
  145. package/build/video/effects/shadereffect.d.ts +127 -0
  146. package/build/video/effects/shadereffect.d.ts.map +1 -1
  147. package/build/video/renderer.d.ts +20 -4
  148. package/build/video/renderer.d.ts.map +1 -1
  149. package/build/video/renderstate.d.ts +26 -3
  150. package/build/video/renderstate.d.ts.map +1 -1
  151. package/build/video/utils/tessellation.d.ts +11 -0
  152. package/build/video/utils/tessellation.d.ts.map +1 -1
  153. package/build/video/webgl/batchers/lit_mesh_batcher.d.ts.map +1 -1
  154. package/build/video/webgl/webgl_renderer.d.ts +3 -6
  155. package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
  156. package/build/video/webgpu/batchers/lit_mesh_batcher.d.ts.map +1 -1
  157. package/build/video/webgpu/batchers/primitive_batcher.d.ts.map +1 -1
  158. package/build/video/webgpu/webgpu_renderer.d.ts +3 -6
  159. package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
  160. package/package.json +1 -1
  161. package/skills/melonjs/SKILL.md +41 -17
  162. package/skills/melonjs-20-migration/SKILL.md +50 -7
  163. package/skills/melonjs-3d/SKILL.md +138 -38
  164. package/skills/melonjs-3d-assets/SKILL.md +83 -33
  165. package/skills/melonjs-audio/SKILL.md +62 -19
  166. package/skills/melonjs-camera-and-drawing/SKILL.md +135 -8
  167. package/skills/melonjs-deployment/SKILL.md +92 -14
  168. package/skills/melonjs-display-and-scaling/SKILL.md +8 -3
  169. package/skills/melonjs-effects-and-shaders/SKILL.md +47 -15
  170. package/skills/melonjs-events/SKILL.md +6 -3
  171. package/skills/melonjs-getting-started/SKILL.md +6 -2
  172. package/skills/melonjs-input/SKILL.md +102 -16
  173. package/skills/melonjs-lighting/SKILL.md +13 -1
  174. package/skills/melonjs-loading-assets/SKILL.md +255 -39
  175. package/skills/melonjs-math/SKILL.md +26 -8
  176. package/skills/melonjs-particles-and-trails/SKILL.md +77 -9
  177. package/skills/melonjs-performance/SKILL.md +18 -8
  178. package/skills/melonjs-physics/SKILL.md +435 -128
  179. package/skills/melonjs-plugins/SKILL.md +50 -11
  180. package/skills/melonjs-renderables/SKILL.md +31 -7
  181. package/skills/melonjs-renderer-backends/SKILL.md +38 -17
  182. package/skills/melonjs-scenes-and-state/SKILL.md +45 -5
  183. package/skills/melonjs-sprites-and-animation/SKILL.md +37 -2
  184. package/skills/melonjs-tilemaps/SKILL.md +149 -17
  185. package/skills/melonjs-ui-and-text/SKILL.md +674 -42
@@ -1,19 +1,28 @@
1
1
 
2
2
  /**
3
- * Sets the options for the loader.
4
- * @param {Object} options - The options to set.
5
- * @param {string} [options.crossOrigin] - The crossOrigin attribute to configure the CORS requests for Image and Video data element.
6
- * @param {boolean} [options.nocache] - Enable or disable the nocache mechanism.
7
- * @param {boolean} [options.withCredentials] - Indicates whether or not cross-site Access-Control requests should be made using credentials.
3
+ * Set the loader's global options, for every asset loaded from then on.
4
+ * Each option left out keeps its current value.
5
+ * @param {Object} options - the options to set
6
+ * @param {string} [options.crossOrigin] - the `crossOrigin` attribute of the
7
+ * `<video>` and `<script>` elements and glTF images the loader creates
8
+ * (`"anonymous"` or `"use-credentials"`). Every other asset is always
9
+ * requested with CORS. See {@link crossOrigin}.
10
+ * @param {boolean} [options.nocache] - when true, append a random query
11
+ * string to every asset URL, so the browser fetches a fresh copy rather than
12
+ * a cached one (development only: it also defeats the HTTP cache in
13
+ * production)
14
+ * @param {boolean} [options.withCredentials] - whether requests to another
15
+ * origin carry credentials (cookies, HTTP authentication). Requests to the
16
+ * game's own origin always carry them. See {@link withCredentials}.
8
17
  * @example
9
- * // Set the crossOrigin attribute to "anonymous"
10
- * me.loader.setOptions({ crossOrigin: "anonymous" });
18
+ * // play videos from another origin, without credentials
19
+ * loader.setOptions({ crossOrigin: "anonymous" });
11
20
  *
12
- * // Enable the nocache mechanism
13
- * me.loader.setOptions({ nocache: true });
21
+ * // bypass the browser cache while developing
22
+ * loader.setOptions({ nocache: true });
14
23
  *
15
- * // Enable withCredentials
16
- * me.loader.setOptions({ withCredentials: true });
24
+ * // send cookies to a CDN that serves assets behind a login
25
+ * loader.setOptions({ withCredentials: true });
17
26
  * @category Assets
18
27
  */
19
28
  export function setOptions(options: {
@@ -22,95 +31,103 @@ export function setOptions(options: {
22
31
  withCredentials?: boolean | undefined;
23
32
  }): void;
24
33
  /**
25
- * change the default baseURL for the given asset type.<br>
26
- * (this will prepend the asset URL and must finish with a '/')
27
- * @public
28
- * @param {string} type - "*", "audio", "video", "binary", "image", "json", "js", "tmx", "tsx", "fontface", "aseprite", "shader", "obj", "mtl", "gltf", "glb"
29
- * @param {string} [url="./"] - default base URL
34
+ * Set the base URL prepended to the `src` of every asset of a type, so the
35
+ * descriptors need not repeat it. Applies to assets loaded from then on; a
36
+ * data URI `src` is never prefixed.
37
+ *
38
+ * `"*"` sets it for every built-in type except `obj`, `mtl`, `gltf` and
39
+ * `glb`, which resolve their own references (a `map_Kd` texture, a glTF
40
+ * buffer) relative to their file and would be prefixed twice: set those one
41
+ * by one. Custom types registered with {@link setParser} are not covered by
42
+ * `"*"` either.
43
+ * @param {string} type - the asset type ("audio", "video", "binary", "image",
44
+ * "json", "js", "tmx", "tsx", "fontface", "aseprite", "shader", "obj", "mtl",
45
+ * "gltf", "glb", or a custom type), or `"*"`
46
+ * @param {string} [url="./"] - the base URL, ending with a `/`
30
47
  * @example
31
- * // change the base URL relative address for audio assets
32
- * me.loader.setBaseURL("audio", "data/audio/");
33
- * // change the base URL absolute address for all object types
34
- * me.loader.setBaseURL("*", "http://myurl.com/")
48
+ * // a relative path for the images
49
+ * loader.setBaseURL("image", "data/img/");
50
+ * // so that a descriptor names the file alone: loads data/img/player.png
51
+ * await loader.preload([{ name: "player", type: "image", src: "player.png" }]);
52
+ *
53
+ * // or an absolute URL for every 2D asset type at once
54
+ * loader.setBaseURL("*", "https://cdn.example.com/");
35
55
  * @category Assets
36
56
  */
37
57
  export function setBaseURL(type: string, url?: string): void;
38
58
  /**
39
- * A registered parser, normalized by {@link loader.setParser}.
40
- *
41
- * Every type gets the same shape whether or not it needs the src hooks, so
42
- * `load()` can treat all of them alike. The alternative — a bare function that
43
- * some types decorate with extra properties — puts the knowledge of which
44
- * types are special back into the caller, which is what moving it out was for.
45
- * @typedef {object} AssetParser
46
- * @property {Function} parse - preloads the asset and returns how many
47
- * resources it will load (0 when already cached)
48
- * @property {function(string): string} normalizeSrc - turns a type-specific
49
- * descriptor into a bare path, before any base URL is applied. Identity unless
50
- * the type overrides it
51
- * @property {function(string): boolean} needsBaseURL - whether the normalized
52
- * src is relative to this type's base URL. Declares only this type's own
53
- * exceptions, such as a `local()` font naming an installed family — data URIs
54
- * are excluded for every type before this is consulted
55
- * @ignore
56
- * @internal
57
- */
58
- /**
59
- * an asset definition to be used with the loader
59
+ * An asset descriptor: what to load, and the name to keep it under. The same
60
+ * descriptors go in a {@link preload} list, in a bundle ({@link setBundle}),
61
+ * or to {@link load} on their own.
62
+ *
63
+ * The type and the name together identify an asset, so two assets of
64
+ * different types may share a name: a texture atlas is usually an `"image"`
65
+ * and a `"json"` both called `"texture"`.
60
66
  * @typedef {object} Asset
61
- * @property {string} name - name of the asset
62
- * @property {string} type - the type of the asset ("audio"|"binary"|"image"|"json"|"js"|"tmx"|"tsx"|"fontface"|"video"|"aseprite"|"shader"|"obj"|"mtl"|"gltf"|"glb"). JSON-serialised Tiled maps and tilesets (`.tmj` / `.tsj`) load under `"tmx"` / `"tsx"` — those are file extensions, not asset types. Any other type is one registered with {@link loader.setParser}.
63
- * @property {string|string[]} [src] - path and/or file name of the resource (for audio assets only the path is required).
64
- * For image assets, an array of sources can be provided as a fallback chain (e.g. compressed texture formats by priority, with a PNG fallback).
65
- * The loader will try each source in order and use the first one that loads successfully.
66
- * @property {string|{glsl?: string, wgsl?: string}} [data] - inline content if not provided through a src url: TMX data for "tmx" assets, GLSL source (the ShaderEffect fragment-body convention) for "shader" assets. A shader may instead carry a `{glsl, wgsl}` pair, so one asset serves both backends; either half may be omitted
67
- * @property {boolean} [stream=false] - Set to true to not to wait for large audio or video file to be downloaded before playing.
68
- * @property {boolean} [autoplay=false] - Set to true to automatically start playing audio or video when loaded or added to a scene (using autoplay might require user iteraction to enable it)
69
- * @property {boolean} [loop=false] - Set to true to automatically loop the audio or video when playing
67
+ * @property {string} name - the name the asset is kept and read back under
68
+ * (`loader.getImage(name)`, `new Sprite(x, y, { image: name })`,
69
+ * `level.load(name)`, `audio.play(name)`)
70
+ * @property {string} type - the type of the asset, which picks its parser:
71
+ * "audio", "binary", "image", "json", "js", "tmx", "tsx", "fontface", "video",
72
+ * "aseprite", "shader", "obj", "mtl", "gltf" or "glb". JSON-serialised Tiled
73
+ * maps and tilesets (`.tmj` / `.tsj`) load under `"tmx"` / `"tsx"`: those are
74
+ * file extensions, not asset types. Any other type is one registered with
75
+ * {@link loader.setParser}.
76
+ * @property {string|string[]} [src] - the URL of the file, relative to the
77
+ * page or to the type's base URL ({@link setBaseURL}), or a data URI.
78
+ * For `"audio"` it is the **directory** holding the clip: the loader appends
79
+ * the asset name and each extension given to `audio.init()`, and keeps the
80
+ * first that decodes.
81
+ * For `"image"` it may be an array of sources, tried in order until one loads:
82
+ * a fallback chain, such as compressed texture formats by priority with a PNG
83
+ * last.
84
+ * For `"shader"` it may be an object of URLs instead (see the example).
85
+ * @property {string|{glsl?: string, wgsl?: string}} [data] - inline content
86
+ * in place of a `src`: the parsed Tiled JSON map or tileset (an object) for
87
+ * `"tmx"` / `"tsx"`, the GLSL source of an effect body for `"shader"`, or a
88
+ * `{glsl, wgsl}` pair of them so that one asset serves both backends (either
89
+ * half may be omitted)
90
+ * @property {boolean} [stream=false] - audio and video: start playing before
91
+ * the whole file is downloaded, rather than waiting for it
92
+ * @property {boolean} [autoplay=false] - audio and video: start playing once
93
+ * loaded, or once added to a scene (a browser may require a user interaction
94
+ * first)
95
+ * @property {boolean} [loop=false] - audio and video: loop when playing
70
96
  * @see {@link preload}
71
97
  * @see {@link load}
98
+ * @see {@link setBundle}
72
99
  * @example
73
- * // PNG tileset
74
- * {name: "tileset-platformer", type: "image", src: "data/map/tileset.png"}
75
- * // PNG packed texture
76
- * {name: "texture", type:"image", src: "data/gfx/texture.png"}
77
- * // PNG base64 encoded image
78
- * {name: "texture", type:"image", src: "data:image/png;base64,iVBORw0KAAAQAAAAEACA..."}
79
- * // compressed texture with fallback chain (tries each source in order until one succeeds)
80
- * {name: "terrain", type:"image", src: ["data/gfx/terrain.astc.ktx", "data/gfx/terrain.dds", "data/gfx/terrain.png"]}
81
- * // TSX file
82
- * {name: "meta_tiles", type: "tsx", src: "data/map/meta_tiles.tsx"}
83
- * // TMX level (XML & JSON)
84
- * {name: "map1", type: "tmx", src: "data/map/map1.json"}
85
- * {name: "map2", type: "tmx", src: "data/map/map2.tmx"}
86
- * {name: "map3", type: "tmx", format: "json", data: {"height":15,"layers":[...],"tilewidth":32,"version":1,"width":20}}
87
- * {name: "map4", type: "tmx", format: "xml", data: {xml representation of tmx}}
88
- * // audio resources
89
- * {name: "bgmusic", type: "audio", src: "data/audio/"}
90
- * {name: "cling", type: "audio", src: "data/audio/"}
91
- * // base64 encoded audio resources
92
- * {name: "band", type: "audio", src: "data:audio/wav;base64,..."}
93
- * // binary file
94
- * {name: "ymTrack", type: "binary", src: "data/audio/main.ym"}
95
- * // JSON file (used for texturePacker)
96
- * {name: "texture", type: "json", src: "data/gfx/texture.json"}
97
- * // JSON file holding collision shapes drawn in a physics-shape editor,
98
- * // named by a body definition as `{ shapes: "shapes", id: <body name> }`
99
- * {name: "shapes", type: "json", src: "data/physics/shapes.json"}
100
- * // JavaScript file
101
- * {name: "plugin", type: "js", src: "data/js/plugin.js"}
102
- * // Font Face
103
- * { name: "'kenpixel'", type: "fontface", src: "data/font/kenvector_future.woff2" }
104
- * // video resources
105
- * {name: "intro", type: "video", src: "data/video/"}
106
- * // 3D assets: Wavefront OBJ model + MTL material library
107
- * {name: "ship", type: "obj", src: "data/models/ship.obj"}
108
- * {name: "ship", type: "mtl", src: "data/models/ship.mtl"}
109
- * // glTF / GLB scene (auto-registers with the level director)
110
- * {name: "diorama", type: "glb", src: "data/scenes/diorama.glb"}
111
- * // shader assets: an effect body, or a complete dual-backend program
112
- * {name: "flash", type: "shader", src: "shaders/flash.frag"}
113
- * {name: "toon", type: "shader", src: {vertex: "shaders/toon.vert", fragment: "shaders/toon.frag", wgsl: "shaders/toon.wgsl"}}
100
+ * // images: a file, a data URI, or a fallback chain (first that loads wins)
101
+ * { name: "tileset", type: "image", src: "data/img/tileset.png" }
102
+ * { name: "logo", type: "image", src: "data:image/png;base64,iVBORw0KGgo..." }
103
+ * { name: "terrain", type: "image", src: ["data/gfx/terrain.astc.ktx", "data/gfx/terrain.dds", "data/gfx/terrain.png"] }
104
+ * // a texture atlas: its image and its JSON descriptor, under the same name
105
+ * { name: "texture", type: "image", src: "data/gfx/texture.png" }
106
+ * { name: "texture", type: "json", src: "data/gfx/texture.json" }
107
+ * // Tiled: a map (XML or JSON), an external tileset, or a map given inline
108
+ * { name: "map1", type: "tmx", src: "data/map/map1.tmx" }
109
+ * { name: "map2", type: "tmx", src: "data/map/map2.tmj" }
110
+ * { name: "tileset", type: "tsx", src: "data/map/tileset.tsx" }
111
+ * { name: "map3", type: "tmx", data: { width: 20, height: 15, tilewidth: 32, tileheight: 32, layers: [], tilesets: [] } }
112
+ * // audio: src is the directory, the extension comes from audio.init()
113
+ * { name: "cling", type: "audio", src: "data/sfx/" }
114
+ * { name: "bgmusic", type: "audio", src: "data/bgm/", stream: true }
115
+ * // video: src is the file
116
+ * { name: "intro", type: "video", src: "data/video/intro.mp4" }
117
+ * // other data: raw bytes, JSON (collision shapes from a shape editor), a script
118
+ * { name: "ymTrack", type: "binary", src: "data/audio/main.ym" }
119
+ * { name: "shapes", type: "json", src: "data/physics/shapes.json" }
120
+ * { name: "plugin", type: "js", src: "data/js/plugin.js" }
121
+ * // a web font, used by its name as a CSS font family
122
+ * { name: "kenpixel", type: "fontface", src: "data/font/kenvector_future.woff2" }
123
+ * // 3D: a Wavefront OBJ model and its MTL materials, or a glTF/GLB scene
124
+ * // (which registers with the level director, like a Tiled map)
125
+ * { name: "ship", type: "obj", src: "data/models/ship.obj" }
126
+ * { name: "ship", type: "mtl", src: "data/models/ship.mtl" }
127
+ * { name: "diorama", type: "glb", src: "data/scenes/diorama.glb" }
128
+ * // shaders: an effect body, or a complete program for both backends
129
+ * { name: "flash", type: "shader", src: "shaders/flash.frag" }
130
+ * { name: "toon", type: "shader", src: { vertex: "shaders/toon.vert", fragment: "shaders/toon.frag", wgsl: "shaders/toon.wgsl" } }
114
131
  */
115
132
  /**
116
133
  * Teach the loader an asset type of your own, or replace the parser of an
@@ -140,6 +157,7 @@ export function setBaseURL(type: string, url?: string): void;
140
157
  * this type by name: the `"*"` wildcard does not cover custom types.
141
158
  * @param {string} type - asset type
142
159
  * @param {Function} parserFn - parser function, as described above
160
+ * @throws {Error} when `parserFn` is not a function
143
161
  * @see {@link Asset.type}
144
162
  * @example
145
163
  * // a texture generated in code rather than loaded, baked behind the
@@ -180,129 +198,438 @@ export function setBaseURL(type: string, url?: string): void;
180
198
  */
181
199
  export function setParser(type: string, parserFn: Function): void;
182
200
  /**
183
- * set all the specified game assets to be preloaded.
184
- * @param {Asset[]} assets - list of assets to load
185
- * @param {Function} [onloadcb=loader.onload] - function to be called when all resources are loaded
186
- * @param {boolean} [switchToLoadState=true] - automatically switch to the loading screen
187
- * @returns {Promise<void>} resolves once every asset has loaded (rejects on a
188
- * load failure). The `onloadcb` callback is still invoked on success, so both
189
- * the callback and `await` forms work — use whichever you prefer.
201
+ * Declare every bundle of a record and load them all, behind the loading
202
+ * screen: the boot call of a game with several levels, given the record its
203
+ * assets file exports (`{ common: [...], level1: [...], ... }`).
204
+ *
205
+ * Each key becomes a bundle, exactly as {@link loader.setBundle} would make
206
+ * it, with the same checks. A bundle already declared with the same assets
207
+ * is left as it is; one declared with other assets is redefined, which throws
208
+ * while it is loaded or loading. Every key is checked before any is declared,
209
+ * so a bad one throws with nothing changed.
210
+ *
211
+ * Every bundle is then loaded as one preload, as with a flat list: one
212
+ * progress bar over all their assets (an asset several bundles list is loaded
213
+ * once, and counted once), the shader warm-up, then the callback,
214
+ * `LOADER_COMPLETE`, and the promise resolves. From there each bundle is
215
+ * loaded as if by `load(id)`: `loader.unload(id)` frees the assets only that
216
+ * bundle holds, and `loader.load(id)` brings them back. Calling it again
217
+ * fetches nothing already in memory.
218
+ * @overload
219
+ * @param {Object<string, Asset[]>} bundles - bundle id → its asset descriptors
220
+ * @param {Function} [onloadcb] - called once every asset has loaded, before
221
+ * `LOADER_COMPLETE`
222
+ * @param {boolean} [switchToLoadState=true] - switch to the loading screen
223
+ * (`state.LOADING`) while loading
224
+ * @returns {Promise<void>} resolves once every asset has loaded; rejects if
225
+ * one fails to load
226
+ * @throws {TypeError} synchronously, when `bundles` is not a record of asset
227
+ * arrays — a single asset descriptor passed by mistake included (wrap it in
228
+ * an array)
229
+ * @throws {Error} synchronously, when a key names a bundle that is loaded or
230
+ * loading with other assets, or an asset has an unknown type
190
231
  * @example
191
- * game.assets = [
192
- * // PNG tileset
193
- * {name: "tileset-platformer", type: "image", src: "data/map/tileset.png"},
194
- * // PNG packed texture
195
- * {name: "texture", type:"image", src: "data/gfx/texture.png"}
196
- * // PNG base64 encoded image
197
- * {name: "texture", type:"image", src: "data:image/png;base64,iVBORw0KAAAQAAAAEACA..."},
198
- * // compressed texture with fallback chain (tries each source in order until one succeeds)
199
- * {name: "terrain", type:"image", src: ["data/gfx/terrain.astc.ktx", "data/gfx/terrain.dds", "data/gfx/terrain.png"]},
200
- * // TSX file
201
- * {name: "meta_tiles", type: "tsx", src: "data/map/meta_tiles.tsx"},
202
- * // TMX level (XML & JSON)
203
- * {name: "map1", type: "tmx", src: "data/map/map1.json"},
204
- * {name: "map2", type: "tmx", src: "data/map/map2.tmx"},
205
- * {name: "map3", type: "tmx", format: "json", data: {"height":15,"layers":[...],"tilewidth":32,"version":1,"width":20}},
206
- * {name: "map4", type: "tmx", format: "xml", data: {xml representation of tmx}},
207
- * // audio resources
208
- * {name: "bgmusic", type: "audio", src: "data/audio/"},
209
- * {name: "cling", type: "audio", src: "data/audio/"},
210
- * // base64 encoded audio resources
211
- * {name: "band", type: "audio", src: "data:audio/wav;base64,..."},
212
- * // binary file
213
- * {name: "ymTrack", type: "binary", src: "data/audio/main.ym"},
214
- * // JSON file (used for texturePacker)
215
- * {name: "texture", type: "json", src: "data/gfx/texture.json"},
216
- * // JSON file holding collision shapes drawn in a physics-shape editor,
217
- * // named by a body definition as `{ shapes: "shapes", id: <body name> }`
218
- * {name: "shapes", type: "json", src: "data/physics/shapes.json"},
219
- * // JavaScript file
220
- * {name: "plugin", type: "js", src: "data/js/plugin.js"},
221
- * // Font Face
222
- * {name: "'kenpixel'", type: "fontface", src: "data/font/kenvector_future.woff2"},
223
- * // video resources
224
- * {name: "intro", type: "video", src: "data/video/"},
225
- * // base64 encoded video asset
226
- * me.loader.load({name: "avatar", type:"video", src: "data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZ..."};
232
+ * // resources.js: what every level uses, then each level's own assets
233
+ * export default {
234
+ * common: [
235
+ * { name: "player", type: "image", src: "img/player.png" },
236
+ * { name: "jump", type: "audio", src: "sfx/" },
237
+ * ],
238
+ * map1: [
239
+ * { name: "map1", type: "tmx", src: "map/map1.tmx" },
240
+ * { name: "hills", type: "image", src: "img/hills.png" },
241
+ * ],
242
+ * map2: [
243
+ * { name: "map2", type: "tmx", src: "map/map2.tmx" },
244
+ * { name: "hills", type: "image", src: "img/hills.png" }, // shared
245
+ * ],
246
+ * };
247
+ *
248
+ * // game.js: the same call as with a flat list
249
+ * import resources from "./resources.js";
250
+ * await loader.preload(resources);
251
+ * state.change(state.PLAY);
252
+ * @category Assets
253
+ */
254
+ export function preload(bundles: {
255
+ [x: string]: Asset[];
256
+ }, onloadcb?: Function | undefined, switchToLoadState?: boolean | undefined): Promise<void>;
257
+ /**
258
+ * Load a list of assets behind the loading screen: the boot call.
259
+ *
260
+ * It switches to the loading screen (`state.LOADING`, unless told not to),
261
+ * loads every asset of the list, warms the shaders (see the `prewarm`
262
+ * application setting), then calls `onloadcb`, emits `LOADER_COMPLETE`, and
263
+ * resolves. Each call has
264
+ * only its own callback: a preload given none calls nothing on completion,
265
+ * whatever an earlier preload was given.
266
+ *
267
+ * Progress is reported through {@link event.LOADER_PROGRESS} as the share of
268
+ * this call's assets loaded so far, reaching 1 with the last of them. A
269
+ * preload started while another is still loading joins it, and the progress
270
+ * then covers the assets of both; once they have all settled, the next
271
+ * preload counts from zero again.
272
+ *
273
+ * If an asset fails to load, {@link event.LOADER_ERROR} is emitted with it,
274
+ * the promise rejects, and neither the callback nor `LOADER_COMPLETE` comes;
275
+ * {@link loader.reload} retries the asset and then completes this preload.
276
+ *
277
+ * The list may also name bundles declared with {@link loader.setBundle},
278
+ * mixed freely with asset descriptors: each id stands for the assets of that
279
+ * bundle, and those bundles are loaded by this call exactly as `load(id)`
280
+ * would load them. An asset that appears more than once (in two bundles, or
281
+ * in a bundle and directly) is loaded once. An asset listed directly is
282
+ * pinned: no bundle unload frees it, only {@link loader.unload} with the
283
+ * descriptor, or {@link loader.unloadAll}.
284
+ * @overload
285
+ * @param {Array<Asset|string>} assets - the asset descriptors to load,
286
+ * and/or ids of bundles declared with {@link loader.setBundle}
287
+ * @param {Function} [onloadcb] - called once every asset has loaded, before
288
+ * `LOADER_COMPLETE`
289
+ * @param {boolean} [switchToLoadState=true] - switch to the loading screen
290
+ * (`state.LOADING`) while loading
291
+ * @returns {Promise<void>} resolves once every asset has loaded (after the
292
+ * callback, which is still called: use either form); rejects if one fails to
293
+ * load
294
+ * @throws {Error} synchronously, on an unknown bundle id (before anything is
295
+ * loaded) or an unknown asset type
296
+ * @example
297
+ * import { loader, state } from "melonjs";
298
+ *
299
+ * const resources = [
300
+ * // an image, and a texture atlas (its image and JSON descriptor)
301
+ * { name: "background", type: "image", src: "data/img/background.png" },
302
+ * { name: "texture", type: "image", src: "data/img/texture.png" },
303
+ * { name: "texture", type: "json", src: "data/img/texture.json" },
304
+ * // a Tiled map, its external tileset and the tileset's image
305
+ * { name: "map1", type: "tmx", src: "data/map/map1.tmx" },
306
+ * { name: "tileset", type: "tsx", src: "data/map/tileset.tsx" },
307
+ * { name: "tileset", type: "image", src: "data/map/tileset.png" },
308
+ * // sounds: src is the directory (see audio.init)
309
+ * { name: "jump", type: "audio", src: "data/sfx/" },
310
+ * // a web font
311
+ * { name: "PressStart2P", type: "fontface", src: "data/fnt/PressStart2P.ttf" },
227
312
  * ];
228
- * ...
229
- * // set all resources to be loaded (callback form)
230
- * me.loader.preload(game.assets, () => this.loaded());
231
- * // ...or await it (the callback still fires too)
232
- * await me.loader.preload(game.assets);
313
+ *
314
+ * // await it...
315
+ * await loader.preload(resources);
316
+ * state.change(state.PLAY);
317
+ *
318
+ * // ...or pass a callback
319
+ * loader.preload(resources, () => {
320
+ * state.change(state.PLAY);
321
+ * });
322
+ * @example
323
+ * // bundles and descriptors in one list
324
+ * loader.setBundle("common", commonAssets);
325
+ * loader.setBundle("level1", level1Assets);
326
+ * await loader.preload([
327
+ * "common",
328
+ * "level1",
329
+ * { name: "logo", type: "image", src: "img/logo.png" },
330
+ * ]);
233
331
  * @category Assets
234
332
  */
235
- export function preload(assets: Asset[], onloadcb?: Function, switchToLoadState?: boolean): Promise<void>;
333
+ export function preload(assets: Array<Asset | string>, onloadcb?: Function | undefined, switchToLoadState?: boolean | undefined): Promise<void>;
236
334
  /**
237
- * retry loading assets after a loading failure
238
- * @param {string} src - src of asset to reload
335
+ * Retry an asset that failed to load in a {@link loader.preload} (or a
336
+ * `load(id)`), given its `src` as reported by {@link event.LOADER_ERROR}.
337
+ *
338
+ * The retried asset counts towards the progress of the call it failed in,
339
+ * and once every asset of that call has loaded, that call completes: its own
340
+ * callback is called, if it was given one, and `LOADER_COMPLETE` is emitted.
341
+ * The promise that call returned has already rejected, and stays rejected.
342
+ * The asset then belongs to whoever asked for it: pinned if it was listed
343
+ * directly, held by its bundles if a bundle asked for it. Should it fail
344
+ * again, `LOADER_ERROR` is emitted again.
345
+ * @param {string} src - the `src` of the asset to retry, exactly as in its
346
+ * descriptor (`asset.src` of the asset `LOADER_ERROR` passed)
347
+ * @throws {TypeError} when no failed asset has that `src`
239
348
  * @example
240
- * event.on(
241
- * event.LOADER_ERROR,
242
- * (res) => {
243
- * // custom function
244
- * showErrorNotification({
245
- * text: `Error during loading content: ${res.name}`,
246
- * done: loader.reload(res.src);
247
- * })
248
- * }
249
- * );
250
- **/
349
+ * import { event, loader } from "melonjs";
350
+ *
351
+ * event.on(event.LOADER_ERROR, (asset) => {
352
+ * // the game's own dialog, with a "retry" button
353
+ * showErrorDialog(`Could not load ${asset.name}`, () => {
354
+ * loader.reload(asset.src);
355
+ * });
356
+ * });
357
+ * @category Assets
358
+ */
251
359
  export function reload(src: string): void;
252
360
  /**
253
- * Load a single asset (to be used if you need to load additional asset(s) during the game)
254
- * @param {Asset} asset
255
- * @param {Function} [onload] - function to be called when the asset is loaded
256
- * @param {Function} [onerror] - function to be called in case of error
257
- * @returns {number|Promise<void>} with `onload`/`onerror` provided, the amount
258
- * of corresponding resource to be preloaded (the legacy callback form). With
259
- * **both omitted**, a Promise that resolves once the asset has loaded, so you
260
- * can `await loader.load(asset)` for a one-off dynamic load.
361
+ * Declare a bundle and load it, in one call: exactly
362
+ * {@link loader.setBundle} with these assets followed by `load(id)`, so the
363
+ * same checks, the same progress and shader warm-up, `LOADER_COMPLETE`, and
364
+ * the same promise. Handy where a level's assets are declared next to the
365
+ * code that enters it.
366
+ *
367
+ * Called again with the same assets (same type, name and src, in any order),
368
+ * it simply loads the bundle, fetching nothing already in memory. With
369
+ * different assets it redefines the bundle, which is allowed only while that
370
+ * bundle is not loaded or loading, and throws synchronously otherwise, as
371
+ * `setBundle` does. Release it with {@link loader.unload} and its id.
372
+ * @overload
373
+ * @param {string} id - the bundle id
374
+ * @param {Asset[]|Asset} assets - the bundle's asset descriptors (one
375
+ * descriptor on its own is accepted too)
376
+ * @returns {Promise<void>} resolves once every asset of the bundle has
377
+ * loaded; rejects if one fails to load
378
+ * @throws {TypeError} synchronously, on an invalid id or asset list
379
+ * @throws {Error} synchronously, when the bundle is loaded or loading with
380
+ * other assets, or an asset has an unknown type
261
381
  * @example
262
- * // load an image asset (callback form)
263
- * me.loader.load({name: "avatar", type:"image", src: "data/avatar.png"}, () => this.onload(), () => this.onerror());
264
- * // ...or await a single dynamic asset (no callbacks)
265
- * await me.loader.load({name: "avatar", type: "image", src: "data/avatar.png"});
266
- * // load a compressed texture with fallback chain
267
- * me.loader.load({name: "terrain", type:"image", src: ["data/gfx/terrain.astc.ktx", "data/gfx/terrain.dds", "data/gfx/terrain.png"]}, () => this.onload());
268
- * // load a base64 image asset
269
- * me.loader.load({name: "avatar", type:"image", src: "data:image/png;base64,iVBORw0KAAAQAAAAEACA..."};
270
- * // load a base64 video asset
271
- * me.loader.load({
272
- * name: "avatar",
273
- * type:"video",
274
- * src: "data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZ.."
275
- * };
276
- * // start loading music
277
- * me.loader.load({
278
- * name : "bgmusic",
279
- * type : "audio",
280
- * src : "data/audio/"
281
- * }, function () {
282
- * me.audio.play("bgmusic");
382
+ * // a level's assets, declared where they are loaded
383
+ * await loader.load("level2", [
384
+ * { name: "level2", type: "tmx", src: "data/map/level2.tmx" },
385
+ * { name: "tiles", type: "image", src: "data/img/tiles.png" },
386
+ * ]);
387
+ * await level.load("level2", { async: true });
388
+ * // ...and later, by id as usual
389
+ * loader.unload("level2");
390
+ * @category Assets
391
+ */
392
+ export function load(id: string, assets: Asset[] | Asset): Promise<void>;
393
+ /**
394
+ * Load a bundle declared with {@link loader.setBundle} (or by a record
395
+ * passed to {@link loader.preload}), while the game keeps running.
396
+ *
397
+ * Every asset of the bundle that is not already in memory is loaded, then the
398
+ * shaders are warmed, as {@link loader.preload} does: `LOADER_PROGRESS`
399
+ * reports this call's assets (each asset is one step, and one already in
400
+ * memory counts as a step done at once), then `onload` is called,
401
+ * `LOADER_COMPLETE` is emitted and the promise resolves. Unlike `preload` it
402
+ * does NOT switch to the loading screen; to show it for a level, use
403
+ * `loader.preload([id])`.
404
+ *
405
+ * The bundle then holds its assets: they stay in memory until
406
+ * {@link loader.unload} with the same id releases them, and are freed then
407
+ * unless another loaded bundle lists them too, or they were loaded the old
408
+ * way (by `preload` / `load` with a descriptor), which pins them. Assets keep
409
+ * their own names: `getImage("tiles")` reads a bundle's image as any other.
410
+ *
411
+ * If an asset fails to load, `LOADER_ERROR` is emitted with it, `onerror` is
412
+ * called and the promise rejects; the assets that did load stay, held by the
413
+ * bundle, and {@link loader.reload} retries the one that failed.
414
+ * @overload
415
+ * @param {string} id - the id of a declared bundle
416
+ * @param {Function} [onload] - called once every asset of the bundle has
417
+ * loaded, before `LOADER_COMPLETE`
418
+ * @param {Function} [onerror] - called with the error if an asset fails to
419
+ * load (the returned promise then needs no `catch` of its own)
420
+ * @returns {Promise<void>} resolves once the bundle is loaded, with or
421
+ * without the callbacks; rejects if an asset fails to load
422
+ * @throws {Error} synchronously, when no bundle is declared under that id
423
+ * @example
424
+ * // before entering a level that may have been unloaded: fetches only what
425
+ * // is missing, and nothing at all when the bundle is still in memory
426
+ * await loader.load("level1");
427
+ * await level.load("level1", { async: true });
428
+ * @example
429
+ * // the next level's assets, loaded while the current one keeps playing
430
+ * loader.load("level3", () => {
431
+ * nextLevelReady = true;
283
432
  * });
284
433
  * @category Assets
285
434
  */
286
- export function load(asset: Asset, onload?: Function, onerror?: Function): number | Promise<void>;
435
+ export function load(id: string, onload?: Function | undefined, onerror?: Function | undefined): Promise<void>;
436
+ /**
437
+ * Load a single asset, and wait for it: for an asset needed during the game
438
+ * that was not preloaded.
439
+ *
440
+ * No loading screen, progress or loader event: the promise is the only
441
+ * signal. An asset already in memory resolves at once, without a request
442
+ * (for every type but `"binary"`, `"fontface"`, `"aseprite"` and `"js"`,
443
+ * which are fetched again). The asset is pinned: unloading a bundle that also lists it does not free it,
444
+ * {@link loader.unload} with the descriptor does.
445
+ * @overload
446
+ * @param {Asset} asset - the asset to load
447
+ * @returns {Promise<void>} resolves once the asset has loaded; rejects with
448
+ * the error if it fails to load
449
+ * @throws {Error} synchronously, when the asset type is unknown
450
+ * @example
451
+ * await loader.load({ name: "avatar", type: "image", src: "data/img/avatar.png" });
452
+ * const avatar = new Sprite(0, 0, { image: "avatar" });
453
+ * @category Assets
454
+ */
455
+ export function load(asset: Asset): Promise<void>;
456
+ /**
457
+ * Load a single asset, with callbacks: the original form of
458
+ * `load(asset)`, for an asset needed during the game that was not preloaded.
459
+ *
460
+ * No loading screen, progress or loader event: the callbacks are the only
461
+ * signal. The asset is pinned: unloading a bundle that also lists it does not
462
+ * free it, {@link loader.unload} with the descriptor does.
463
+ * @overload
464
+ * @param {Asset} asset - the asset to load
465
+ * @param {Function} [onload] - called once the asset has loaded. Not called
466
+ * for an asset already in memory: the function then returns `0` (for every
467
+ * type but `"binary"`, `"fontface"`, `"aseprite"` and `"js"`, which are
468
+ * fetched again)
469
+ * @param {Function} [onerror] - called with the error if it fails to load
470
+ * @returns {number|Promise<void>} the number of resources it started loading
471
+ * (usually `1`), or `0` when the asset was already in memory. With `onload`
472
+ * and `onerror` both undefined it is the promise form above, and returns a
473
+ * promise
474
+ * @throws {Error} synchronously, when the asset type is unknown
475
+ * @example
476
+ * loader.load(
477
+ * { name: "bgmusic", type: "audio", src: "data/bgm/" },
478
+ * () => audio.play("bgmusic"),
479
+ * (error) => console.warn("no music", error),
480
+ * );
481
+ * @category Assets
482
+ */
483
+ export function load(asset: Asset, onload?: Function | undefined, onerror?: Function | undefined): number | Promise<void>;
287
484
  /**
288
- * unload the specified asset to free memory
289
- * @param {Asset} asset
290
- * @returns {boolean} true if unloaded
291
- * @example me.loader.unload({name: "avatar", type:"image"});
485
+ * Release a bundle, or free a single asset: a string is a bundle id, an
486
+ * object is an asset descriptor. So `loader.unload("map1")` releases the
487
+ * bundle `"map1"`, and `loader.unload({ name: "map1", type: "tmx" })` frees
488
+ * that one map, whichever bundles list it.
489
+ *
490
+ * **With a bundle id** (see {@link loader.setBundle}), the bundle lets go of
491
+ * each of its assets, and every one that nothing else still holds is freed:
492
+ * an asset another loaded bundle lists stays, and so does one loaded the old
493
+ * way (by `preload` / `load` with a descriptor), which pins it. Freeing a map
494
+ * or a glTF scene this way also unregisters its level, so `level.load` of it
495
+ * throws "not found" until the bundle is loaded again. Unload the bundle of
496
+ * the level being left once the next level is in: unloading the bundle of the
497
+ * level being played leaves the world as it is, but with no current level,
498
+ * so `level.reload()` has nothing to reload. Allowed while the bundle is
499
+ * still loading: its assets are then freed as they arrive.
500
+ *
501
+ * **With an asset descriptor** (only `name` and `type` are read), the asset is
502
+ * freed at once, whoever holds it: a bundle listing it reports
503
+ * {@link loader.isLoaded} `false` afterwards, and loading that bundle again
504
+ * fetches it again.
505
+ *
506
+ * Either way, freeing an image also frees the texture the renderer uploaded
507
+ * from it, a shader its GPU program, a font its place in `document.fonts`.
508
+ * A shader handed out by {@link loader.getShader} is not tracked once handed
509
+ * out, so an effect that outlives a level (a HUD's, a camera's) belongs in a
510
+ * bundle that outlives it too, or it is freed under whatever still uses it.
511
+ * @param {string|Asset} asset - a bundle id, or the descriptor of the asset
512
+ * to free
513
+ * @returns {boolean} with a bundle id, `false` when the bundle was not
514
+ * loaded; with a descriptor, `false` when the asset was not in memory
515
+ * @throws {Error} synchronously, on an unknown bundle id, or a descriptor
516
+ * whose type the loader keeps nothing for (a type registered with
517
+ * {@link loader.setParser}: the game keeps those assets itself)
518
+ * @example
519
+ * // level 1 is behind the player for good: free what only it uses
520
+ * await level.load("level2", { async: true });
521
+ * loader.unload("level1");
522
+ * @example
523
+ * // free one asset, whatever loaded it
524
+ * loader.unload({ name: "avatar", type: "image" });
292
525
  * @category Assets
293
526
  */
294
- export function unload(asset: Asset): boolean;
527
+ export function unload(asset: string | Asset): boolean;
295
528
  /**
296
- * unload all resources to free memory
297
- * @example me.loader.unloadAll();
529
+ * Free every asset the loader holds, whoever holds it: the caches, the audio
530
+ * clips, and what the engine made from them (GPU textures, shader programs,
531
+ * fonts in `document.fonts`).
532
+ *
533
+ * Bundles declared with {@link loader.setBundle} stay declared, all of them
534
+ * back to not loaded, so they can be loaded again by id. Base URLs, options
535
+ * and parsers are kept too. Levels stay registered with the level director:
536
+ * load the bundles (or preload the assets) again before loading one.
537
+ * @example
538
+ * // back to the title screen: drop everything, then load what it needs
539
+ * loader.unloadAll();
540
+ * await loader.load("common");
298
541
  * @category Assets
299
542
  */
300
543
  export function unloadAll(): void;
544
+ /**
545
+ * Declare a bundle: a named list of the asset descriptors you would otherwise
546
+ * pass to {@link loader.preload}, to load and free together — typically the
547
+ * assets of one level, plus a `"common"` bundle for what every level uses.
548
+ * Passing a record of bundles to `preload` (`{ common: [...], level1: [...] }`,
549
+ * as an assets file exports it) declares each of its keys this way.
550
+ *
551
+ * A bundle is a lifetime, not a namespace: its assets keep their own names
552
+ * and live in the same caches as every other asset, so `getImage("tiles")`
553
+ * and `level.load("map1")` read them as before. Bundle ids and asset names
554
+ * are separate, so a level's bundle may share its map's name. Load it with
555
+ * {@link loader.load} (or name it in a {@link loader.preload} list), check it
556
+ * with {@link loader.isLoaded}, and release it with {@link loader.unload}. An
557
+ * asset listed in several bundles is loaded once and freed with the last
558
+ * loaded bundle that lists it, so list a shared asset in every bundle that
559
+ * uses it.
560
+ *
561
+ * Declaring does not load anything, and a bundle can be declared before the
562
+ * parsers of custom types it uses are registered. Redefining an id replaces
563
+ * its list, but only while that bundle is not loaded or loading: unload it
564
+ * first. The list is copied, so changing the array afterwards changes nothing.
565
+ * An asset listed twice is one asset (type and name identify it), and an
566
+ * empty list is allowed: such a bundle loads at once and is always loaded.
567
+ * @param {string} id - the bundle id
568
+ * @param {Asset[]} assets - its asset descriptors (bundle ids cannot be nested)
569
+ * @throws {TypeError} on an empty or non-string id, or a list that is not an
570
+ * array of asset descriptors
571
+ * @throws {Error} when that bundle is loaded or loading
572
+ * @example
573
+ * loader.setBundle("common", [
574
+ * { name: "player", type: "image", src: "img/player.png" },
575
+ * { name: "font", type: "fontface", src: "font/PressStart2P.ttf" },
576
+ * ]);
577
+ * loader.setBundle("level1", [
578
+ * { name: "level1", type: "tmx", src: "map/level1.tmx" },
579
+ * { name: "hills", type: "image", src: "img/hills.png" },
580
+ * ]);
581
+ * loader.setBundle("level2", [
582
+ * { name: "level2", type: "tmx", src: "map/level2.tmx" },
583
+ * { name: "hills", type: "image", src: "img/hills.png" }, // shared
584
+ * ]);
585
+ *
586
+ * // boot: behind the loading screen
587
+ * await loader.preload(["common", "level1"]);
588
+ *
589
+ * // moving on: load the next level, switch, then free the previous one
590
+ * // ("hills" stays in memory: level2 lists it too)
591
+ * await loader.load("level2");
592
+ * await level.load("level2", { async: true });
593
+ * loader.unload("level1");
594
+ * @category Assets
595
+ */
596
+ export function setBundle(id: string, assets: Asset[]): void;
597
+ /**
598
+ * The asset list of a declared bundle, or `undefined` when there is none:
599
+ * the way to test whether an id is declared, since the other bundle calls
600
+ * throw on an unknown one.
601
+ * @param {string} id - the bundle id
602
+ * @returns {Asset[]|undefined} a copy of its asset descriptors, or
603
+ * `undefined` when no bundle is declared under that id
604
+ * @example
605
+ * if (loader.getBundle("level3") === undefined) {
606
+ * loader.setBundle("level3", level3Assets);
607
+ * }
608
+ * @category Assets
609
+ */
610
+ export function getBundle(id: string): Asset[] | undefined;
611
+ /**
612
+ * Whether every asset of a bundle is in memory, however it got there (by
613
+ * this bundle, another one, or the old way) — so a game can skip a loading
614
+ * screen it does not need. `false` again as soon as one of them is unloaded,
615
+ * by a bundle or on its own. An empty bundle is always loaded.
616
+ * @param {string} id - the bundle id
617
+ * @returns {boolean} true if every asset of the bundle is loaded
618
+ * @throws {Error} when no bundle is declared under that id
619
+ * @example
620
+ * if (!loader.isLoaded("level2")) {
621
+ * await loader.preload(["level2"]); // with the loading screen
622
+ * }
623
+ * level.load("level2");
624
+ * @category Assets
625
+ */
626
+ export function isLoaded(id: string): boolean;
301
627
  /**
302
628
  * additional import for TypeScript
303
629
  * @import {CompressedImage} from "./parsers/compressed_textures/compressed_image.js";
304
630
  * @import GLShader from "../video/webgl/glshader.js";
305
631
  * @import ShaderEffect from "../video/effects/shadereffect.js";
632
+ * @import {AssetParser, Bundle, PreloadTally} from "./internal-types.ts";
306
633
  */
307
634
  /**
308
635
  * The parsed glTF/GLB scene descriptors, re-exported from the parser that
@@ -318,118 +645,127 @@ export function unloadAll(): void;
318
645
  * @typedef {import("./parsers/gltf.js").GLTFNode} GLTFNode
319
646
  */
320
647
  /**
321
- * a small class to manage loading of stuff and manage resources
322
- * @namespace loader
648
+ * the cache-busting query string appended to asset URLs, set through
649
+ * {@link setOptions} (`nocache: true`)
650
+ * @ignore
323
651
  */
324
652
  export let nocache: string;
325
653
  /**
654
+ * The base URL of each asset type, as set by {@link setBaseURL}: prepended to
655
+ * the `src` of every asset of that type, unless the `src` is a data URI. A
656
+ * type with no entry here is loaded from its `src` as written.
657
+ * Read it here, change it through `setBaseURL`.
326
658
  * @type {Object.<string, string>}
659
+ * @example
660
+ * loader.setBaseURL("image", "data/img/");
661
+ * loader.baseURL.image; // "data/img/"
327
662
  */
328
663
  export const baseURL: {
329
664
  [x: string]: string;
330
665
  };
331
666
  /**
332
- * crossOrigin attribute to configure the CORS requests for Image and Video data element.
333
- * By default (that is, when the attribute is not specified), CORS is not used at all.
334
- * The "anonymous" keyword means that there will be no exchange of user credentials via cookies,
335
- * client-side SSL certificates or HTTP authentication as described in the Terminology section of the CORS specification.<br>
667
+ * The `crossOrigin` attribute the loader gives the `<video>` and `<script>`
668
+ * elements it creates, and the images of a glTF model: `"anonymous"` sends no
669
+ * user credentials (cookies, client-side TLS certificates or HTTP
670
+ * authentication) to another origin, `"use-credentials"` sends them, as
671
+ * `withCredentials` does.<br>
672
+ * Every other asset (images, JSON, maps, binary files, buffered audio...) is
673
+ * always requested with CORS, whatever this says: an asset on another origin
674
+ * loads when its server allows it (an `Access-Control-Allow-Origin` header),
675
+ * and fails to load, with an error naming the asset, when it does not.
336
676
  * @type {string}
337
677
  * @default undefined
338
678
  * @see {@link setOptions}
339
679
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes}
340
- * @deprecated since 20.4.0, read-only — set it with
341
- * {@link setOptions}. This is a module binding, so assigning to it throws a
342
- * `TypeError`; the example below never worked.
680
+ * @deprecated since 20.4.0 as a setting: it is read-only, set it with
681
+ * {@link setOptions}. It is a module binding, so assigning to it
682
+ * (`loader.crossOrigin = "anonymous"`) throws a `TypeError`, and always did.
343
683
  * @example
344
- * // allow for cross-origin texture loading
345
- * me.loader.setOptions({ crossOrigin: "anonymous" });
346
- *
347
- * // set all resources to be loaded
348
- * me.loader.preload(game.resources, () => this.loaded());
684
+ * // play videos from another origin, without credentials
685
+ * loader.setOptions({ crossOrigin: "anonymous" });
686
+ * await loader.preload(resources);
349
687
  */
350
688
  export let crossOrigin: string;
351
689
  /**
352
- * indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies,
353
- * authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.
354
- * @public
690
+ * Whether requests to another origin carry credentials: cookies,
691
+ * authorization headers or TLS client certificates. It has no effect on
692
+ * requests to the game's own origin, which always carry the browser's
693
+ * credentials, as the page and its scripts do, so a game behind a login or a
694
+ * session cookie loads its own assets without it.
355
695
  * @type {boolean}
356
- * @see {@link setOptions}
357
696
  * @default false
697
+ * @see {@link setOptions}
358
698
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}
359
- * @deprecated since 20.4.0, read-only — set it with
360
- * {@link setOptions}. This is a module binding, so assigning to it throws a
361
- * `TypeError`; the example below never worked.
699
+ * @deprecated since 20.4.0 as a setting: it is read-only, set it with
700
+ * {@link setOptions}. It is a module binding, so assigning to it
701
+ * (`loader.withCredentials = true`) throws a `TypeError`, and always did.
362
702
  * @example
363
- * // enable withCredentials, for assets behind a session cookie or login
364
- * me.loader.setOptions({ withCredentials: true });
365
- *
366
- * // set all resources to be loaded
367
- * me.loader.preload(game.resources, () => this.loaded());
703
+ * // assets on a CDN behind a session cookie or a login
704
+ * loader.setOptions({ withCredentials: true });
705
+ * await loader.preload(resources);
368
706
  */
369
707
  export let withCredentials: boolean;
370
708
  /**
371
- * A registered parser, normalized by {@link loader.setParser}.
709
+ * An asset descriptor: what to load, and the name to keep it under. The same
710
+ * descriptors go in a {@link preload} list, in a bundle ({@link setBundle}),
711
+ * or to {@link load} on their own.
372
712
  *
373
- * Every type gets the same shape whether or not it needs the src hooks, so
374
- * `load()` can treat all of them alike. The alternative — a bare function that
375
- * some types decorate with extra properties — puts the knowledge of which
376
- * types are special back into the caller, which is what moving it out was for.
377
- */
378
- export type AssetParser = {
379
- /**
380
- * - preloads the asset and returns how many
381
- * resources it will load (0 when already cached)
382
- */
383
- parse: Function;
384
- /**
385
- * - turns a type-specific
386
- * descriptor into a bare path, before any base URL is applied. Identity unless
387
- * the type overrides it
388
- */
389
- normalizeSrc: (arg0: string) => string;
390
- /**
391
- * - whether the normalized
392
- * src is relative to this type's base URL. Declares only this type's own
393
- * exceptions, such as a `local()` font naming an installed family — data URIs
394
- * are excluded for every type before this is consulted
395
- */
396
- needsBaseURL: (arg0: string) => boolean;
397
- };
398
- /**
399
- * an asset definition to be used with the loader
713
+ * The type and the name together identify an asset, so two assets of
714
+ * different types may share a name: a texture atlas is usually an `"image"`
715
+ * and a `"json"` both called `"texture"`.
400
716
  */
401
717
  export type Asset = {
402
718
  /**
403
- * - name of the asset
719
+ * - the name the asset is kept and read back under
720
+ * (`loader.getImage(name)`, `new Sprite(x, y, { image: name })`,
721
+ * `level.load(name)`, `audio.play(name)`)
404
722
  */
405
723
  name: string;
406
724
  /**
407
- * - the type of the asset ("audio"|"binary"|"image"|"json"|"js"|"tmx"|"tsx"|"fontface"|"video"|"aseprite"|"shader"|"obj"|"mtl"|"gltf"|"glb"). JSON-serialised Tiled maps and tilesets (`.tmj` / `.tsj`) load under `"tmx"` / `"tsx"` — those are file extensions, not asset types. Any other type is one registered with {@link loader.setParser}.
725
+ * - the type of the asset, which picks its parser:
726
+ * "audio", "binary", "image", "json", "js", "tmx", "tsx", "fontface", "video",
727
+ * "aseprite", "shader", "obj", "mtl", "gltf" or "glb". JSON-serialised Tiled
728
+ * maps and tilesets (`.tmj` / `.tsj`) load under `"tmx"` / `"tsx"`: those are
729
+ * file extensions, not asset types. Any other type is one registered with
730
+ * {@link loader.setParser}.
408
731
  */
409
732
  type: string;
410
733
  /**
411
- * - path and/or file name of the resource (for audio assets only the path is required).
412
- * For image assets, an array of sources can be provided as a fallback chain (e.g. compressed texture formats by priority, with a PNG fallback).
413
- * The loader will try each source in order and use the first one that loads successfully.
734
+ * - the URL of the file, relative to the
735
+ * page or to the type's base URL ({@link setBaseURL}), or a data URI.
736
+ * For `"audio"` it is the **directory** holding the clip: the loader appends
737
+ * the asset name and each extension given to `audio.init()`, and keeps the
738
+ * first that decodes.
739
+ * For `"image"` it may be an array of sources, tried in order until one loads:
740
+ * a fallback chain, such as compressed texture formats by priority with a PNG
741
+ * last.
742
+ * For `"shader"` it may be an object of URLs instead (see the example).
414
743
  */
415
744
  src?: string | string[];
416
745
  /**
417
- * - inline content if not provided through a src url: TMX data for "tmx" assets, GLSL source (the ShaderEffect fragment-body convention) for "shader" assets. A shader may instead carry a `{glsl, wgsl}` pair, so one asset serves both backends; either half may be omitted
746
+ * - inline content
747
+ * in place of a `src`: the parsed Tiled JSON map or tileset (an object) for
748
+ * `"tmx"` / `"tsx"`, the GLSL source of an effect body for `"shader"`, or a
749
+ * `{glsl, wgsl}` pair of them so that one asset serves both backends (either
750
+ * half may be omitted)
418
751
  */
419
752
  data?: string | {
420
753
  glsl?: string;
421
754
  wgsl?: string;
422
755
  };
423
756
  /**
424
- * - Set to true to not to wait for large audio or video file to be downloaded before playing.
757
+ * - audio and video: start playing before
758
+ * the whole file is downloaded, rather than waiting for it
425
759
  */
426
760
  stream?: boolean;
427
761
  /**
428
- * - Set to true to automatically start playing audio or video when loaded or added to a scene (using autoplay might require user iteraction to enable it)
762
+ * - audio and video: start playing once
763
+ * loaded, or once added to a scene (a browser may require a user interaction
764
+ * first)
429
765
  */
430
766
  autoplay?: boolean;
431
767
  /**
432
- * - Set to true to automatically loop the audio or video when playing
768
+ * - audio and video: loop when playing
433
769
  */
434
770
  loop?: boolean;
435
771
  };