melonjs 20.2.0 → 20.3.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 (140) hide show
  1. package/README.md +86 -8
  2. package/build/application/settings.d.ts +3 -2
  3. package/build/application/settings.d.ts.map +1 -1
  4. package/build/audio/audio.d.ts +2 -2
  5. package/build/audio/audio.d.ts.map +1 -1
  6. package/build/audio/backend/buffer.d.ts +26 -0
  7. package/build/audio/backend/buffer.d.ts.map +1 -0
  8. package/build/audio/backend/cache.d.ts +2 -0
  9. package/build/audio/backend/cache.d.ts.map +1 -0
  10. package/build/audio/backend/core.d.ts +24 -0
  11. package/build/audio/backend/core.d.ts.map +1 -0
  12. package/build/audio/backend/engine.d.ts +54 -0
  13. package/build/audio/backend/engine.d.ts.map +1 -0
  14. package/build/audio/backend/sound.d.ts +79 -0
  15. package/build/audio/backend/sound.d.ts.map +1 -0
  16. package/build/audio/backend/spatial.d.ts +191 -0
  17. package/build/audio/backend/spatial.d.ts.map +1 -0
  18. package/build/audio/backend/types.d.ts +97 -0
  19. package/build/audio/backend/types.d.ts.map +1 -0
  20. package/build/audio/backend/voice.d.ts +33 -0
  21. package/build/audio/backend/voice.d.ts.map +1 -0
  22. package/build/audio/playback.d.ts +49 -4
  23. package/build/audio/playback.d.ts.map +1 -1
  24. package/build/audio/{backend.d.ts → state.d.ts} +13 -11
  25. package/build/audio/state.d.ts.map +1 -0
  26. package/build/audio/types.d.ts +93 -1
  27. package/build/audio/types.d.ts.map +1 -1
  28. package/build/camera/camera3d.d.ts +5 -5
  29. package/build/const.d.ts +2 -2
  30. package/build/index.d.ts.map +1 -1
  31. package/build/index.js +8793 -10171
  32. package/build/index.js.map +4 -4
  33. package/build/input/input.d.ts +19 -0
  34. package/build/input/input.d.ts.map +1 -1
  35. package/build/lang/deprecated.d.ts +4 -2
  36. package/build/lang/deprecated.d.ts.map +1 -1
  37. package/build/level/gltf/GLTFScene.d.ts +12 -0
  38. package/build/level/gltf/GLTFScene.d.ts.map +1 -1
  39. package/build/level/tiled/TMXObjectFactory.d.ts.map +1 -1
  40. package/build/loader/loader.d.ts +4 -40
  41. package/build/loader/loader.d.ts.map +1 -1
  42. package/build/loader/parsers/audio.d.ts +31 -0
  43. package/build/loader/parsers/audio.d.ts.map +1 -0
  44. package/build/loader/parsers/shader.d.ts.map +1 -1
  45. package/build/physics/adapter.d.ts +3 -3
  46. package/build/physics/builtin/body.d.ts +23 -24
  47. package/build/physics/builtin/body.d.ts.map +1 -1
  48. package/build/physics/builtin/detector.d.ts +1 -1
  49. package/build/plugin/plugin.d.ts +9 -1
  50. package/build/plugin/plugin.d.ts.map +1 -1
  51. package/build/polyfill/index.d.ts +1 -4
  52. package/build/polyfill/index.d.ts.map +1 -1
  53. package/build/renderable/mesh.d.ts +16 -0
  54. package/build/renderable/mesh.d.ts.map +1 -1
  55. package/build/renderable/renderable.d.ts +16 -10
  56. package/build/renderable/renderable.d.ts.map +1 -1
  57. package/build/renderable/sprite.d.ts +7 -7
  58. package/build/renderable/sprite.d.ts.map +1 -1
  59. package/build/state/stage.d.ts +4 -2
  60. package/build/state/stage.d.ts.map +1 -1
  61. package/build/system/event.d.ts +1 -1
  62. package/build/system/platform.d.ts +21 -1
  63. package/build/system/platform.d.ts.map +1 -1
  64. package/build/utils/fetchdata.d.ts.map +1 -0
  65. package/build/video/blendmodes.d.ts +1 -1
  66. package/build/video/canvas/canvas_renderer.d.ts +5 -2
  67. package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
  68. package/build/video/effects/blur.d.ts +4 -4
  69. package/build/video/effects/blur.d.ts.map +1 -1
  70. package/build/video/effects/chromaticAberration.d.ts +5 -5
  71. package/build/video/effects/chromaticAberration.d.ts.map +1 -1
  72. package/build/video/effects/colorMatrix.d.ts +5 -5
  73. package/build/video/effects/colorMatrix.d.ts.map +1 -1
  74. package/build/video/effects/desaturate.d.ts +5 -5
  75. package/build/video/effects/desaturate.d.ts.map +1 -1
  76. package/build/video/effects/dissolve.d.ts +4 -4
  77. package/build/video/effects/dissolve.d.ts.map +1 -1
  78. package/build/video/effects/dropShadow.d.ts +5 -5
  79. package/build/video/effects/dropShadow.d.ts.map +1 -1
  80. package/build/video/effects/flash.d.ts +4 -4
  81. package/build/video/effects/flash.d.ts.map +1 -1
  82. package/build/video/effects/glow.d.ts +5 -5
  83. package/build/video/effects/glow.d.ts.map +1 -1
  84. package/build/video/effects/hologram.d.ts +4 -4
  85. package/build/video/effects/hologram.d.ts.map +1 -1
  86. package/build/video/effects/invert.d.ts +5 -5
  87. package/build/video/effects/invert.d.ts.map +1 -1
  88. package/build/video/effects/outline.d.ts +6 -6
  89. package/build/video/effects/outline.d.ts.map +1 -1
  90. package/build/video/effects/pixelate.d.ts +4 -4
  91. package/build/video/effects/pixelate.d.ts.map +1 -1
  92. package/build/video/effects/radialGradient.d.ts +2 -2
  93. package/build/video/effects/scanline.d.ts +6 -6
  94. package/build/video/effects/scanline.d.ts.map +1 -1
  95. package/build/video/effects/sepia.d.ts +5 -5
  96. package/build/video/effects/sepia.d.ts.map +1 -1
  97. package/build/video/effects/shadereffect.d.ts +12 -10
  98. package/build/video/effects/shadereffect.d.ts.map +1 -1
  99. package/build/video/effects/shine.d.ts +3 -3
  100. package/build/video/effects/shine.d.ts.map +1 -1
  101. package/build/video/effects/tintPulse.d.ts +4 -4
  102. package/build/video/effects/tintPulse.d.ts.map +1 -1
  103. package/build/video/effects/vignette.d.ts +6 -6
  104. package/build/video/effects/vignette.d.ts.map +1 -1
  105. package/build/video/effects/wave.d.ts +4 -4
  106. package/build/video/effects/wave.d.ts.map +1 -1
  107. package/build/video/texture/atlas.d.ts +1 -1
  108. package/build/video/webgl/glshader.d.ts +2 -2
  109. package/build/video/webgl/webgl_renderer.d.ts +2 -1
  110. package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
  111. package/build/video/webgpu/webgpu_renderer.d.ts +2 -1
  112. package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
  113. package/package.json +5 -9
  114. package/skills/AGENTS.md +67 -0
  115. package/skills/melonjs/SKILL.md +156 -0
  116. package/skills/melonjs-20-migration/SKILL.md +160 -0
  117. package/skills/melonjs-3d/SKILL.md +226 -0
  118. package/skills/melonjs-3d-assets/SKILL.md +239 -0
  119. package/skills/melonjs-audio/SKILL.md +215 -0
  120. package/skills/melonjs-camera-and-drawing/SKILL.md +171 -0
  121. package/skills/melonjs-deployment/SKILL.md +113 -0
  122. package/skills/melonjs-effects-and-shaders/SKILL.md +177 -0
  123. package/skills/melonjs-events/SKILL.md +159 -0
  124. package/skills/melonjs-getting-started/SKILL.md +183 -0
  125. package/skills/melonjs-input/SKILL.md +166 -0
  126. package/skills/melonjs-lighting/SKILL.md +139 -0
  127. package/skills/melonjs-loading-assets/SKILL.md +157 -0
  128. package/skills/melonjs-particles-and-trails/SKILL.md +136 -0
  129. package/skills/melonjs-performance/SKILL.md +178 -0
  130. package/skills/melonjs-physics/SKILL.md +321 -0
  131. package/skills/melonjs-plugins/SKILL.md +191 -0
  132. package/skills/melonjs-renderables/SKILL.md +214 -0
  133. package/skills/melonjs-renderer-backends/SKILL.md +173 -0
  134. package/skills/melonjs-scenes-and-state/SKILL.md +180 -0
  135. package/skills/melonjs-sprites-and-animation/SKILL.md +173 -0
  136. package/skills/melonjs-tilemaps/SKILL.md +193 -0
  137. package/skills/melonjs-ui-and-text/SKILL.md +175 -0
  138. package/build/audio/backend.d.ts.map +0 -1
  139. package/build/loader/parsers/fetchdata.d.ts.map +0 -1
  140. /package/build/{loader/parsers → utils}/fetchdata.d.ts +0 -0
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: melonjs-sprites-and-animation
3
+ description: "Use this skill when creating sprites, playing frame animations, or working with texture atlases in melonJS. Covers Sprite construction from a plain image or an atlas region, addAnimation/setCurrentAnimation, TextureAtlas for TexturePacker/ShoeBox/Aseprite, tint, flip, NineSliceSprite, and the centred anchorPoint that offsets naive positioning. Triggers on: Sprite, new Sprite, addAnimation, setCurrentAnimation, isCurrentAnimation, TextureAtlas, TexturePacker, Aseprite, ShoeBox, atlas, region, framewidth, frameheight, tint, flipX, flipY, NineSliceSprite, animation."
4
+ license: MIT
5
+ ---
6
+
7
+ # Sprites, animation and atlases
8
+
9
+ > Creating sprites from images or atlases, driving frame animation, and the
10
+ > positioning trap that catches almost everyone.
11
+
12
+ ## `pos` is the centre, not the top-left
13
+
14
+ `Renderable.anchorPoint` defaults to **`(0.5, 0.5)`**, so a sprite's `pos` is its
15
+ **centre**. `Container` forces `(0, 0)` instead, which is why containers and
16
+ sprites appear to disagree.
17
+
18
+ ```js
19
+ // a 64×64 sprite at (100, 100) covers 68..132, not 100..164
20
+ const s = new Sprite(100, 100, { image: "hero", framewidth: 64, frameheight: 64 });
21
+
22
+ s.anchorPoint.set(0, 0); // switch to top-left positioning if you prefer
23
+ ```
24
+
25
+ Writing top-left maths against the centred default puts everything half a sprite
26
+ off, with no error. It is the most common source of "close but subtly wrong"
27
+ placement.
28
+
29
+ ## Constructing a sprite
30
+
31
+ From a plain image:
32
+
33
+ ```js
34
+ const hero = new Sprite(x, y, {
35
+ image: "hero", // preloaded asset name
36
+ framewidth: 32,
37
+ frameheight: 32,
38
+ });
39
+ ```
40
+
41
+ From a texture atlas region:
42
+
43
+ ```js
44
+ const atlas = new TextureAtlas(loader.getJSON("sprites"), loader.getImage("sprites"));
45
+ const coin = new Sprite(x, y, { image: atlas, region: "coin_01.png" });
46
+ ```
47
+
48
+ `framewidth` / `frameheight` define the animation grid on a sheet. Omit them and
49
+ the whole image is one frame.
50
+
51
+ ## Animation
52
+
53
+ ```js
54
+ hero.addAnimation("idle", [0, 1, 2, 3], 100); // frames, ms per frame
55
+ hero.addAnimation("walk", [4, 5, 6, 7]);
56
+ hero.addAnimation("die", [8, 9], 150);
57
+
58
+ hero.setCurrentAnimation("walk");
59
+ hero.setCurrentAnimation("die", "idle"); // chain to idle when it ends
60
+ hero.setCurrentAnimation("die", { loop: false }); // play once, hold the last frame
61
+ hero.setCurrentAnimation("die", { loop: false, onComplete: fn }); // …and call fn when it does
62
+
63
+ if (hero.isCurrentAnimation("walk")) { /* … */ }
64
+ ```
65
+
66
+ Frame indices are into the `framewidth`/`frameheight` grid. With an atlas, use
67
+ `atlas.getAnimationSettings([regionNames])` and spread it into the Sprite
68
+ settings, or `atlas.createAnimationFromName([regionNames])`, which returns a
69
+ ready-made Sprite. On a fixed-cell spritesheet only numeric indices are
70
+ accepted — passing region names throws.
71
+
72
+ The second argument to `setCurrentAnimation` is polymorphic. A **string** chains
73
+ to that animation when this one ends. An **options object** takes
74
+ `{ loop, next, speed, onComplete }`, and only an explicit `loop: false` stops the
75
+ looping. A **bare function** is the legacy form: it fires at *every* cycle end,
76
+ and only holds the last frame if it returns `false`. Omit the argument entirely
77
+ and the animation loops forever.
78
+
79
+ Re-selecting the animation that is already current is a no-op, so calling
80
+ `setCurrentAnimation` every frame is safe. An unknown id throws.
81
+
82
+ ## Texture atlases
83
+
84
+ `TextureAtlas` reads several formats:
85
+
86
+ | source | how |
87
+ |---|---|
88
+ | TexturePacker / Free Texture Packer JSON | `new TextureAtlas(loader.getJSON(name), loader.getImage(name))` |
89
+ | Aseprite **JSON export** | same as TexturePacker — the format is detected from `meta.app` |
90
+ | Aseprite **`.aseprite` / `.ase` binary** | loader type `"aseprite"`, which stores the composited image *and* a JSON sidecar under the one asset name |
91
+ | ShoeBox | JSON export using the melonJS exporter settings file; same call as TexturePacker |
92
+ | fixed-cell spritesheet | `new TextureAtlas({ framewidth, frameheight, anchorPoint }, loader.getImage(name))` |
93
+ | multi-page | pass an array of atlas JSON objects as the first argument |
94
+
95
+ Helpers: `createSpriteFromName(name)`, `createAnimationFromName([names])`,
96
+ `getAnimationSettings([names])`.
97
+
98
+ Atlases matter for performance: the GPU batchers bind several textures at once
99
+ (up to `renderer.maxTextures`), so a handful of separate images still batch —
100
+ but once a frame crosses that many distinct textures the batch has to flush.
101
+ Packing into one atlas keeps everything on a single binding.
102
+
103
+ ## Visual properties
104
+
105
+ ```js
106
+ sprite.tint.setColor(255, 128, 0); // multiply tint
107
+ sprite.alpha = 0.5;
108
+ sprite.flipX(true); // mirror horizontally
109
+ sprite.flipY(true);
110
+ sprite.blendMode = "additive"; // see the effects skill for the full list
111
+ sprite.scale(2, 2); // ← multiplicative, see below
112
+ ```
113
+
114
+ **`scale()` is multiplicative, not absolute.** Calling it every frame compounds.
115
+ For absolute scaling reset first:
116
+
117
+ ```js
118
+ sprite.currentTransform.identity();
119
+ sprite.currentTransform.scale(s, s, 1);
120
+ ```
121
+
122
+ This bites hardest with pooled sprites, which arrive carrying their previous
123
+ life's transform.
124
+
125
+ ## `NineSliceSprite`
126
+
127
+ For panels and dialogue boxes that stretch without distorting their corners:
128
+
129
+ ```js
130
+ new NineSliceSprite(x, y, {
131
+ image: "panel", width: 300, height: 120,
132
+ insetx: 12, insety: 12, // lowercase x/y — `insetX` is silently ignored
133
+ });
134
+ ```
135
+
136
+ `width` and `height` are mandatory and the constructor throws without them.
137
+ The insets default to a quarter of the frame.
138
+
139
+ ## Pooling
140
+
141
+ Frequently spawned sprites should be pooled:
142
+
143
+ ```js
144
+ pool.register("bullet", Bullet, true); // true = recyclable
145
+ const b = pool.pull("bullet", x, y); // new Bullet(x, y), or onResetEvent(x, y) on a reused one
146
+ world.removeChild(b); // returns it to the pool automatically
147
+ ```
148
+
149
+ Two consequences:
150
+
151
+ - A recyclable class's `onResetEvent` must reset **everything** its lifetime
152
+ mutates — alpha, tint, scale, animation state. Anything you forget carries
153
+ over to the next use.
154
+ - Pool-recycled objects do **not** fire `onDestroyEvent` on removal. Pair event
155
+ subscriptions with `onActivateEvent` / `onDeactivateEvent` instead.
156
+
157
+ ## Symptom → cause
158
+
159
+ | symptom | cause |
160
+ |---|---|
161
+ | everything offset by half a sprite | top-left maths against the centred `anchorPoint` |
162
+ | sprite grows every frame | `scale()` is multiplicative — reset the transform |
163
+ | a recycled sprite keeps its old look | `onResetEvent` does not restore every mutated property |
164
+ | event handlers leak on pooled objects | bound in the constructor rather than `onActivateEvent` |
165
+ | animation never advances | no `framewidth`/`frameheight`, so the sheet is one frame |
166
+ | animation plays once and stops | `{ loop: false }`, or a callback that returned `false` |
167
+ | sprites do not batch | more distinct textures in one frame than `renderer.maxTextures` |
168
+ | nine-slice corners stretch anyway | `insetX`/`insetY` instead of `insetx`/`insety` |
169
+
170
+ ## Related skills
171
+
172
+ - `melonjs-renderables` — anchors, draw order, custom draw
173
+ - `melonjs-getting-started` — preloading images and atlases
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: melonjs-tilemaps
3
+ description: "Use this skill for Tiled maps in melonJS — loading TMX/TSX levels, spawning entities from Tiled objects, collision shapes authored in Tiled, isometric and hexagonal maps, and image layers. Covers the pool.register name contract, camera bounds, compressed maps needing the inflate plugin, and the level director API. Triggers on: Tiled, TMX, TSX, tilemap, level.load, tileset, ImageLayer, isometric, hexagonal, staggered, pool.register, Collectable, Trigger, object layer, collision layer, parallax."
4
+ license: MIT
5
+ ---
6
+
7
+ # Tiled maps
8
+
9
+ > melonJS's flagship content pipeline. Maps are authored in
10
+ > [Tiled](https://www.mapeditor.org/) and loaded through the `level` director —
11
+ > you rarely touch the `TMX*` classes directly.
12
+
13
+ ## Loading a level
14
+
15
+ Preload the map **and** everything it references — the `.tmx`, any external
16
+ `.tsx` tilesets, and the tileset images:
17
+
18
+ ```js
19
+ await loader.preload([
20
+ { name: "map1", type: "tmx", src: "data/map/map1.tmx" },
21
+ { name: "tileset", type: "tsx", src: "data/map/tileset.tsx" },
22
+ { name: "tiles", type: "image", src: "data/img/tiles.png" },
23
+ ]);
24
+
25
+ level.load("map1"); // inside Stage.onResetEvent
26
+ ```
27
+
28
+ Asset `type` is `"tmx"` for maps and `"tsx"` for external tilesets — those are
29
+ the only two type strings the loader knows. The *file* can be `.tmx` / `.tsx`
30
+ (XML), or `.json` / `.tmj` / `.tsj`; the parser branches on the extension, not
31
+ on the type. `type: "tmj"` throws `unknown or invalid resource type`. You can
32
+ also skip `src` and pass the map inline via `data` (with `format: "json"` or
33
+ `"xml"`).
34
+
35
+ `level.load(levelId, options)` accepts `container` (default `game.world`),
36
+ `onLoaded` (default `game.onLevelLoaded`), `flatten` (default `game.mergeGroup`)
37
+ and `setViewportBounds` (default **`true`**). It throws `level <id> not found`
38
+ for an unknown id.
39
+
40
+ **`level.load` is deferred while the game loop is running.** It calls
41
+ `state.stop()` and finishes the load in a `setTimeout`, so it returns `true`
42
+ before anything is in the world. Do follow-up work from the `onLoaded` callback
43
+ or an `event.LEVEL_LOADED` listener, not on the next line.
44
+
45
+ `level.reload()`, `level.next()`, `level.previous()`, `level.getCurrentLevelId()`
46
+ and `level.levelCount()` round out the namespace. `flatten: false` wraps each
47
+ Tiled object group in its own `Container` named after the group.
48
+
49
+ ## Spawning entities from Tiled objects
50
+
51
+ Objects are matched against a factory registry, in this order: the object's
52
+ Tiled **class**, then its **name**, then the structural fallbacks `"text"`,
53
+ `"tile"` and `"shape"`.
54
+
55
+ ```js
56
+ pool.register("mainPlayer", PlayerEntity); // ← matches Tiled class OR name
57
+ level.load("map1");
58
+ ```
59
+
60
+ `pool.register(className, classObj, recycling)` also registers the class as a
61
+ Tiled object factory (and again under an `me.`-prefixed alias), unless you set
62
+ `pool.autoRegisterTiled = false`. The dedicated entry points are:
63
+
64
+ ```js
65
+ import { registerTiledObjectClass, registerTiledObjectFactory } from "melonjs";
66
+
67
+ registerTiledObjectClass("Enemy", Enemy); // new Enemy(x, y, settings)
68
+ registerTiledObjectFactory("Spine", (settings, map) => { /* → Renderable */ });
69
+ ```
70
+
71
+ Register **before** loading. With no match the object falls through to the
72
+ structural factory and becomes a plain `Renderable` with a static body — it does
73
+ not error, it just has none of your behaviour.
74
+
75
+ `registerTiledObjectClass` **throws** if you register a *different* constructor
76
+ under a name already taken (re-registering the same one is a no-op).
77
+ `registerTiledObjectFactory` overwrites and only `console.warn`s, so it is the
78
+ one to use for overriding a built-in such as `"shape"`.
79
+
80
+ melonJS pre-registers `Renderable`, `Sprite`, `NineSliceSprite`, `Text`,
81
+ `BitmapText`, `ImageLayer`, `ColorLayer`, `Light2d`, `Collectable` and `Trigger`
82
+ as Tiled classes, so `Collectable` and `Trigger` work out of the box.
83
+
84
+ ## Camera bounds
85
+
86
+ `level.load` sets the viewport bounds to the map size for you —
87
+ `setViewportBounds` defaults to `true`, and the handler is re-run on every
88
+ viewport resize, centring the map when it is smaller than the screen. You only
89
+ need to do it by hand when you opted out:
90
+
91
+ ```js
92
+ level.load("map1", { setViewportBounds: false });
93
+ app.viewport.setBounds(0, 0, mapWidth, mapHeight); // now it's on you
94
+ ```
95
+
96
+ The same is true if you drive `TMXTileMap.addTo(container, flatten, setViewportBounds)`
97
+ directly — note that method's `setViewportBounds` defaults to **`false`**, the
98
+ opposite of `level.load`'s.
99
+
100
+ ## Collision shapes
101
+
102
+ Draw collision geometry in Tiled on an object layer and melonJS turns it into
103
+ world shapes automatically — rectangles, polygons, polylines, ellipses and
104
+ points all work.
105
+
106
+ The contract is the **layer name**: melonJS lowercases it and checks whether it
107
+ *contains* `"collision"` (so `collision`, `Collision`, `world collision` all
108
+ match). Inside such a layer, objects **with no name** get
109
+ `collisionType = collision.types.WORLD_SHAPE` and `type = "static"`. A *named*
110
+ object in a collision layer keeps whatever its factory gave it — that is how you
111
+ mix triggers into the collision layer.
112
+
113
+ An object that matches no factory and carries no text or tile data falls to the
114
+ `"shape"` factory: a plain `Renderable` with a static `bodyDef` built from its
115
+ geometry, which the world auto-registers with the active adapter on `addChild`.
116
+
117
+ For per-object physics, set the object's custom properties in Tiled; they arrive
118
+ on the settings object passed to your entity's constructor.
119
+
120
+ ## Map orientations
121
+
122
+ Orthogonal, **isometric**, hexagonal, staggered and oblique are all supported;
123
+ anything else throws `<orientation> type TMX Tile Map not supported!` at load.
124
+ Isometric maps need y-sorting so objects overlap correctly:
125
+
126
+ ```js
127
+ app.world.sortOn = "y"; // after level.load
128
+ ```
129
+
130
+ `sortOn` only accepts `"x"`, `"y"`, `"z"` (the default) or `"depth"` and throws
131
+ on anything else. `Vector2d`, `Vector3d`, their observable variants and `Polygon`
132
+ all carry `.toIso()` / `.to2d()` for converting between screen and map space.
133
+
134
+ ## Image layers
135
+
136
+ `ImageLayer` gives parallax backgrounds with a ratio per axis, set in Tiled or in
137
+ code. Repeat behaviour matches Tiled's.
138
+
139
+ ## Compressed maps need a plugin
140
+
141
+ A map saved with **gzip, zlib or zstd** compressed layer data throws
142
+ `No inflate function set — GZIP/ZLIB decompression not supported!` at parse time
143
+ without:
144
+
145
+ ```js
146
+ import { plugin } from "melonjs";
147
+ import { TiledInflatePlugin } from "@melonjs/tiled-inflate-plugin";
148
+
149
+ plugin.register(TiledInflatePlugin); // before preloading any compressed map
150
+ ```
151
+
152
+ Uncompressed base64 and CSV layer data need no plugin. If a map loads in Tiled
153
+ but not in melonJS, check the layer compression setting first.
154
+
155
+ ## Rendering
156
+
157
+ Each tile layer resolves to one of three `renderMode`s — `"shader"`,
158
+ `"prerender"` or `"perTile"` — auto-selected in that order of preference, or
159
+ forced per layer. The `"shader"` path is a single quad per tileset with a
160
+ per-pixel GID lookup in the fragment shader. It requires **all** of:
161
+
162
+ - a renderer that reports GPU tile-layer support (WebGL 2 / WebGPU — not Canvas),
163
+ - `world.gpuTilemap !== false` (the `gpuTilemap` application setting, default `true`),
164
+ - an **orthogonal** layer — isometric, hexagonal, staggered and oblique always
165
+ fall back,
166
+ - no collection-of-image tileset, no non-zero `tileoffset`, and tile overflow
167
+ within the shader's 4-cell limit.
168
+
169
+ When a layer falls back, melonJS `console.warn`s once with the reason. Practical
170
+ consequences: fewer tilesets means fewer batches (one packed tileset beats
171
+ several small ones), and on the Canvas fallback large maps get noticeably
172
+ slower. `world.preRender` (or a `preRender` layer property in Tiled) opts an
173
+ unanimated layer into the offscreen-bake path instead.
174
+
175
+ ## Symptom → cause
176
+
177
+ | symptom | cause |
178
+ |---|---|
179
+ | a Tiled object becomes a plain shape with no behaviour | its class/name does not match any registered factory, or it was registered after `level.load` |
180
+ | the world is still empty right after `level.load` | the load is deferred via `setTimeout` while the loop runs — use `onLoaded` / `LEVEL_LOADED` |
181
+ | `level <id> not found` | the map was never preloaded, or the asset `name` differs from the id passed to `load` |
182
+ | `unknown or invalid resource type` | asset `type` set to `"tmj"` / `"tsj"` — use `"tmx"` / `"tsx"` with the `.tmj` / `.tsj` file |
183
+ | camera will not scroll | `setViewportBounds: false`, or the map was added with `addTo()` (which defaults to `false`) |
184
+ | `No inflate function set` at parse time | compressed layers without the tiled-inflate plugin |
185
+ | collision shapes are not solid | the object layer's name does not contain `"collision"`, or the objects are named |
186
+ | isometric objects overlap wrongly | `world.sortOn` not set to `"y"` |
187
+ | missing tiles or a blank map | the `.tsx` or tileset image was not preloaded |
188
+ | tilemap slow on some machines | layer fell back off the shader path — check the console warning for the reason |
189
+
190
+ ## Related skills
191
+
192
+ - `melonjs-physics` — what the collision shapes become once loaded
193
+ - `melonjs-getting-started` — preloading and the asset type list
@@ -0,0 +1,175 @@
1
+ ---
2
+ name: melonjs-ui-and-text
3
+ description: "Use this skill for HUDs, buttons, menus, dialogue panels and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, Draggable and DropTarget, the floating screen-space container pattern, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, UIBaseElement, UISpriteElement, UITextButton, Draggable, DropTarget, menu, dialogue, Text, BitmapText, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating."
4
+ license: MIT
5
+ ---
6
+
7
+ # UI, HUD and text
8
+
9
+ ## The HUD pattern
10
+
11
+ A HUD is a `floating` container at a high z, built once and re-added:
12
+
13
+ ```js
14
+ class HUD extends Container {
15
+ constructor(app) {
16
+ super(0, 0, app.viewport.width, app.viewport.height);
17
+ this.floating = true; // screen space, not world space
18
+ this.isPersistent = true; // survives a world reset
19
+ }
20
+ }
21
+
22
+ app.world.addChild(new HUD(app), 100); // explicit z — not `.z = Infinity`
23
+ ```
24
+
25
+ There is no `UIContainer` class. Use `Container`, or `UIBaseElement` when the
26
+ panel itself must react to the pointer — it is a `Container` that already sets
27
+ `floating = true` and `isKinematic = false`.
28
+
29
+ Three things matter here:
30
+
31
+ - **`floating = true`** opts the container out of camera transforms, so it stays
32
+ put while the world scrolls. Without it the HUD scrolls away — a silent
33
+ failure.
34
+ - **Only the parent container needs `floating`.** `addChild` forces
35
+ `child.floating = false` under a floating parent, and the container applies one
36
+ projection swap for the whole subtree.
37
+ - **Pass an explicit z.** `this.z = Number.POSITIVE_INFINITY` appears in several
38
+ shipped examples and does nothing — `renderable.z` is not a real property. The
39
+ real accessor is `depth` (an alias for `pos.z`); `addChild(child, z)` sets it
40
+ for you.
41
+
42
+ Relayout on resize by listening for `event.CANVAS_ONRESIZE`.
43
+
44
+ ## Buttons and interactive elements
45
+
46
+ Use the built-ins rather than hand-rolling — they set `isKinematic = false` for
47
+ you, which is the trap that stops hand-rolled buttons receiving clicks at all.
48
+
49
+ ```js
50
+ class PlayButton extends UISpriteElement {
51
+ constructor(x, y) {
52
+ super(x, y, { image: atlas, region: "play.png" });
53
+ }
54
+ onClick() { state.change(state.PLAY); return false; }
55
+ onOver() { this.setOpacity(1.0); }
56
+ onOut() { this.setOpacity(0.8); }
57
+ onRelease() { return false; }
58
+ }
59
+ ```
60
+
61
+ | class | for |
62
+ |---|---|
63
+ | `UIBaseElement` | a `Container` base — clickable, optionally draggable and holdable |
64
+ | `UISpriteElement` | a `Sprite`-backed button with hover/press callbacks |
65
+ | `UITextButton` | a `BitmapText` label on a `RoundRect` background — it needs a **bitmap** font, not a `fontface` |
66
+ | `Draggable` / `DropTarget` | drag-and-drop; `dropTarget.setCheckMethod(dropTarget.CHECKMETHOD_CONTAINS)` to require containment instead of overlap |
67
+
68
+ The callbacks to override are `onClick`, `onOver`, `onOut`, `onRelease` and
69
+ `onHold`; `UIBaseElement` adds `onMove` while dragging. Returning `false` from
70
+ `onClick` / `onRelease` stops the event propagating further.
71
+
72
+ ## Text
73
+
74
+ ```js
75
+ new Text(x, y, {
76
+ font: "Arial",
77
+ size: 32,
78
+ fillStyle: "#FFFFFF",
79
+ textAlign: "center",
80
+ textBaseline: "middle",
81
+ text: "Score: 0",
82
+ wordWrapWidth: 400, // enables wrapping
83
+ });
84
+ ```
85
+
86
+ `text` accepts a string or an array of lines. Update with `setText()`.
87
+
88
+ **Custom web fonts must be preloaded** with the `"fontface"` asset type:
89
+
90
+ ```js
91
+ { name: "PressStart2P", type: "fontface", src: "data/font/PressStart2P.ttf" }
92
+ ```
93
+
94
+ Drawing before the font has loaded silently renders in a fallback font — the
95
+ layout looks subtly wrong rather than failing.
96
+
97
+ ## `BitmapText`
98
+
99
+ For pixel-perfect text that scales without antialiasing, and for text drawn in
100
+ volume: every `BitmapText` sharing a font draws glyph quads from that one page
101
+ image, so they batch together. Each `Text` instead owns a private canvas
102
+ texture (re-rasterised whenever it changes), so a screenful of them is a
103
+ screenful of distinct textures.
104
+
105
+ ```js
106
+ await loader.preload([
107
+ { name: "PressStart2P", type: "image", src: "data/font/font.png" },
108
+ { name: "PressStart2P", type: "binary", src: "data/font/font.fnt" },
109
+ ]);
110
+
111
+ new BitmapText(x, y, {
112
+ font: "PressStart2P",
113
+ size: 2, // a scale ratio, not a pixel size
114
+ text: "GAME OVER",
115
+ });
116
+ ```
117
+
118
+ It needs **both** assets, and by default they must share the **same asset
119
+ name** — `settings.font` resolves the image *and*, unless you pass
120
+ `settings.fontData`, the descriptor. Registering the descriptor under a
121
+ different name (`"…-fnt"`) is the usual mistake; either use one name for both,
122
+ or pass `fontData: "PressStart2P-fnt"` explicitly.
123
+
124
+ The descriptor is AngelCode BMFont in either flavour — the text `.fnt` form or
125
+ the XML form — auto-detected, so an `.xml` export loads as-is.
126
+
127
+ ## Never draw text through the raw context
128
+
129
+ ```js
130
+ // ✗ works on Canvas only — getContext() returns the GL/GPU context on the
131
+ // GPU backends, and neither has fillText
132
+ app.renderer.getContext().fillText("hi", 10, 10);
133
+
134
+ // ✓
135
+ world.addChild(new Text(10, 10, { text: "hi", /* … */ }));
136
+ ```
137
+
138
+ `getContext()` hands back the *backend's* context — a
139
+ `CanvasRenderingContext2D` only under the Canvas renderer. On WebGL or WebGPU
140
+ the call throws `TypeError: … .fillText is not a function`, so this fails loudly
141
+ — but only on the machines that picked a GPU backend, which under `video.AUTO`
142
+ is most of them and probably not yours.
143
+
144
+ ## Panels
145
+
146
+ `NineSliceSprite` stretches a panel without distorting its corners — the right
147
+ tool for dialogue boxes and windows:
148
+
149
+ ```js
150
+ new NineSliceSprite(x, y, {
151
+ image: "panel", width: 300, height: 120, insetx: 12, insety: 12,
152
+ });
153
+ ```
154
+
155
+ The inset keys are lowercase `insetx` / `insety`; `insetX` is silently ignored
156
+ and the corners fall back to a quarter of the frame. `width` and `height` are
157
+ mandatory — the constructor throws without them.
158
+
159
+ ## Symptom → cause
160
+
161
+ | symptom | cause |
162
+ |---|---|
163
+ | HUD scrolls away with the camera | missing `floating = true` on the container |
164
+ | HUD drawn under the game | `this.z = …` instead of `addChild(hud, z)` |
165
+ | hand-rolled button never responds | `isKinematic` left `true` — use `UISpriteElement` |
166
+ | text renders in the wrong font | web font not preloaded as `"fontface"` |
167
+ | `BitmapText` renders nothing | the `.fnt` / image pair was loaded under two different asset names |
168
+ | `TypeError: … .fillText is not a function` | drawn via `getContext()` under a GPU backend |
169
+ | `UIContainer is not defined` | no such class — use `Container` or `UIBaseElement` |
170
+ | UI misplaced after a window resize | no `CANVAS_ONRESIZE` relayout |
171
+
172
+ ## Related skills
173
+
174
+ - `melonjs-input` — the `isKinematic` requirement in full
175
+ - `melonjs-renderables` — `floating`, draw order, containers
@@ -1 +0,0 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/audio/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAU,MAAM,QAAQ,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,eAAO,IAAI,gBAAgB,EAAE,OAAc,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK;YACH,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC;oBACtB,MAAM,GAAG,IAAI;mBAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;eAC1B,MAAM,EAAE;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,YAAY,MAAM,EAClB,aAAa,MAAM,IAAI,EACvB,cAAa,OAAc,KACzB,IAqBF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAmBrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,QAAQ,GAAG,IAAI,CAS/C;AAUD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEnD;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetchdata.d.ts","sourceRoot":"","sources":["../../../src/loader/parsers/fetchdata.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,oCALW,MAAM,aACN,MAAM,GACJ,OAAO,CAKnB;AA2DD;;;;;;;;;;;;;;;GAeG;AACH,+BAdW,MAAM,gBACN,MAAM,aACN,MAAM,gBAkDhB"}
File without changes